diff --git a/.docker/Dockerfile-try-runtime b/.docker/Dockerfile-try-runtime index a483bd8839..2e2370d505 100644 --- a/.docker/Dockerfile-try-runtime +++ b/.docker/Dockerfile-try-runtime @@ -46,4 +46,4 @@ RUN echo "Requested features: ${NETWORK}-runtime\n" && \ echo "Fork from: $REPLICA_FROM\n" && \ cargo build --features=try-runtime,${NETWORK}-runtime --release -CMD cargo run --features=try-runtime,${NETWORK}-runtime --release -- try-runtime -ltry-runtime::cli=debug --no-spec-check-panic on-runtime-upgrade live --uri $REPLICA_FROM +CMD cargo run --release --features ${NETWORK}-runtime,try-runtime -- try-runtime --runtime target/release/wbuild/${NETWORK}-runtime/${NETWORK}_runtime.compact.compressed.wasm -lruntime=debug -ltry-runtime::cli=debug on-runtime-upgrade --checks live --uri $REPLICA_FROM diff --git a/.docker/additional/xcm-rococo/.env b/.docker/additional/xcm-rococo/.env index 2458f34215..7f34e92563 100644 --- a/.docker/additional/xcm-rococo/.env +++ b/.docker/additional/xcm-rococo/.env @@ -1,16 +1,16 @@ -RUST_TOOLCHAIN=nightly-2022-07-24 +RUST_TOOLCHAIN=nightly-2022-10-09 UNIQUE_BRANCH="develop" -POLKADOT_BUILD_BRANCH=release-v0.9.30 +POLKADOT_BUILD_BRANCH=release-v0.9.34 -KARURA_BUILD_BRANCH=2.9.1 -ACALA_BUILD_BRANCH=2.9.2 +KARURA_BUILD_BRANCH=release-karura-2.9.5 +ACALA_BUILD_BRANCH=2.9.6 -MOONRIVER_BUILD_BRANCH=runtime-1701 -MOONBEAM_BUILD_BRANCH=runtime-1701 +MOONRIVER_BUILD_BRANCH=v0.26.1 +MOONBEAM_BUILD_BRANCH=v0.26.1 -STATEMINE_BUILD_BRANCH=parachains-v9270 -STATEMINT_BUILD_BRANCH=release-parachains-v9230 -WESTMINT_BUILD_BRANCH=parachains-v9270 +STATEMINE_BUILD_BRANCH=parachains-v9271 +STATEMINT_BUILD_BRANCH=parachains-v9271 +WESTMINT_BUILD_BRANCH=parachains-v9290 POLKADOT_LAUNCH_BRANCH="unique-network" diff --git a/.docker/patch/disable-ic.patch b/.docker/patch/disable-ic.patch deleted file mode 100644 index 7b3cea5585..0000000000 --- a/.docker/patch/disable-ic.patch +++ /dev/null @@ -1,1972 +0,0 @@ -diff --git a/Cargo.lock b/Cargo.lock -index 62c2493f..9236a3f3 100644 ---- a/Cargo.lock -+++ b/Cargo.lock -@@ -420,7 +420,7 @@ dependencies = [ - [[package]] - name = "beefy-gadget" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "beefy-primitives", - "fnv", -@@ -454,7 +454,7 @@ dependencies = [ - [[package]] - name = "beefy-gadget-rpc" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "beefy-gadget", - "beefy-primitives", -@@ -474,12 +474,12 @@ dependencies = [ - [[package]] - name = "beefy-merkle-tree" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - - [[package]] - name = "beefy-primitives" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - "scale-info", -@@ -2682,7 +2682,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] - name = "fork-tree" - version = "3.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - ] -@@ -2776,7 +2776,7 @@ dependencies = [ - [[package]] - name = "frame-benchmarking" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "frame-system", -@@ -2798,7 +2798,7 @@ dependencies = [ - [[package]] - name = "frame-benchmarking-cli" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "Inflector", - "chrono", -@@ -2848,7 +2848,7 @@ dependencies = [ - [[package]] - name = "frame-election-provider-solution-type" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "proc-macro-crate", - "proc-macro2", -@@ -2859,7 +2859,7 @@ dependencies = [ - [[package]] - name = "frame-election-provider-support" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-election-provider-solution-type", - "frame-support", -@@ -2875,7 +2875,7 @@ dependencies = [ - [[package]] - name = "frame-executive" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "frame-system", -@@ -2903,7 +2903,7 @@ dependencies = [ - [[package]] - name = "frame-support" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "bitflags", - "frame-metadata", -@@ -2933,7 +2933,7 @@ dependencies = [ - [[package]] - name = "frame-support-procedural" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "Inflector", - "frame-support-procedural-tools", -@@ -2945,7 +2945,7 @@ dependencies = [ - [[package]] - name = "frame-support-procedural-tools" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support-procedural-tools-derive", - "proc-macro-crate", -@@ -2957,7 +2957,7 @@ dependencies = [ - [[package]] - name = "frame-support-procedural-tools-derive" - version = "3.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "proc-macro2", - "quote", -@@ -2967,7 +2967,7 @@ dependencies = [ - [[package]] - name = "frame-system" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "log", -@@ -2984,7 +2984,7 @@ dependencies = [ - [[package]] - name = "frame-system-benchmarking" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -2999,7 +2999,7 @@ dependencies = [ - [[package]] - name = "frame-system-rpc-runtime-api" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - "sp-api", -@@ -3008,7 +3008,7 @@ dependencies = [ - [[package]] - name = "frame-try-runtime" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "sp-api", -@@ -5449,7 +5449,7 @@ dependencies = [ - [[package]] - name = "pallet-aura" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "frame-system", -@@ -5465,7 +5465,7 @@ dependencies = [ - [[package]] - name = "pallet-authority-discovery" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "frame-system", -@@ -5481,7 +5481,7 @@ dependencies = [ - [[package]] - name = "pallet-authorship" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "frame-system", -@@ -5496,7 +5496,7 @@ dependencies = [ - [[package]] - name = "pallet-babe" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -5520,7 +5520,7 @@ dependencies = [ - [[package]] - name = "pallet-bags-list" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", -@@ -5540,7 +5540,7 @@ dependencies = [ - [[package]] - name = "pallet-balances" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -5570,7 +5570,7 @@ dependencies = [ - [[package]] - name = "pallet-beefy" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "beefy-primitives", - "frame-support", -@@ -5586,7 +5586,7 @@ dependencies = [ - [[package]] - name = "pallet-beefy-mmr" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "beefy-merkle-tree", - "beefy-primitives", -@@ -5609,7 +5609,7 @@ dependencies = [ - [[package]] - name = "pallet-bounties" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -5687,7 +5687,7 @@ dependencies = [ - [[package]] - name = "pallet-child-bounties" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -5706,7 +5706,7 @@ dependencies = [ - [[package]] - name = "pallet-collective" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -5744,7 +5744,7 @@ dependencies = [ - [[package]] - name = "pallet-democracy" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -5760,7 +5760,7 @@ dependencies = [ - [[package]] - name = "pallet-election-provider-multi-phase" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", -@@ -5783,7 +5783,7 @@ dependencies = [ - [[package]] - name = "pallet-election-provider-support-benchmarking" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", -@@ -5796,7 +5796,7 @@ dependencies = [ - [[package]] - name = "pallet-elections-phragmen" - version = "5.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -5966,7 +5966,7 @@ dependencies = [ - [[package]] - name = "pallet-gilt" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -5981,7 +5981,7 @@ dependencies = [ - [[package]] - name = "pallet-grandpa" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6004,7 +6004,7 @@ dependencies = [ - [[package]] - name = "pallet-identity" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "enumflags2", - "frame-benchmarking", -@@ -6020,7 +6020,7 @@ dependencies = [ - [[package]] - name = "pallet-im-online" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6040,7 +6040,7 @@ dependencies = [ - [[package]] - name = "pallet-indices" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6076,7 +6076,7 @@ dependencies = [ - [[package]] - name = "pallet-membership" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6093,7 +6093,7 @@ dependencies = [ - [[package]] - name = "pallet-mmr" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "ckb-merkle-mountain-range", - "frame-benchmarking", -@@ -6111,7 +6111,7 @@ dependencies = [ - [[package]] - name = "pallet-mmr-rpc" - version = "3.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "jsonrpsee", - "parity-scale-codec 3.1.5", -@@ -6126,7 +6126,7 @@ dependencies = [ - [[package]] - name = "pallet-multisig" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6141,7 +6141,7 @@ dependencies = [ - [[package]] - name = "pallet-nicks" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "frame-system", -@@ -6155,7 +6155,7 @@ dependencies = [ - [[package]] - name = "pallet-nomination-pools" - version = "1.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "frame-system", -@@ -6171,7 +6171,7 @@ dependencies = [ - [[package]] - name = "pallet-nomination-pools-benchmarking" - version = "1.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", -@@ -6212,7 +6212,7 @@ dependencies = [ - [[package]] - name = "pallet-offences" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "frame-system", -@@ -6229,7 +6229,7 @@ dependencies = [ - [[package]] - name = "pallet-offences-benchmarking" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", -@@ -6252,7 +6252,7 @@ dependencies = [ - [[package]] - name = "pallet-preimage" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6268,7 +6268,7 @@ dependencies = [ - [[package]] - name = "pallet-proxy" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6283,7 +6283,7 @@ dependencies = [ - [[package]] - name = "pallet-randomness-collective-flip" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "frame-system", -@@ -6297,7 +6297,7 @@ dependencies = [ - [[package]] - name = "pallet-recovery" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6372,7 +6372,7 @@ dependencies = [ - [[package]] - name = "pallet-scheduler" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6388,7 +6388,7 @@ dependencies = [ - [[package]] - name = "pallet-session" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "frame-system", -@@ -6409,7 +6409,7 @@ dependencies = [ - [[package]] - name = "pallet-session-benchmarking" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6425,7 +6425,7 @@ dependencies = [ - [[package]] - name = "pallet-society" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "frame-system", -@@ -6439,7 +6439,7 @@ dependencies = [ - [[package]] - name = "pallet-staking" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", -@@ -6462,7 +6462,7 @@ dependencies = [ - [[package]] - name = "pallet-staking-reward-curve" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "proc-macro-crate", - "proc-macro2", -@@ -6473,7 +6473,7 @@ dependencies = [ - [[package]] - name = "pallet-staking-reward-fn" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "log", - "sp-arithmetic", -@@ -6497,7 +6497,7 @@ dependencies = [ - [[package]] - name = "pallet-sudo" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "frame-system", -@@ -6531,7 +6531,7 @@ dependencies = [ - [[package]] - name = "pallet-timestamp" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6549,7 +6549,7 @@ dependencies = [ - [[package]] - name = "pallet-tips" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6568,7 +6568,7 @@ dependencies = [ - [[package]] - name = "pallet-transaction-payment" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-support", - "frame-system", -@@ -6584,7 +6584,7 @@ dependencies = [ - [[package]] - name = "pallet-transaction-payment-rpc" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "jsonrpsee", - "pallet-transaction-payment-rpc-runtime-api", -@@ -6599,7 +6599,7 @@ dependencies = [ - [[package]] - name = "pallet-transaction-payment-rpc-runtime-api" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "pallet-transaction-payment", - "parity-scale-codec 3.1.5", -@@ -6610,7 +6610,7 @@ dependencies = [ - [[package]] - name = "pallet-treasury" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6669,7 +6669,7 @@ dependencies = [ - [[package]] - name = "pallet-utility" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -6685,7 +6685,7 @@ dependencies = [ - [[package]] - name = "pallet-vesting" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-benchmarking", - "frame-support", -@@ -8942,7 +8942,7 @@ dependencies = [ - [[package]] - name = "remote-externalities" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "env_logger", - "jsonrpsee", -@@ -9321,7 +9321,7 @@ dependencies = [ - [[package]] - name = "sc-allocator" - version = "4.1.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "log", - "sp-core", -@@ -9332,7 +9332,7 @@ dependencies = [ - [[package]] - name = "sc-authority-discovery" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "futures 0.3.21", -@@ -9359,7 +9359,7 @@ dependencies = [ - [[package]] - name = "sc-basic-authorship" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "futures-timer", -@@ -9382,7 +9382,7 @@ dependencies = [ - [[package]] - name = "sc-block-builder" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - "sc-client-api", -@@ -9398,7 +9398,7 @@ dependencies = [ - [[package]] - name = "sc-chain-spec" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "impl-trait-for-tuples", - "memmap2 0.5.5", -@@ -9415,7 +9415,7 @@ dependencies = [ - [[package]] - name = "sc-chain-spec-derive" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "proc-macro-crate", - "proc-macro2", -@@ -9426,7 +9426,7 @@ dependencies = [ - [[package]] - name = "sc-cli" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "chrono", - "clap", -@@ -9465,7 +9465,7 @@ dependencies = [ - [[package]] - name = "sc-client-api" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "fnv", - "futures 0.3.21", -@@ -9493,7 +9493,7 @@ dependencies = [ - [[package]] - name = "sc-client-db" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "hash-db", - "kvdb", -@@ -9518,7 +9518,7 @@ dependencies = [ - [[package]] - name = "sc-consensus" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "futures 0.3.21", -@@ -9542,7 +9542,7 @@ dependencies = [ - [[package]] - name = "sc-consensus-aura" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "futures 0.3.21", -@@ -9571,7 +9571,7 @@ dependencies = [ - [[package]] - name = "sc-consensus-babe" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "fork-tree", -@@ -9614,7 +9614,7 @@ dependencies = [ - [[package]] - name = "sc-consensus-babe-rpc" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "jsonrpsee", -@@ -9636,7 +9636,7 @@ dependencies = [ - [[package]] - name = "sc-consensus-epochs" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "fork-tree", - "parity-scale-codec 3.1.5", -@@ -9649,7 +9649,7 @@ dependencies = [ - [[package]] - name = "sc-consensus-manual-seal" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "assert_matches", - "async-trait", -@@ -9683,7 +9683,7 @@ dependencies = [ - [[package]] - name = "sc-consensus-slots" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "futures 0.3.21", -@@ -9708,7 +9708,7 @@ dependencies = [ - [[package]] - name = "sc-consensus-uncles" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "sc-client-api", - "sp-authorship", -@@ -9719,7 +9719,7 @@ dependencies = [ - [[package]] - name = "sc-executor" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "lazy_static", - "lru 0.7.8", -@@ -9746,7 +9746,7 @@ dependencies = [ - [[package]] - name = "sc-executor-common" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "environmental", - "parity-scale-codec 3.1.5", -@@ -9763,7 +9763,7 @@ dependencies = [ - [[package]] - name = "sc-executor-wasmi" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "log", - "parity-scale-codec 3.1.5", -@@ -9778,7 +9778,7 @@ dependencies = [ - [[package]] - name = "sc-executor-wasmtime" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "cfg-if 1.0.0", - "libc", -@@ -9796,7 +9796,7 @@ dependencies = [ - [[package]] - name = "sc-finality-grandpa" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "ahash", - "async-trait", -@@ -9836,7 +9836,7 @@ dependencies = [ - [[package]] - name = "sc-finality-grandpa-rpc" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "finality-grandpa", - "futures 0.3.21", -@@ -9857,7 +9857,7 @@ dependencies = [ - [[package]] - name = "sc-informant" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "ansi_term", - "futures 0.3.21", -@@ -9874,7 +9874,7 @@ dependencies = [ - [[package]] - name = "sc-keystore" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "hex", -@@ -9889,7 +9889,7 @@ dependencies = [ - [[package]] - name = "sc-network" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "asynchronous-codec", -@@ -9941,7 +9941,7 @@ dependencies = [ - [[package]] - name = "sc-network-common" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "libp2p", -@@ -9954,7 +9954,7 @@ dependencies = [ - [[package]] - name = "sc-network-gossip" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "ahash", - "futures 0.3.21", -@@ -9971,7 +9971,7 @@ dependencies = [ - [[package]] - name = "sc-network-light" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "libp2p", -@@ -9991,7 +9991,7 @@ dependencies = [ - [[package]] - name = "sc-network-sync" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "bitflags", - "either", -@@ -10020,7 +10020,7 @@ dependencies = [ - [[package]] - name = "sc-offchain" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "bytes 1.2.0", - "fnv", -@@ -10048,7 +10048,7 @@ dependencies = [ - [[package]] - name = "sc-peerset" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "libp2p", -@@ -10061,7 +10061,7 @@ dependencies = [ - [[package]] - name = "sc-proposer-metrics" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "log", - "substrate-prometheus-endpoint", -@@ -10070,7 +10070,7 @@ dependencies = [ - [[package]] - name = "sc-rpc" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "hash-db", -@@ -10100,7 +10100,7 @@ dependencies = [ - [[package]] - name = "sc-rpc-api" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "jsonrpsee", -@@ -10123,7 +10123,7 @@ dependencies = [ - [[package]] - name = "sc-rpc-server" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "jsonrpsee", -@@ -10136,7 +10136,7 @@ dependencies = [ - [[package]] - name = "sc-service" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "directories", -@@ -10201,7 +10201,7 @@ dependencies = [ - [[package]] - name = "sc-state-db" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "log", - "parity-scale-codec 3.1.5", -@@ -10215,7 +10215,7 @@ dependencies = [ - [[package]] - name = "sc-sync-state-rpc" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "jsonrpsee", - "parity-scale-codec 3.1.5", -@@ -10234,7 +10234,7 @@ dependencies = [ - [[package]] - name = "sc-sysinfo" - version = "6.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "libc", -@@ -10253,7 +10253,7 @@ dependencies = [ - [[package]] - name = "sc-telemetry" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "chrono", - "futures 0.3.21", -@@ -10271,7 +10271,7 @@ dependencies = [ - [[package]] - name = "sc-tracing" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "ansi_term", - "atty", -@@ -10302,7 +10302,7 @@ dependencies = [ - [[package]] - name = "sc-tracing-proc-macro" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "proc-macro-crate", - "proc-macro2", -@@ -10313,7 +10313,7 @@ dependencies = [ - [[package]] - name = "sc-transaction-pool" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "futures-timer", -@@ -10340,7 +10340,7 @@ dependencies = [ - [[package]] - name = "sc-transaction-pool-api" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "log", -@@ -10353,7 +10353,7 @@ dependencies = [ - [[package]] - name = "sc-utils" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "futures-timer", -@@ -10795,7 +10795,7 @@ dependencies = [ - [[package]] - name = "sp-api" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "hash-db", - "log", -@@ -10812,7 +10812,7 @@ dependencies = [ - [[package]] - name = "sp-api-proc-macro" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "blake2", - "proc-macro-crate", -@@ -10824,7 +10824,7 @@ dependencies = [ - [[package]] - name = "sp-application-crypto" - version = "6.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - "scale-info", -@@ -10837,7 +10837,7 @@ dependencies = [ - [[package]] - name = "sp-arithmetic" - version = "5.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "integer-sqrt", - "num-traits", -@@ -10852,7 +10852,7 @@ dependencies = [ - [[package]] - name = "sp-authority-discovery" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - "scale-info", -@@ -10865,7 +10865,7 @@ dependencies = [ - [[package]] - name = "sp-authorship" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "parity-scale-codec 3.1.5", -@@ -10877,7 +10877,7 @@ dependencies = [ - [[package]] - name = "sp-block-builder" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - "sp-api", -@@ -10889,7 +10889,7 @@ dependencies = [ - [[package]] - name = "sp-blockchain" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "log", -@@ -10907,7 +10907,7 @@ dependencies = [ - [[package]] - name = "sp-consensus" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "futures 0.3.21", -@@ -10926,7 +10926,7 @@ dependencies = [ - [[package]] - name = "sp-consensus-aura" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "parity-scale-codec 3.1.5", -@@ -10944,7 +10944,7 @@ dependencies = [ - [[package]] - name = "sp-consensus-babe" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "merlin", -@@ -10967,7 +10967,7 @@ dependencies = [ - [[package]] - name = "sp-consensus-slots" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - "scale-info", -@@ -10981,7 +10981,7 @@ dependencies = [ - [[package]] - name = "sp-consensus-vrf" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - "scale-info", -@@ -10994,7 +10994,7 @@ dependencies = [ - [[package]] - name = "sp-core" - version = "6.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "base58", - "bitflags", -@@ -11040,7 +11040,7 @@ dependencies = [ - [[package]] - name = "sp-core-hashing" - version = "4.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "blake2", - "byteorder", -@@ -11054,7 +11054,7 @@ dependencies = [ - [[package]] - name = "sp-core-hashing-proc-macro" - version = "5.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "proc-macro2", - "quote", -@@ -11065,7 +11065,7 @@ dependencies = [ - [[package]] - name = "sp-database" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "kvdb", - "parking_lot 0.12.1", -@@ -11074,7 +11074,7 @@ dependencies = [ - [[package]] - name = "sp-debug-derive" - version = "4.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "proc-macro2", - "quote", -@@ -11084,7 +11084,7 @@ dependencies = [ - [[package]] - name = "sp-externalities" - version = "0.12.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "environmental", - "parity-scale-codec 3.1.5", -@@ -11095,7 +11095,7 @@ dependencies = [ - [[package]] - name = "sp-finality-grandpa" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "finality-grandpa", - "log", -@@ -11113,7 +11113,7 @@ dependencies = [ - [[package]] - name = "sp-inherents" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "impl-trait-for-tuples", -@@ -11127,7 +11127,7 @@ dependencies = [ - [[package]] - name = "sp-io" - version = "6.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "hash-db", -@@ -11152,7 +11152,7 @@ dependencies = [ - [[package]] - name = "sp-keyring" - version = "6.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "lazy_static", - "sp-core", -@@ -11163,7 +11163,7 @@ dependencies = [ - [[package]] - name = "sp-keystore" - version = "0.12.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "futures 0.3.21", -@@ -11180,7 +11180,7 @@ dependencies = [ - [[package]] - name = "sp-maybe-compressed-blob" - version = "4.1.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "thiserror", - "zstd", -@@ -11189,7 +11189,7 @@ dependencies = [ - [[package]] - name = "sp-mmr-primitives" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "log", - "parity-scale-codec 3.1.5", -@@ -11204,7 +11204,7 @@ dependencies = [ - [[package]] - name = "sp-npos-elections" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - "scale-info", -@@ -11218,7 +11218,7 @@ dependencies = [ - [[package]] - name = "sp-offchain" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "sp-api", - "sp-core", -@@ -11228,7 +11228,7 @@ dependencies = [ - [[package]] - name = "sp-panic-handler" - version = "4.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "backtrace", - "lazy_static", -@@ -11238,7 +11238,7 @@ dependencies = [ - [[package]] - name = "sp-rpc" - version = "6.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "rustc-hash", - "serde", -@@ -11248,7 +11248,7 @@ dependencies = [ - [[package]] - name = "sp-runtime" - version = "6.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "either", - "hash256-std-hasher", -@@ -11270,7 +11270,7 @@ dependencies = [ - [[package]] - name = "sp-runtime-interface" - version = "6.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "impl-trait-for-tuples", - "parity-scale-codec 3.1.5", -@@ -11287,7 +11287,7 @@ dependencies = [ - [[package]] - name = "sp-runtime-interface-proc-macro" - version = "5.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "Inflector", - "proc-macro-crate", -@@ -11299,7 +11299,7 @@ dependencies = [ - [[package]] - name = "sp-sandbox" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "log", - "parity-scale-codec 3.1.5", -@@ -11313,7 +11313,7 @@ dependencies = [ - [[package]] - name = "sp-serializer" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "serde", - "serde_json", -@@ -11322,7 +11322,7 @@ dependencies = [ - [[package]] - name = "sp-session" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - "scale-info", -@@ -11336,7 +11336,7 @@ dependencies = [ - [[package]] - name = "sp-staking" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - "scale-info", -@@ -11347,7 +11347,7 @@ dependencies = [ - [[package]] - name = "sp-state-machine" - version = "0.12.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "hash-db", - "log", -@@ -11369,12 +11369,12 @@ dependencies = [ - [[package]] - name = "sp-std" - version = "4.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - - [[package]] - name = "sp-storage" - version = "6.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "impl-serde", - "parity-scale-codec 3.1.5", -@@ -11387,7 +11387,7 @@ dependencies = [ - [[package]] - name = "sp-tasks" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "log", - "sp-core", -@@ -11400,7 +11400,7 @@ dependencies = [ - [[package]] - name = "sp-timestamp" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "futures-timer", -@@ -11416,7 +11416,7 @@ dependencies = [ - [[package]] - name = "sp-tracing" - version = "5.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - "sp-std", -@@ -11428,7 +11428,7 @@ dependencies = [ - [[package]] - name = "sp-transaction-pool" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "sp-api", - "sp-runtime", -@@ -11437,7 +11437,7 @@ dependencies = [ - [[package]] - name = "sp-transaction-storage-proof" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "log", -@@ -11453,7 +11453,7 @@ dependencies = [ - [[package]] - name = "sp-trie" - version = "6.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "hash-db", - "memory-db", -@@ -11469,7 +11469,7 @@ dependencies = [ - [[package]] - name = "sp-version" - version = "5.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "impl-serde", - "parity-scale-codec 3.1.5", -@@ -11486,7 +11486,7 @@ dependencies = [ - [[package]] - name = "sp-version-proc-macro" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "parity-scale-codec 3.1.5", - "proc-macro2", -@@ -11497,7 +11497,7 @@ dependencies = [ - [[package]] - name = "sp-wasm-interface" - version = "6.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "impl-trait-for-tuples", - "log", -@@ -11652,7 +11652,7 @@ dependencies = [ - [[package]] - name = "substrate-build-script-utils" - version = "3.0.0" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "platforms", - ] -@@ -11660,7 +11660,7 @@ dependencies = [ - [[package]] - name = "substrate-frame-rpc-system" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "frame-system-rpc-runtime-api", - "futures 0.3.21", -@@ -11681,7 +11681,7 @@ dependencies = [ - [[package]] - name = "substrate-prometheus-endpoint" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures-util", - "hyper", -@@ -11694,7 +11694,7 @@ dependencies = [ - [[package]] - name = "substrate-state-trie-migration-rpc" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "jsonrpsee", - "log", -@@ -11715,7 +11715,7 @@ dependencies = [ - [[package]] - name = "substrate-test-client" - version = "2.0.1" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "async-trait", - "futures 0.3.21", -@@ -11741,7 +11741,7 @@ dependencies = [ - [[package]] - name = "substrate-test-utils" - version = "4.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "futures 0.3.21", - "substrate-test-utils-derive", -@@ -11751,7 +11751,7 @@ dependencies = [ - [[package]] - name = "substrate-test-utils-derive" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "proc-macro-crate", - "proc-macro2", -@@ -11762,7 +11762,7 @@ dependencies = [ - [[package]] - name = "substrate-wasm-builder" - version = "5.0.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "ansi_term", - "build-helper", -@@ -12197,10 +12197,8 @@ version = "0.1.3" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" - dependencies = [ -- "ahash", - "lazy_static", - "log", -- "lru 0.7.8", - "tracing-core", - ] - -@@ -12321,7 +12319,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" - [[package]] - name = "try-runtime-cli" - version = "0.10.0-dev" --source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute#1fa76b0665d32b1e28c36da67e54da1816db3fa2" -+source = "git+https://github.com/uniquenetwork/substrate?branch=polkadot-v0.9.24-hack-substitute-disable-ic#6365b31efb056108a3ed28751d33332751220b39" - dependencies = [ - "clap", - "jsonrpsee", -diff --git a/Cargo.toml b/Cargo.toml -index 6a520f4b..f4619ddb 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -21,176 +21,176 @@ jsonrpsee-types = {git = "https://github.com/uniquenetwork/jsonrpsee", branch = - jsonrpsee-core = {git = "https://github.com/uniquenetwork/jsonrpsee", branch = "unique-v0.13.1-fix-unknown-fields"} - - [patch."https://github.com/paritytech/substrate"] --beefy-gadget = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --beefy-gadget-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --beefy-merkle-tree = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --beefy-primitives = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --fork-tree = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --frame-benchmarking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --frame-benchmarking-cli = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --frame-election-provider-solution-type = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --frame-election-provider-support = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --frame-executive = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --frame-support = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --frame-support-procedural = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --frame-support-procedural-tools = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --frame-support-procedural-tools-derive = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --frame-system = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --frame-system-benchmarking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --frame-system-rpc-runtime-api = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --frame-try-runtime = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-aura = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-authority-discovery = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-authorship = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-babe = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-bags-list = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-balances = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-beefy = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-beefy-mmr = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-bounties = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-child-bounties = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-collective = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-democracy = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-election-provider-multi-phase = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-election-provider-support-benchmarking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-elections-phragmen = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-gilt = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-grandpa = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-identity = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-im-online = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-indices = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-membership = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-mmr = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-mmr-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-multisig = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-nicks = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-nomination-pools = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-nomination-pools-benchmarking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-offences = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-offences-benchmarking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-preimage = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-proxy = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-randomness-collective-flip = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-recovery = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-scheduler = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-session = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-session-benchmarking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-society = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-staking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-staking-reward-curve = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-staking-reward-fn = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-sudo = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-timestamp = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-tips = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-transaction-payment = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-transaction-payment-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-transaction-payment-rpc-runtime-api = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-treasury = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-utility = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --pallet-vesting = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --remote-externalities = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-allocator = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-authority-discovery = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-basic-authorship = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-block-builder = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-chain-spec = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-chain-spec-derive = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-cli = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-client-api = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-client-db = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-consensus = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-consensus-aura = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-consensus-babe = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-consensus-babe-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-consensus-epochs = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-consensus-manual-seal = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-consensus-slots = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-consensus-uncles = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-executor = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-executor-common = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-executor-wasmi = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-executor-wasmtime = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-finality-grandpa = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-finality-grandpa-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-informant = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-keystore = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-network = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-network-common = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-network-gossip = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-network-light = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-network-sync = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-offchain = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-peerset = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-proposer-metrics = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-rpc-api = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-rpc-server = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-service = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-state-db = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-sync-state-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-sysinfo = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-telemetry = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-tracing = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-tracing-proc-macro = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-transaction-pool = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-transaction-pool-api = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sc-utils = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-api = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-api-proc-macro = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-application-crypto = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-arithmetic = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-authority-discovery = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-authorship = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-block-builder = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-blockchain = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-consensus = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-consensus-aura = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-consensus-babe = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-consensus-slots = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-consensus-vrf = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-core = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-core-hashing = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-core-hashing-proc-macro = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-database = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-debug-derive = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-externalities = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-finality-grandpa = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-inherents = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-io = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-keyring = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-keystore = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-maybe-compressed-blob = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-mmr-primitives = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-npos-elections = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-offchain = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-panic-handler = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-runtime = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-runtime-interface = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-runtime-interface-proc-macro = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-sandbox = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-serializer = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-session = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-staking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-state-machine = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-std = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-storage = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-tasks = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-timestamp = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-tracing = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-transaction-pool = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-transaction-storage-proof = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-trie = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-version = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-version-proc-macro = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --sp-wasm-interface = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --substrate-build-script-utils = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --substrate-frame-rpc-system = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --substrate-prometheus-endpoint = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --substrate-state-trie-migration-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --substrate-test-client = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --substrate-test-utils = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --substrate-test-utils-derive = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --substrate-wasm-builder = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} --try-runtime-cli = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute"} -+beefy-gadget = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+beefy-gadget-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+beefy-merkle-tree = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+beefy-primitives = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+fork-tree = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+frame-benchmarking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+frame-benchmarking-cli = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+frame-election-provider-solution-type = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+frame-election-provider-support = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+frame-executive = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+frame-support = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+frame-support-procedural = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+frame-support-procedural-tools = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+frame-support-procedural-tools-derive = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+frame-system = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+frame-system-benchmarking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+frame-system-rpc-runtime-api = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+frame-try-runtime = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-aura = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-authority-discovery = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-authorship = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-babe = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-bags-list = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-balances = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-beefy = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-beefy-mmr = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-bounties = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-child-bounties = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-collective = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-democracy = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-election-provider-multi-phase = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-election-provider-support-benchmarking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-elections-phragmen = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-gilt = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-grandpa = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-identity = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-im-online = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-indices = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-membership = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-mmr = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-mmr-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-multisig = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-nicks = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-nomination-pools = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-nomination-pools-benchmarking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-offences = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-offences-benchmarking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-preimage = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-proxy = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-randomness-collective-flip = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-recovery = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-scheduler = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-session = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-session-benchmarking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-society = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-staking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-staking-reward-curve = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-staking-reward-fn = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-sudo = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-timestamp = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-tips = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-transaction-payment = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-transaction-payment-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-transaction-payment-rpc-runtime-api = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-treasury = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-utility = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+pallet-vesting = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+remote-externalities = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-allocator = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-authority-discovery = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-basic-authorship = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-block-builder = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-chain-spec = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-chain-spec-derive = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-cli = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-client-api = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-client-db = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-consensus = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-consensus-aura = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-consensus-babe = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-consensus-babe-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-consensus-epochs = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-consensus-manual-seal = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-consensus-slots = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-consensus-uncles = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-executor = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-executor-common = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-executor-wasmi = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-executor-wasmtime = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-finality-grandpa = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-finality-grandpa-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-informant = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-keystore = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-network = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-network-common = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-network-gossip = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-network-light = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-network-sync = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-offchain = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-peerset = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-proposer-metrics = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-rpc-api = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-rpc-server = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-service = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-state-db = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-sync-state-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-sysinfo = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-telemetry = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-tracing = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-tracing-proc-macro = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-transaction-pool = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-transaction-pool-api = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sc-utils = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-api = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-api-proc-macro = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-application-crypto = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-arithmetic = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-authority-discovery = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-authorship = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-block-builder = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-blockchain = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-consensus = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-consensus-aura = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-consensus-babe = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-consensus-slots = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-consensus-vrf = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-core = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-core-hashing = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-core-hashing-proc-macro = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-database = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-debug-derive = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-externalities = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-finality-grandpa = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-inherents = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-io = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-keyring = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-keystore = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-maybe-compressed-blob = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-mmr-primitives = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-npos-elections = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-offchain = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-panic-handler = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-runtime = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-runtime-interface = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-runtime-interface-proc-macro = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-sandbox = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-serializer = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-session = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-staking = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-state-machine = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-std = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-storage = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-tasks = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-timestamp = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-tracing = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-transaction-pool = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-transaction-storage-proof = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-trie = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-version = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-version-proc-macro = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+sp-wasm-interface = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+substrate-build-script-utils = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+substrate-frame-rpc-system = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+substrate-prometheus-endpoint = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+substrate-state-trie-migration-rpc = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+substrate-test-client = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+substrate-test-utils = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+substrate-test-utils-derive = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+substrate-wasm-builder = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} -+try-runtime-cli = {git = "https://github.com/uniquenetwork/substrate", branch = "polkadot-v0.9.24-hack-substitute-disable-ic"} - -diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml -index 5ce0c106..8572c20b 100644 ---- a/node/cli/Cargo.toml -+++ b/node/cli/Cargo.toml -@@ -328,4 +328,8 @@ runtime-benchmarks = [ - 'opal-runtime/runtime-benchmarks', - 'polkadot-service/runtime-benchmarks', - ] --try-runtime = [] -+try-runtime = [ -+ 'unique-runtime?/try-runtime', -+ 'quartz-runtime?/try-runtime', -+ 'opal-runtime/try-runtime', -+] -diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml -index 29924138..5e117c53 100644 ---- a/runtime/common/Cargo.toml -+++ b/runtime/common/Cargo.toml -@@ -32,6 +32,7 @@ runtime-benchmarks = [ - 'frame-support/runtime-benchmarks', - 'frame-system/runtime-benchmarks', - ] -+try-runtime = [] - - [dependencies.sp-core] - default-features = false -diff --git a/runtime/opal/Cargo.toml b/runtime/opal/Cargo.toml -index 678dfc3d..d2f9a24e 100644 ---- a/runtime/opal/Cargo.toml -+++ b/runtime/opal/Cargo.toml -@@ -46,6 +46,7 @@ try-runtime = [ - 'frame-try-runtime', - 'frame-executive/try-runtime', - 'frame-system/try-runtime', -+ 'unique-runtime-common/try-runtime', - ] - std = [ - 'codec/std', -diff --git a/runtime/quartz/Cargo.toml b/runtime/quartz/Cargo.toml -index 4c9425a5..885a22d2 100644 ---- a/runtime/quartz/Cargo.toml -+++ b/runtime/quartz/Cargo.toml -@@ -46,6 +46,7 @@ try-runtime = [ - 'frame-try-runtime', - 'frame-executive/try-runtime', - 'frame-system/try-runtime', -+ 'unique-runtime-common/try-runtime', - ] - std = [ - 'codec/std', -diff --git a/runtime/unique/Cargo.toml b/runtime/unique/Cargo.toml -index 631a1a12..ae00be67 100644 ---- a/runtime/unique/Cargo.toml -+++ b/runtime/unique/Cargo.toml -@@ -47,6 +47,7 @@ try-runtime = [ - 'frame-try-runtime', - 'frame-executive/try-runtime', - 'frame-system/try-runtime', -+ 'unique-runtime-common/try-runtime', - ] - std = [ - 'codec/std', diff --git a/.docker/xcm-config/launch-config-xcm-quartz-rococo.json b/.docker/xcm-config/launch-config-xcm-quartz-rococo.json index 52c55770fd..7cd818a7c5 100644 --- a/.docker/xcm-config/launch-config-xcm-quartz-rococo.json +++ b/.docker/xcm-config/launch-config-xcm-quartz-rococo.json @@ -101,6 +101,11 @@ "id": "2000", "chain": "karura-dev", "balance": "1000000000000000000000", + "chainInitializer": [ + "chainql", + "-e", + "(import '${spec}') {id+: '-local'}" + ], "nodes": [ { "wsPort": 9946, diff --git a/.docker/xcm-config/launch-config-xcm-quartz.json b/.docker/xcm-config/launch-config-xcm-quartz.json index 17a3f7bacf..03f619c992 100644 --- a/.docker/xcm-config/launch-config-xcm-quartz.json +++ b/.docker/xcm-config/launch-config-xcm-quartz.json @@ -103,10 +103,10 @@ "chain": "karura-dev", "balance": "1000000000000000000000", "chainInitializer": [ - "chainql", - "-e", - "(import '${spec}') {id+: '-local'}" - ], + "chainql", + "-e", + "(import '${spec}') {id+: '-local'}" + ], "nodes": [ { "wsPort": 9946, diff --git a/.env b/.env index f4b2e521ca..d5c08dafb8 100644 --- a/.env +++ b/.env @@ -1,23 +1,23 @@ -RUST_TOOLCHAIN=nightly-2022-07-24 -POLKADOT_BUILD_BRANCH=release-v0.9.30 +RUST_TOOLCHAIN=nightly-2022-10-09 +POLKADOT_BUILD_BRANCH=release-v0.9.34 POLKADOT_MAINNET_BRANCH=release-v0.9.30 STATEMINT_BUILD_BRANCH=release-parachains-v9320 -ACALA_BUILD_BRANCH=2.10.1 +ACALA_BUILD_BRANCH=2.11.0 MOONBEAM_BUILD_BRANCH=runtime-1901 -UNIQUE_MAINNET_BRANCH=v930033-node-only-fix +UNIQUE_MAINNET_BRANCH=release-v930033-fix-gas-price UNIQUE_REPLICA_FROM=wss://eu-ws.unique.network:443 -KUSAMA_MAINNET_BRANCH=release-v0.9.34 -STATEMINE_BUILD_BRANCH=release-parachains-v9320 -KARURA_BUILD_BRANCH=release-karura-2.10.0 -MOONRIVER_BUILD_BRANCH=runtime-1901 -QUARTZ_MAINNET_BRANCH=v930033-node-only-fix +KUSAMA_MAINNET_BRANCH=release-v0.9.35 +STATEMINE_BUILD_BRANCH=release-parachains-v9330 +KARURA_BUILD_BRANCH=release-karura-2.11.0 +MOONRIVER_BUILD_BRANCH=runtime-2000 +QUARTZ_MAINNET_BRANCH=release-v930034-fix-gas-price QUARTZ_REPLICA_FROM=wss://eu-ws-quartz.unique.network:443 UNQWND_MAINNET_BRANCH=release-v0.9.30 WESTMINT_BUILD_BRANCH=parachains-v9330 -OPAL_MAINNET_BRANCH=v930032-node-only-fix +OPAL_MAINNET_BRANCH=release-v930034-fix-gas-price OPAL_REPLICA_FROM=wss://eu-ws-opal.unique.network:443 POLKADOT_LAUNCH_BRANCH=unique-network diff --git a/.github/workflows/ci-master.yml b/.github/workflows/ci-master.yml index 48e4f0e966..77d486abcd 100644 --- a/.github/workflows/ci-master.yml +++ b/.github/workflows/ci-master.yml @@ -42,3 +42,6 @@ jobs: codestyle: uses: ./.github/workflows/codestyle.yml + + polkadot-types: + uses: ./.github/workflows/polkadot-types.yml \ No newline at end of file diff --git a/.github/workflows/polkadot-types.yml b/.github/workflows/polkadot-types.yml new file mode 100644 index 0000000000..f0027b4e6e --- /dev/null +++ b/.github/workflows/polkadot-types.yml @@ -0,0 +1,96 @@ +# Integration test in --dev mode +# https://cryptousetech.atlassian.net/wiki/spaces/CI/pages/2586411104/Integration+tests +name: Polkadot types + +# Triger: only call from main workflow(re-usable workflows) +on: + workflow_call: + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# on: +# pull_request: +# branches: [ 'develop' ] +# types: [ opened, reopened, synchronize, ready_for_review, converted_to_draft ] + + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + + polkadot_generate_types: + # The type of runner that the job will run on + runs-on: [self-hosted-ci,medium] + timeout-minutes: 1380 + + name: ${{ matrix.network }} + + continue-on-error: true #Do not stop testing of matrix runs failed. As it decided during PR review - it required 50/50& Let's check it with false. + + strategy: + matrix: + include: + - network: "sapphire" + usage: "" + - network: "opal" + usage: "" + - network: "quartz" + usage: "" + - network: "unique" + usage: "" + + steps: + + - name: Clean Workspace + uses: AutoModality/action-clean@v1.1.0 + + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v3 + with: + ref: ${{ github.head_ref }} #Checking out head commit + + - name: Read .env file + uses: xom9ikk/dotenv@v2 + + - name: Generate ENV related extend file for docker-compose + uses: cuchi/jinja2-action@v1.2.0 + with: + template: .docker/docker-compose.tmp-dev.j2 + output_file: .docker/docker-compose.${{ matrix.network }}.yml + variables: | + RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }} + NETWORK=${{ matrix.network }} + + - name: Show build configuration + run: cat .docker/docker-compose.${{ matrix.network }}.yml + + - name: Build the stack + run: docker-compose -f ".docker/docker-compose.${{ matrix.network }}.yml" up -d --build --remove-orphans + + - uses: actions/setup-node@v3 + with: + node-version: 16 + + # - name: Install jq + # run: sudo apt install jq -y + + - name: Run generate_types_package script + working-directory: tests + run: | + yarn install + /bin/bash ./scripts/wait_for_first_block.sh + git config --global user.name "Unique" + git config --global user.email github-actions@usetech.com + /bin/bash ./scripts/generate_types_package.sh --release ${{ matrix.usage }} --push + env: + RPC_URL: http://127.0.0.1:9933/ + + - name: Stop running containers + if: always() # run this step always + run: docker-compose -f ".docker/docker-compose.${{ matrix.network }}.yml" down + + - name: Remove builder cache + if: always() # run this step always + run: | + docker builder prune -f -a + docker system prune -f + docker image prune -f -a diff --git a/.github/workflows/schedule-trigger-for-develop-build.yml b/.github/workflows/schedule-trigger-for-develop-build.yml index 04a846a4dd..ae1c35a8be 100644 --- a/.github/workflows/schedule-trigger-for-develop-build.yml +++ b/.github/workflows/schedule-trigger-for-develop-build.yml @@ -1,8 +1,8 @@ name: schedule-trigger-for-develop-build on: # update the branch ci/develop-scheduler every night - schedule: - - cron: '0 1 * * *' + # schedule: + # - cron: '0 1 * * *' # or update the branch manually workflow_dispatch: # pull_request: diff --git a/.maintain/scripts/compile_stub.sh b/.maintain/scripts/compile_stub.sh index e96c6e8ff9..66a71caf3e 100755 --- a/.maintain/scripts/compile_stub.sh +++ b/.maintain/scripts/compile_stub.sh @@ -6,6 +6,7 @@ dir=$PWD tmp=$(mktemp -d) cd $tmp cp $dir/$INPUT input.sol +echo "Tmp file: $tmp/input.sol" solcjs --optimize --bin input.sol -o $PWD mv input_sol_$(basename $OUTPUT .raw).bin out.bin diff --git a/.maintain/scripts/generate_abi.sh b/.maintain/scripts/generate_abi.sh index 3925d89102..e0d487fb05 100755 --- a/.maintain/scripts/generate_abi.sh +++ b/.maintain/scripts/generate_abi.sh @@ -4,6 +4,7 @@ set -eu dir=$PWD tmp=$(mktemp -d) +echo "Tmp file: $tmp/input.sol" cd $tmp cp $dir/$INPUT input.sol solcjs --abi -p input.sol diff --git a/.maintain/scripts/generate_sol.sh b/.maintain/scripts/generate_sol.sh index e9bb7b5675..c4922f5e47 100755 --- a/.maintain/scripts/generate_sol.sh +++ b/.maintain/scripts/generate_sol.sh @@ -4,7 +4,7 @@ set -eu PRETTIER_CONFIG="$(pwd)""/.prettierrc" tmp=$(mktemp) -cargo test --package $PACKAGE -- $NAME --exact --nocapture --ignored | tee $tmp +cargo test --package=$PACKAGE --features=stubgen -- $NAME --exact --nocapture --ignored | tee $tmp raw=$(mktemp --suffix .sol) sed -n '/=== SNIP START ===/, /=== SNIP END ===/{ /=== SNIP START ===/! { /=== SNIP END ===/! p } }' $tmp > $raw diff --git a/Cargo.lock b/Cargo.lock index 66e53a0df4..94819eb2ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,7 +18,16 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" dependencies = [ - "gimli", + "gimli 0.26.2", +] + +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli 0.27.0", ] [[package]] @@ -42,8 +51,8 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ - "cfg-if 1.0.0", - "cipher 0.3.0", + "cfg-if", + "cipher", "cpufeatures", "opaque-debug 0.3.0", ] @@ -56,7 +65,7 @@ checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" dependencies = [ "aead", "aes", - "cipher 0.3.0", + "cipher", "ctr", "ghash", "subtle", @@ -75,9 +84,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.19" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -108,9 +117,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" [[package]] name = "app-promotion-rpc" @@ -137,24 +146,21 @@ dependencies = [ [[package]] name = "array-bytes" -version = "4.1.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a913633b0c922e6b745072795f50d90ebea78ba31a57e2ac8c2fc7b50950949" +checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" [[package]] -name = "arrayref" -version = "0.3.6" +name = "array-bytes" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "22f72e9d6fac4bc80778ea470b20197b88d28c292bb7d60c3fb099280003cd19" [[package]] -name = "arrayvec" -version = "0.4.12" +name = "arrayref" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -dependencies = [ - "nodrop", -] +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" @@ -192,9 +198,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28" +checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" dependencies = [ "concurrent-queue", "event-listener", @@ -203,23 +209,23 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b" dependencies = [ + "async-lock", "async-task", "concurrent-queue", "fastrand", "futures-lite", - "once_cell", "slab", ] [[package]] name = "async-global-executor" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da5b41ee986eed3f524c380e6d64965aea573882a8907682ad100f7859305ca" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" dependencies = [ "async-channel", "async-executor", @@ -232,49 +238,50 @@ dependencies = [ [[package]] name = "async-io" -version = "1.9.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7" +checksum = "8c374dda1ed3e7d8f0d9ba58715f924862c63eae6849c92d3a18e7fbde9e2794" dependencies = [ + "async-lock", "autocfg", "concurrent-queue", "futures-lite", "libc", "log", - "once_cell", "parking", "polling", "slab", "socket2", "waker-fn", - "winapi", + "windows-sys 0.42.0", ] [[package]] name = "async-lock" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" +checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" dependencies = [ "event-listener", + "futures-lite", ] [[package]] name = "async-process" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02111fd8655a613c25069ea89fc8d9bb89331fa77486eb3bc059ee757cfa481c" +checksum = "6381ead98388605d0d9ff86371043b5aa922a3905824244de40dc263a14fcba4" dependencies = [ "async-io", + "async-lock", "autocfg", "blocking", - "cfg-if 1.0.0", + "cfg-if", "event-listener", "futures-lite", "libc", - "once_cell", "signal-hook", - "winapi", + "windows-sys 0.42.0", ] [[package]] @@ -288,7 +295,6 @@ dependencies = [ "async-global-executor", "async-io", "async-lock", - "async-process", "crossbeam-utils", "futures-channel", "futures-core", @@ -305,21 +311,6 @@ dependencies = [ "wasm-bindgen-futures", ] -[[package]] -name = "async-std-resolver" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2f8a4a203be3325981310ab243a28e6e4ea55b6519bffce05d41ab60e09ad8" -dependencies = [ - "async-std", - "async-trait", - "futures-io", - "futures-util", - "pin-utils", - "socket2", - "trust-dns-resolver", -] - [[package]] name = "async-task" version = "4.3.0" @@ -328,9 +319,9 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" [[package]] name = "async-trait" -version = "0.1.58" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" +checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" dependencies = [ "proc-macro2", "quote", @@ -339,9 +330,9 @@ dependencies = [ [[package]] name = "asynchronous-codec" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0de5164e5edbf51c45fb8c2d9664ae1c095cce1b265ecf7569093c0d66ef690" +checksum = "06a0daa378f5fd10634e44b0a29b2a87b890657658e072a30d6f26e57ddee182" dependencies = [ "bytes", "futures-sink", @@ -362,7 +353,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -385,32 +376,18 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "backoff" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" -dependencies = [ - "futures-core", - "getrandom 0.2.8", - "instant", - "pin-project-lite 0.2.9", - "rand 0.8.5", - "tokio", -] - [[package]] name = "backtrace" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" dependencies = [ - "addr2line", + "addr2line 0.19.0", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", - "object", + "object 0.30.0", "rustc-demangle", ] @@ -456,11 +433,10 @@ dependencies = [ [[package]] name = "beefy-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "async-trait", - "beefy-primitives", "fnv", "futures 0.3.25", "futures-timer", @@ -479,6 +455,7 @@ dependencies = [ "sp-api", "sp-application-crypto", "sp-arithmetic", + "sp-beefy", "sp-blockchain", "sp-consensus", "sp-core", @@ -493,10 +470,9 @@ dependencies = [ [[package]] name = "beefy-gadget-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "beefy-gadget", - "beefy-primitives", "futures 0.3.25", "jsonrpsee", "log", @@ -505,6 +481,7 @@ dependencies = [ "sc-rpc", "sc-utils", "serde", + "sp-beefy", "sp-core", "sp-runtime", "thiserror", @@ -513,32 +490,13 @@ dependencies = [ [[package]] name = "beefy-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "beefy-primitives", "sp-api", -] - -[[package]] -name = "beefy-primitives" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" -dependencies = [ - "parity-scale-codec 3.2.1", - "scale-info", - "sp-api", - "sp-application-crypto", - "sp-core", + "sp-beefy", "sp-runtime", - "sp-std", ] -[[package]] -name = "bimap" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0455254eb5c6964c4545d8bac815e1a1be4f3afe0ae695ea539c12d728d44b" - [[package]] name = "bincode" version = "1.3.3" @@ -550,9 +508,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.59.2" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" dependencies = [ "bitflags", "cexpr", @@ -594,26 +552,16 @@ dependencies = [ "funty 2.0.0", "radium 0.7.0", "tap", - "wyz 0.5.0", + "wyz 0.5.1", ] [[package]] name = "blake2" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" -dependencies = [ - "digest 0.10.5", -] - -[[package]] -name = "blake2-rfc" -version = "0.2.18" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "arrayvec 0.4.12", - "constant_time_eq", + "digest 0.10.6", ] [[package]] @@ -624,7 +572,7 @@ checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq", + "constant_time_eq 0.1.5", ] [[package]] @@ -635,21 +583,21 @@ checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq", + "constant_time_eq 0.1.5", ] [[package]] name = "blake3" -version = "1.3.1" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" +checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef" dependencies = [ "arrayref", "arrayvec 0.7.2", "cc", - "cfg-if 1.0.0", - "constant_time_eq", - "digest 0.10.5", + "cfg-if", + "constant_time_eq 0.2.4", + "digest 0.10.6", ] [[package]] @@ -693,16 +641,16 @@ dependencies = [ [[package]] name = "blocking" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc" +checksum = "3c67b173a56acffd6d2326fb7ab938ba0b00a71480e14902b2591c87bc5741e8" dependencies = [ "async-channel", + "async-lock", "async-task", "atomic-waker", "fastrand", "futures-lite", - "once_cell", ] [[package]] @@ -746,7 +694,9 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ + "lazy_static", "memchr", + "regex-automata", ] [[package]] @@ -766,9 +716,9 @@ checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "byte-slice-cast" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c5fdd0166095e1d463fc6cc01aa8ce547ad77a4e84d42eb6762b084e28067e" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "byte-tools" @@ -784,9 +734,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" [[package]] name = "bzip2-sys" @@ -799,12 +749,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "cache-padded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" - [[package]] name = "camino" version = "1.1.1" @@ -831,16 +775,16 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", - "semver 1.0.14", + "semver 1.0.16", "serde", "serde_json", ] [[package]] name = "cc" -version = "1.0.73" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" dependencies = [ "jobserver", ] @@ -863,12 +807,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -887,8 +825,8 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" dependencies = [ - "cfg-if 1.0.0", - "cipher 0.3.0", + "cfg-if", + "cipher", "cpufeatures", "zeroize", ] @@ -901,22 +839,22 @@ checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" dependencies = [ "aead", "chacha20", - "cipher 0.3.0", + "cipher", "poly1305", "zeroize", ] [[package]] name = "chrono" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" dependencies = [ "iana-time-zone", "js-sys", "num-integer", "num-traits", - "time 0.1.44", + "time", "wasm-bindgen", "winapi", ] @@ -943,23 +881,13 @@ dependencies = [ "generic-array 0.14.6", ] -[[package]] -name = "cipher" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "ckb-merkle-mountain-range" -version = "0.3.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f061f97d64fd1822664bdfb722f7ae5469a97b77567390f7442be5b5dc82a5b" +checksum = "56ccb671c5921be8a84686e6212ca184cb1d7c51cadcdbfcbd1cc3f042f5dfb8" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", ] [[package]] @@ -970,31 +898,29 @@ checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" dependencies = [ "glob", "libc", - "libloading 0.7.3", + "libloading", ] [[package]] name = "clap" -version = "3.2.22" +version = "4.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" +checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" dependencies = [ - "atty", "bitflags", "clap_derive", "clap_lex", - "indexmap", + "is-terminal", "once_cell", "strsim", "termcolor", - "textwrap", ] [[package]] name = "clap_derive" -version = "3.2.18" +version = "4.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" dependencies = [ "heck", "proc-macro-error", @@ -1005,22 +931,13 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" dependencies = [ "os_str_bytes", ] -[[package]] -name = "cmake" -version = "0.1.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" -dependencies = [ - "cc", -] - [[package]] name = "coarsetime" version = "0.1.22" @@ -1045,9 +962,9 @@ dependencies = [ [[package]] name = "comfy-table" -version = "6.1.1" +version = "6.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b3d16bb3da60be2f7c7acfc438f2ae6f3496897ce68c291d0509bb67b4e248e" +checksum = "e621e7e86c46fd8a14c32c6ae3cb95656621b4743a27d0cffedb831d46e7ad21" dependencies = [ "strum", "strum_macros", @@ -1056,18 +973,31 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "1.2.4" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" +checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c" dependencies = [ - "cache-padded", + "encode_unicode", + "lazy_static", + "libc", + "terminal_size", + "winapi", ] [[package]] name = "const-oid" -version = "0.7.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" +checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" [[package]] name = "constant_time_eq" @@ -1075,6 +1005,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "constant_time_eq" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279" + [[package]] name = "convert_case" version = "0.4.0" @@ -1112,7 +1048,17 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", +] + +[[package]] +name = "cpu-time" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e393a7668fe1fad3075085b86c781883000b4ede868f43627b34a87c8b7ded" +dependencies = [ + "libc", + "winapi", ] [[package]] @@ -1126,18 +1072,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.88.1" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44409ccf2d0f663920cab563d2b79fcd6b2e9a2bcc6e929fef76c8f82ad6c17a" +checksum = "52056f6d0584484b57fa6c1a65c1fcb15f3780d8b6a758426d9e3084169b2ddd" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.88.1" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de2018ad96eb97f621f7d6b900a0cc661aec8d02ea4a50e56ecb48e5a2fcaf" +checksum = "18fed94c8770dc25d01154c3ffa64ed0b3ba9d583736f305fed7beebe5d9cf74" dependencies = [ "arrayvec 0.7.2", "bumpalo", @@ -1146,7 +1092,7 @@ dependencies = [ "cranelift-codegen-shared", "cranelift-entity", "cranelift-isle", - "gimli", + "gimli 0.26.2", "log", "regalloc2", "smallvec", @@ -1155,33 +1101,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.88.1" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5287ce36e6c4758fbaf298bd1a8697ad97a4f2375a3d1b61142ea538db4877e5" +checksum = "1c451b81faf237d11c7e4f3165eeb6bac61112762c5cfe7b4c0fb7241474358f" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.88.1" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2855c24219e2f08827f3f4ffb2da92e134ae8d8ecc185b11ec8f9878cf5f588e" +checksum = "e7c940133198426d26128f08be2b40b0bd117b84771fd36798969c4d712d81fc" [[package]] name = "cranelift-entity" -version = "0.88.1" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b65673279d75d34bf11af9660ae2dbd1c22e6d28f163f5c72f4e1dc56d56103" +checksum = "87a0f1b2fdc18776956370cf8d9b009ded3f855350c480c1c52142510961f352" dependencies = [ "serde", ] [[package]] name = "cranelift-frontend" -version = "0.88.1" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed2b3d7a4751163f6c4a349205ab1b7d9c00eecf19dcea48592ef1f7688eefc" +checksum = "34897538b36b216cc8dd324e73263596d51b8cf610da6498322838b2546baf8a" dependencies = [ "cranelift-codegen", "log", @@ -1191,15 +1137,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.88.1" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be64cecea9d90105fc6a2ba2d003e98c867c1d6c4c86cc878f97ad9fb916293" +checksum = "1b2629a569fae540f16a76b70afcc87ad7decb38dc28fa6c648ac73b51e78470" [[package]] name = "cranelift-native" -version = "0.88.1" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a03a6ac1b063e416ca4b93f6247978c991475e8271465340caa6f92f3c16a4" +checksum = "20937dab4e14d3e225c5adfc9c7106bafd4ac669bdb43027b911ff794c6fb318" dependencies = [ "cranelift-codegen", "libc", @@ -1208,9 +1154,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.88.1" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c699873f7b30bc5f20dd03a796b4183e073a46616c91704792ec35e45d13f913" +checksum = "80fc2288957a94fd342a015811479de1837850924166d1f1856d8406e6f3609b" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -1228,7 +1174,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1237,7 +1183,7 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] @@ -1247,41 +1193,41 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.11" +version = "0.9.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", - "memoffset", + "memoffset 0.7.1", "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.12" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1292,9 +1238,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.3.2" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ "generic-array 0.14.6", "rand_core 0.6.4", @@ -1348,24 +1294,13 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ - "cipher 0.3.0", -] - -[[package]] -name = "cuckoofilter" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b810a8449931679f64cd7eef1bbd0fa315801b6d5d9cdc1ace2804d6529eee18" -dependencies = [ - "byteorder", - "fnv", - "rand 0.7.3", + "cipher", ] [[package]] name = "cumulus-client-cli" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "clap", "parity-scale-codec 3.2.1", @@ -1380,12 +1315,11 @@ dependencies = [ [[package]] name = "cumulus-client-collator" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "cumulus-client-consensus-common", "cumulus-client-network", "cumulus-primitives-core", - "cumulus-relay-chain-interface", "futures 0.3.25", "parity-scale-codec 3.2.1", "parking_lot 0.12.1", @@ -1404,7 +1338,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-aura" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "async-trait", "cumulus-client-consensus-common", @@ -1433,17 +1367,19 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-common" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "async-trait", + "cumulus-client-pov-recovery", + "cumulus-primitives-core", "cumulus-relay-chain-interface", "dyn-clone", "futures 0.3.25", + "log", "parity-scale-codec 3.2.1", "polkadot-primitives", "sc-client-api", "sc-consensus", - "sp-api", "sp-blockchain", "sp-consensus", "sp-runtime", @@ -1454,11 +1390,10 @@ dependencies = [ [[package]] name = "cumulus-client-network" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "async-trait", "cumulus-relay-chain-interface", - "derive_more", "futures 0.3.25", "futures-timer", "parity-scale-codec 3.2.1", @@ -1467,7 +1402,6 @@ dependencies = [ "polkadot-parachain", "polkadot-primitives", "sc-client-api", - "sp-api", "sp-blockchain", "sp-consensus", "sp-core", @@ -1479,7 +1413,7 @@ dependencies = [ [[package]] name = "cumulus-client-pov-recovery" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "cumulus-primitives-core", "cumulus-relay-chain-interface", @@ -1493,7 +1427,6 @@ dependencies = [ "rand 0.8.5", "sc-client-api", "sc-consensus", - "sp-api", "sp-consensus", "sp-maybe-compressed-blob", "sp-runtime", @@ -1503,43 +1436,41 @@ dependencies = [ [[package]] name = "cumulus-client-service" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-common", "cumulus-client-pov-recovery", "cumulus-primitives-core", + "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", + "cumulus-relay-chain-minimal-node", + "futures 0.3.25", "parking_lot 0.12.1", - "polkadot-overseer", "polkadot-primitives", "sc-client-api", "sc-consensus", - "sc-consensus-babe", "sc-service", + "sc-sysinfo", "sc-telemetry", - "sc-tracing", "sp-api", "sp-blockchain", "sp-consensus", "sp-core", "sp-runtime", - "tracing", ] [[package]] name = "cumulus-pallet-aura-ext" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ - "frame-executive", "frame-support", "frame-system", "pallet-aura", "parity-scale-codec 3.2.1", "scale-info", - "serde", "sp-application-crypto", "sp-consensus-aura", "sp-runtime", @@ -1549,7 +1480,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-dmp-queue" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1561,13 +1492,12 @@ dependencies = [ "sp-runtime", "sp-std", "xcm", - "xcm-executor", ] [[package]] name = "cumulus-pallet-parachain-system" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "bytes", "cumulus-pallet-parachain-system-proc-macro", @@ -1578,11 +1508,9 @@ dependencies = [ "frame-system", "impl-trait-for-tuples", "log", - "pallet-balances", "parity-scale-codec 3.2.1", "polkadot-parachain", "scale-info", - "serde", "sp-core", "sp-externalities", "sp-inherents", @@ -1592,13 +1520,12 @@ dependencies = [ "sp-std", "sp-trie", "sp-version", - "xcm", ] [[package]] name = "cumulus-pallet-parachain-system-proc-macro" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1609,14 +1536,13 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcm" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "cumulus-primitives-core", "frame-support", "frame-system", "parity-scale-codec 3.2.1", "scale-info", - "serde", "sp-io", "sp-runtime", "sp-std", @@ -1626,7 +1552,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcmp-queue" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1644,9 +1570,8 @@ dependencies = [ [[package]] name = "cumulus-primitives-core" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ - "frame-support", "parity-scale-codec 3.2.1", "polkadot-core-primitives", "polkadot-parachain", @@ -1660,7 +1585,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-parachain-inherent" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1683,7 +1608,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-timestamp" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "cumulus-primitives-core", "futures 0.3.25", @@ -1696,18 +1621,14 @@ dependencies = [ [[package]] name = "cumulus-primitives-utility" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "cumulus-primitives-core", "frame-support", "log", "parity-scale-codec 3.2.1", - "polkadot-core-primitives", - "polkadot-parachain", - "polkadot-primitives", "sp-runtime", "sp-std", - "sp-trie", "xcm", "xcm-builder", "xcm-executor", @@ -1716,7 +1637,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-inprocess-interface" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1728,63 +1649,98 @@ dependencies = [ "polkadot-service", "sc-cli", "sc-client-api", - "sc-consensus-babe", - "sc-network", "sc-sysinfo", "sc-telemetry", "sc-tracing", "sp-api", - "sp-blockchain", "sp-consensus", "sp-core", "sp-runtime", "sp-state-machine", - "tracing", ] [[package]] name = "cumulus-relay-chain-interface" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "async-trait", "cumulus-primitives-core", - "derive_more", "futures 0.3.25", "jsonrpsee-core", "parity-scale-codec 3.2.1", - "parking_lot 0.12.1", "polkadot-overseer", "polkadot-service", "sc-client-api", "sp-api", "sp-blockchain", - "sp-core", - "sp-runtime", "sp-state-machine", "thiserror", + "tokio", +] + +[[package]] +name = "cumulus-relay-chain-minimal-node" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" +dependencies = [ + "array-bytes 6.0.0", + "async-trait", + "cumulus-primitives-core", + "cumulus-relay-chain-interface", + "cumulus-relay-chain-rpc-interface", + "futures 0.3.25", + "lru", + "polkadot-core-primitives", + "polkadot-network-bridge", + "polkadot-node-network-protocol", + "polkadot-node-subsystem-util", + "polkadot-overseer", + "polkadot-primitives", + "polkadot-service", + "sc-authority-discovery", + "sc-client-api", + "sc-consensus", + "sc-keystore", + "sc-network", + "sc-network-common", + "sc-service", + "sc-telemetry", + "sc-tracing", + "sc-transaction-pool", + "sc-transaction-pool-api", + "sp-api", + "sp-blockchain", + "sp-consensus", + "sp-consensus-babe", + "sp-runtime", + "tokio", + "tracing", + "url", ] [[package]] name = "cumulus-relay-chain-rpc-interface" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "async-trait", - "backoff", "cumulus-primitives-core", "cumulus-relay-chain-interface", "futures 0.3.25", "futures-timer", "jsonrpsee", + "lru", "parity-scale-codec 3.2.1", - "parking_lot 0.12.1", "polkadot-service", "sc-client-api", "sc-rpc-api", + "serde", + "serde_json", "sp-api", + "sp-authority-discovery", + "sp-consensus-babe", "sp-core", - "sp-runtime", "sp-state-machine", "sp-storage", "tokio", @@ -1795,7 +1751,7 @@ dependencies = [ [[package]] name = "cumulus-test-relay-sproof-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "cumulus-primitives-core", "parity-scale-codec 3.2.1", @@ -1833,22 +1789,23 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-pre.1" +version = "4.0.0-pre.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4033478fbf70d6acf2655ac70da91ee65852d69daf7a67bf7a2f518fb47aafcf" +checksum = "67bc65846be335cb20f4e52d49a437b773a2c1fdb42b19fc84e79e6f6771536f" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.6.4", + "cfg-if", + "fiat-crypto", + "packed_simd_2", + "platforms 3.0.2", "subtle", "zeroize", ] [[package]] name = "cxx" -version = "1.0.79" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f83d0ebf42c6eafb8d7c52f7e5f2d3003b89c7aa4fd2b79229209459a849af8" +checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" dependencies = [ "cc", "cxxbridge-flags", @@ -1858,9 +1815,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.79" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07d050484b55975889284352b0ffc2ecbda25c0c55978017c132b29ba0818a86" +checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" dependencies = [ "cc", "codespan-reporting", @@ -1873,15 +1830,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.79" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d2199b00553eda8012dfec8d3b1c75fce747cf27c169a270b3b99e3448ab78" +checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" [[package]] name = "cxxbridge-macro" -version = "1.0.79" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb67a6de1f602736dd7eaead0080cf3435df806c61b24b13328db128c58868f" +checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" dependencies = [ "proc-macro2", "quote", @@ -1890,9 +1847,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" +checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" [[package]] name = "data-encoding-macro" @@ -1916,11 +1873,12 @@ dependencies = [ [[package]] name = "der" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" dependencies = [ "const-oid", + "zeroize", ] [[package]] @@ -1947,6 +1905,12 @@ dependencies = [ "syn", ] +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "digest" version = "0.8.1" @@ -1967,9 +1931,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer 0.10.3", "crypto-common", @@ -1991,7 +1955,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "dirs-sys-next", ] @@ -2028,16 +1992,22 @@ dependencies = [ ] [[package]] -name = "downcast-rs" +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + +[[package]] +name = "downcast-rs" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "dtoa" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a6eee2d5d0d113f015688310da018bd1d864d86bd567c8fca9c266889e1bfa" +checksum = "c00704156a7de8df8da0911424e30c2049957b0a714542a44e05fe693dd85313" [[package]] name = "dyn-clonable" @@ -2062,15 +2032,15 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f94fa09c2aeea5b8839e414b7b841bf429fd25b9c522116ac97ee87856d88b2" +checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60" [[package]] name = "ecdsa" -version = "0.13.4" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" dependencies = [ "der", "elliptic-curve", @@ -2103,15 +2073,15 @@ dependencies = [ [[package]] name = "ed25519-zebra" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" dependencies = [ "curve25519-dalek 3.2.0", + "hashbrown", "hex", "rand_core 0.6.4", "sha2 0.9.9", - "thiserror", "zeroize", ] @@ -2123,13 +2093,14 @@ checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "elliptic-curve" -version = "0.11.12" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ "base16ct", "crypto-bigint", "der", + "digest 0.10.6", "ff", "generic-array 0.14.6", "group", @@ -2139,11 +2110,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "enum-as-inner" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" +checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ "heck", "proc-macro2", @@ -2173,9 +2150,9 @@ dependencies = [ [[package]] name = "enumn" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038b1afa59052df211f9efd58f8b1d84c242935ede1c3dbaed26b018a9e06ae2" +checksum = "e88bcb3a067a6555d577aba299e75eff9942da276e6506fc6274327daa026132" dependencies = [ "proc-macro2", "quote", @@ -2184,9 +2161,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ "atty", "humantime", @@ -2197,9 +2174,9 @@ dependencies = [ [[package]] name = "environmental" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b91989ae21441195d7d9b9993a2f9295c7e1a8c96255d8b729accddc124797" +checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" [[package]] name = "errno" @@ -2229,7 +2206,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" dependencies = [ "crunchy", - "fixed-hash", + "fixed-hash 0.7.0", + "impl-codec", + "impl-rlp", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash 0.8.0", "impl-codec", "impl-rlp", "impl-serde", @@ -2244,15 +2235,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23750149fe8834c0e24bb9adcbacbe06c45b9861f15df53e09f26cb7c4ab91ef" dependencies = [ "bytes", - "ethereum-types", + "ethereum-types 0.13.1", "hash-db", "hash256-std-hasher", - "parity-scale-codec 3.2.1", "rlp", "rlp-derive", + "sha3 0.10.6", + "triehash", +] + +[[package]] +name = "ethereum" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89fb87a9e103f71b903b80b670200b54cc67a07578f070681f1fffb7396fb7" +dependencies = [ + "bytes", + "ethereum-types 0.14.1", + "hash-db", + "hash256-std-hasher", + "parity-scale-codec 3.2.1", + "rlp", "scale-info", "serde", - "sha3", + "sha3 0.10.6", "triehash", ] @@ -2262,12 +2268,27 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" dependencies = [ - "ethbloom", - "fixed-hash", + "ethbloom 0.12.1", + "fixed-hash 0.7.0", + "impl-codec", + "impl-rlp", + "primitive-types 0.11.1", + "scale-info", + "uint", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom 0.13.0", + "fixed-hash 0.8.0", "impl-codec", "impl-rlp", "impl-serde", - "primitive-types", + "primitive-types 0.12.1", "scale-info", "uint", ] @@ -2281,57 +2302,61 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "evm" version = "0.35.0" -source = "git+https://github.com/uniquenetwork/evm?branch=unique-polkadot-v0.9.30#e9252ed42dc26fc85b6703b1ba50660a08209e55" +source = "git+https://github.com/uniquenetwork/evm?branch=unique-polkadot-v0.9.36#a68cd3ea5ee2eb310e3452e660a8e9e56a474d2a" dependencies = [ "auto_impl", "environmental", - "ethereum", + "ethereum 0.14.0", "evm-core", "evm-gasometer", "evm-runtime", "log", "parity-scale-codec 3.2.1", - "primitive-types", + "primitive-types 0.12.1", "rlp", "scale-info", "serde", - "sha3", + "sha3 0.10.6", ] [[package]] name = "evm-coder" -version = "0.1.3" +version = "0.1.5" dependencies = [ - "ethereum", + "ethereum 0.14.0", "evm-coder-procedural", "evm-core", "frame-support", "hex", "hex-literal", "impl-trait-for-tuples", - "primitive-types", + "pallet-evm", + "primitive-types 0.12.1", + "sha3-const", + "similar-asserts", "sp-std", + "trybuild", ] [[package]] name = "evm-coder-procedural" -version = "0.2.0" +version = "0.2.2" dependencies = [ "Inflector", "hex", "proc-macro2", "quote", - "sha3", + "sha3 0.10.6", "syn", ] [[package]] name = "evm-core" version = "0.35.0" -source = "git+https://github.com/uniquenetwork/evm?branch=unique-polkadot-v0.9.30#e9252ed42dc26fc85b6703b1ba50660a08209e55" +source = "git+https://github.com/uniquenetwork/evm?branch=unique-polkadot-v0.9.36#a68cd3ea5ee2eb310e3452e660a8e9e56a474d2a" dependencies = [ "parity-scale-codec 3.2.1", - "primitive-types", + "primitive-types 0.12.1", "scale-info", "serde", ] @@ -2339,24 +2364,24 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.35.0" -source = "git+https://github.com/uniquenetwork/evm?branch=unique-polkadot-v0.9.30#e9252ed42dc26fc85b6703b1ba50660a08209e55" +source = "git+https://github.com/uniquenetwork/evm?branch=unique-polkadot-v0.9.36#a68cd3ea5ee2eb310e3452e660a8e9e56a474d2a" dependencies = [ "environmental", "evm-core", "evm-runtime", - "primitive-types", + "primitive-types 0.12.1", ] [[package]] name = "evm-runtime" version = "0.35.0" -source = "git+https://github.com/uniquenetwork/evm?branch=unique-polkadot-v0.9.30#e9252ed42dc26fc85b6703b1ba50660a08209e55" +source = "git+https://github.com/uniquenetwork/evm?branch=unique-polkadot-v0.9.36#a68cd3ea5ee2eb310e3452e660a8e9e56a474d2a" dependencies = [ "auto_impl", "environmental", "evm-core", - "primitive-types", - "sha3", + "primitive-types 0.12.1", + "sha3 0.10.6", ] [[package]] @@ -2442,7 +2467,7 @@ dependencies = [ [[package]] name = "fc-consensus" version = "2.0.0-dev" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ "async-trait", "fc-db", @@ -2461,14 +2486,17 @@ dependencies = [ [[package]] name = "fc-db" version = "2.0.0-dev" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ "fp-storage", "kvdb-rocksdb", + "log", "parity-db", "parity-scale-codec 3.2.1", "parking_lot 0.12.1", "sc-client-db", + "smallvec", + "sp-blockchain", "sp-core", "sp-database", "sp-runtime", @@ -2477,7 +2505,7 @@ dependencies = [ [[package]] name = "fc-mapping-sync" version = "2.0.0-dev" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ "fc-db", "fp-consensus", @@ -2494,13 +2522,15 @@ dependencies = [ [[package]] name = "fc-rpc" version = "2.0.0-dev" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ - "ethereum", - "ethereum-types", + "ethereum 0.14.0", + "ethereum-types 0.14.1", "evm", "fc-db", "fc-rpc-core", + "fp-ethereum", + "fp-evm", "fp-rpc", "fp-storage", "futures 0.3.25", @@ -2508,12 +2538,11 @@ dependencies = [ "jsonrpsee", "libsecp256k1", "log", - "lru 0.7.8", + "lru", "parity-scale-codec 3.2.1", "prometheus", "rand 0.8.5", "rlp", - "rustc-hex", "sc-client-api", "sc-network", "sc-network-common", @@ -2536,10 +2565,10 @@ dependencies = [ [[package]] name = "fc-rpc-core" version = "1.1.0-dev" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ - "ethereum", - "ethereum-types", + "ethereum 0.14.0", + "ethereum-types 0.14.1", "jsonrpsee", "rlp", "rustc-hex", @@ -2558,14 +2587,20 @@ dependencies = [ [[package]] name = "ff" -version = "0.11.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" dependencies = [ "rand_core 0.6.4", "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a214f5bb88731d436478f3ae1f8a277b62124089ba9fb67f4f93fb100ef73c90" + [[package]] name = "file-per-thread-logger" version = "0.1.5" @@ -2578,11 +2613,11 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" +checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "windows-sys 0.42.0", @@ -2609,6 +2644,17 @@ name = "fixed-hash" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "byteorder", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", "rand 0.8.5", @@ -2624,9 +2670,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ "crc32fast", "libz-sys", @@ -2635,19 +2681,27 @@ dependencies = [ [[package]] name = "flexi_logger" -version = "0.22.6" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c76a80dd14a27fc3d8bc696502132cb52b3f227256fd8601166c3a35e45f409" +checksum = "ade8e86c48285f138a4d6ca15a2912e39bd6c74d62db42da4f1985f651a0b057" dependencies = [ - "ansi_term", "atty", + "chrono", "glob", "lazy_static", "log", + "nu-ansi-term", "regex", - "rustversion", "thiserror", - "time 0.3.9", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", ] [[package]] @@ -2659,7 +2713,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", ] @@ -2676,19 +2730,34 @@ dependencies = [ [[package]] name = "fp-consensus" version = "2.0.0-dev" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ - "ethereum", + "ethereum 0.14.0", "parity-scale-codec 3.2.1", "sp-core", "sp-runtime", "sp-std", ] +[[package]] +name = "fp-ethereum" +version = "1.0.0-dev" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" +dependencies = [ + "ethereum 0.14.0", + "ethereum-types 0.14.1", + "fp-evm", + "frame-support", + "num_enum", + "parity-scale-codec 3.2.1", + "sp-core", + "sp-std", +] + [[package]] name = "fp-evm" version = "3.0.0-dev" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ "evm", "frame-support", @@ -2702,7 +2771,7 @@ dependencies = [ [[package]] name = "fp-evm-mapping" version = "0.1.0" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ "frame-support", "sp-core", @@ -2711,10 +2780,10 @@ dependencies = [ [[package]] name = "fp-rpc" version = "3.0.0-dev" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ - "ethereum", - "ethereum-types", + "ethereum 0.14.0", + "ethereum-types 0.14.1", "fp-evm", "parity-scale-codec 3.2.1", "scale-info", @@ -2728,31 +2797,35 @@ dependencies = [ [[package]] name = "fp-self-contained" version = "1.0.0-dev" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ - "ethereum", + "ethereum 0.14.0", "frame-support", "parity-scale-codec 3.2.1", - "parity-util-mem", "scale-info", "serde", - "sp-debug-derive", - "sp-io", "sp-runtime", ] [[package]] name = "fp-storage" version = "2.0.0" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ "parity-scale-codec 3.2.1", + "serde", ] +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "frame-system", @@ -2775,10 +2848,10 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "Inflector", - "array-bytes", + "array-bytes 4.2.0", "chrono", "clap", "comfy-table", @@ -2816,6 +2889,7 @@ dependencies = [ "sp-keystore", "sp-runtime", "sp-state-machine", + "sp-std", "sp-storage", "sp-trie", "tempfile", @@ -2826,7 +2900,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2837,7 +2911,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -2845,6 +2919,7 @@ dependencies = [ "parity-scale-codec 3.2.1", "scale-info", "sp-arithmetic", + "sp-core", "sp-npos-elections", "sp-runtime", "sp-std", @@ -2853,7 +2928,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "frame-system", @@ -2873,16 +2948,35 @@ version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df6bb8542ef006ef0de09a5c4420787d79823c0ed7924225822362fd2bf2ff2d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "parity-scale-codec 3.2.1", "scale-info", "serde", ] +[[package]] +name = "frame-remote-externalities" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" +dependencies = [ + "env_logger", + "futures 0.3.25", + "log", + "parity-scale-codec 3.2.1", + "serde", + "serde_json", + "sp-core", + "sp-io", + "sp-runtime", + "sp-version", + "substrate-rpc-client", + "tokio", +] + [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "bitflags", "frame-metadata", @@ -2914,7 +3008,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "Inflector", "cfg-expr", @@ -2928,7 +3022,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -2940,7 +3034,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "proc-macro2", "quote", @@ -2950,7 +3044,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "log", @@ -2968,7 +3062,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -2983,7 +3077,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", "sp-api", @@ -2992,7 +3086,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "parity-scale-codec 3.2.1", @@ -3003,21 +3097,9 @@ dependencies = [ [[package]] name = "fs-err" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64db3e262960f0662f43a6366788d5f10f7f244b8f7d7d987f560baf5ded5c50" - -[[package]] -name = "fs-swap" -version = "0.2.6" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d47dad3685eceed8488986cad3d5027165ea5edb164331770e2059555f10a5" -dependencies = [ - "lazy_static", - "libc", - "libloading 0.5.2", - "winapi", -] +checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" [[package]] name = "fs2" @@ -3220,7 +3302,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", @@ -3233,7 +3315,7 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.11.0+wasi-snapshot-preview1", ] @@ -3259,6 +3341,12 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" + [[package]] name = "glob" version = "0.3.0" @@ -3280,9 +3368,9 @@ dependencies = [ [[package]] name = "gloo-timers" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" +checksum = "98c4a8d6391675c6b2ee1a6c8d06e8e2d03605c44cec1270675985a4c2a5500b" dependencies = [ "futures-channel", "futures-core", @@ -3292,9 +3380,9 @@ dependencies = [ [[package]] name = "group" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ "ff", "rand_core 0.6.4", @@ -3303,9 +3391,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" dependencies = [ "bytes", "fnv", @@ -3322,9 +3410,9 @@ dependencies = [ [[package]] name = "handlebars" -version = "4.3.5" +version = "4.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433e4ab33f1213cdc25b5fa45c76881240cfe79284cf2b395e8b9e312a30a2fd" +checksum = "035ef95d03713f2c347a72547b7cd38cbc9af7cd51e6099fb62d586d4a6dee3a" dependencies = [ "log", "pest", @@ -3373,6 +3461,15 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + [[package]] name = "hex" version = "0.4.3" @@ -3385,12 +3482,6 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" -[[package]] -name = "hex_fmt" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" - [[package]] name = "hmac" version = "0.8.1" @@ -3411,6 +3502,15 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.6", +] + [[package]] name = "hmac-drbg" version = "0.3.0" @@ -3455,6 +3555,12 @@ dependencies = [ "pin-project-lite 0.2.9", ] +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + [[package]] name = "httparse" version = "1.8.0" @@ -3475,9 +3581,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.20" +version = "0.14.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" +checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" dependencies = [ "bytes", "futures-channel", @@ -3499,9 +3605,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.0" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ "http", "hyper", @@ -3514,9 +3620,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.51" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -3569,9 +3675,9 @@ dependencies = [ [[package]] name = "if-watch" -version = "1.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "015a7df1eb6dda30df37f34b63ada9b7b352984b0e84de2a20ed526345000791" +checksum = "065c008e570a43c00de6aed9714035e5ea6a498c255323db9091722af6ee67dd" dependencies = [ "async-io", "core-foundation", @@ -3605,9 +3711,9 @@ dependencies = [ [[package]] name = "impl-serde" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" dependencies = [ "serde", ] @@ -3625,31 +3731,22 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", "hashbrown", "serde", ] -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array 0.14.6", -] - [[package]] name = "instant" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -3669,9 +3766,19 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "0.7.3" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074" + +[[package]] +name = "io-lifetimes" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ea37f355c05dde75b84bba2d767906ad522e97cd9e2eef2be7a4ab7fb442c06" +checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +dependencies = [ + "libc", + "windows-sys 0.42.0", +] [[package]] name = "ip_network" @@ -3681,9 +3788,9 @@ checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" [[package]] name = "ipconfig" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98" +checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be" dependencies = [ "socket2", "widestring", @@ -3693,9 +3800,21 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.5.0" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" + +[[package]] +name = "is-terminal" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +dependencies = [ + "hermit-abi 0.2.6", + "io-lifetimes 1.0.3", + "rustix 0.36.5", + "windows-sys 0.42.0", +] [[package]] name = "itertools" @@ -3708,9 +3827,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "jobserver" @@ -3732,24 +3851,23 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.15.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd0d559d5e679b1ab2f869b486a11182923863b1b3ee8b421763cdd707b783a" +checksum = "7d291e3a5818a2384645fd9756362e6d89cf0541b0b916fa7702ea4a9833608e" dependencies = [ "jsonrpsee-core", - "jsonrpsee-http-server", "jsonrpsee-proc-macros", + "jsonrpsee-server", "jsonrpsee-types", "jsonrpsee-ws-client", - "jsonrpsee-ws-server", "tracing", ] [[package]] name = "jsonrpsee-client-transport" -version = "0.15.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8752740ecd374bcbf8b69f3e80b0327942df76f793f8d4e60d3355650c31fb74" +checksum = "965de52763f2004bc91ac5bcec504192440f0b568a5d621c59d9dbd6f886c3fb" dependencies = [ "futures-util", "http", @@ -3768,9 +3886,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.15.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3dc3e9cf2ba50b7b1d7d76a667619f82846caa39e8e8daa8a4962d74acaddca" +checksum = "a4e70b4439a751a5de7dd5ed55eacff78ebf4ffe0fc009cb1ebb11417f5b536b" dependencies = [ "anyhow", "arrayvec 0.7.2", @@ -3781,10 +3899,8 @@ dependencies = [ "futures-timer", "futures-util", "globset", - "http", "hyper", "jsonrpsee-types", - "lazy_static", "parking_lot 0.12.1", "rand 0.8.5", "rustc-hash", @@ -3794,45 +3910,48 @@ dependencies = [ "thiserror", "tokio", "tracing", - "tracing-futures", - "unicase", ] [[package]] -name = "jsonrpsee-http-server" -version = "0.15.1" +name = "jsonrpsee-proc-macros" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa6da1e4199c10d7b1d0a6e5e8bd8e55f351163b6f4b3cbb044672a69bd4c1c" +dependencies = [ + "heck", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "jsonrpsee-server" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03802f0373a38c2420c70b5144742d800b509e2937edc4afb116434f07120117" +checksum = "1fb69dad85df79527c019659a992498d03f8495390496da2f07e6c24c2b356fc" dependencies = [ "futures-channel", "futures-util", + "http", "hyper", "jsonrpsee-core", "jsonrpsee-types", "serde", "serde_json", + "soketto", "tokio", + "tokio-stream", + "tokio-util", + "tower", "tracing", - "tracing-futures", -] - -[[package]] -name = "jsonrpsee-proc-macros" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd67957d4280217247588ac86614ead007b301ca2fa9f19c19f880a536f029e3" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", ] [[package]] name = "jsonrpsee-types" -version = "0.15.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e290bba767401b646812f608c099b922d8142603c9e73a50fb192d3ac86f4a0d" +checksum = "5bd522fe1ce3702fd94812965d7bb7a3364b1c9aba743944c5a00529aae80f8c" dependencies = [ "anyhow", "beef", @@ -3844,9 +3963,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.15.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee5feddd5188e62ac08fcf0e56478138e581509d4730f3f7be9b57dd402a4ff" +checksum = "0b83daeecfc6517cfe210df24e570fb06213533dfb990318fae781f4c7119dd9" dependencies = [ "http", "jsonrpsee-client-transport", @@ -3854,50 +3973,32 @@ dependencies = [ "jsonrpsee-types", ] -[[package]] -name = "jsonrpsee-ws-server" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d488ba74fb369e5ab68926feb75a483458b88e768d44319f37e4ecad283c7325" -dependencies = [ - "futures-channel", - "futures-util", - "http", - "jsonrpsee-core", - "jsonrpsee-types", - "serde_json", - "soketto", - "tokio", - "tokio-stream", - "tokio-util", - "tracing", - "tracing-futures", -] - [[package]] name = "k256" -version = "0.10.4" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "ecdsa", "elliptic-curve", - "sec1", + "sha2 0.10.6", ] [[package]] name = "keccak" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] [[package]] name = "kusama-runtime" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ - "beefy-primitives", "bitvec 1.0.1", "frame-benchmarking", "frame-election-provider-support", @@ -3918,18 +4019,19 @@ dependencies = [ "pallet-bounties", "pallet-child-bounties", "pallet-collective", + "pallet-conviction-voting", "pallet-democracy", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", - "pallet-gilt", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-membership", "pallet-multisig", + "pallet-nis", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", @@ -3937,13 +4039,14 @@ dependencies = [ "pallet-offences-benchmarking", "pallet-preimage", "pallet-proxy", + "pallet-ranked-collective", "pallet-recovery", + "pallet-referenda", "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", "pallet-society", "pallet-staking", - "pallet-staking-reward-fn", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", @@ -3951,6 +4054,7 @@ dependencies = [ "pallet-treasury", "pallet-utility", "pallet-vesting", + "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "parity-scale-codec 3.2.1", @@ -3965,6 +4069,7 @@ dependencies = [ "sp-api", "sp-arithmetic", "sp-authority-discovery", + "sp-beefy", "sp-block-builder", "sp-consensus-babe", "sp-core", @@ -3988,14 +4093,16 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "frame-support", "polkadot-primitives", "polkadot-runtime-common", "smallvec", + "sp-core", "sp-runtime", + "sp-weights", ] [[package]] @@ -4009,37 +4116,31 @@ dependencies = [ [[package]] name = "kvdb" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a301d8ecb7989d4a6e2c57a49baca77d353bdbf879909debe3f375fe25d61f86" +checksum = "e7d770dcb02bf6835887c3a979b5107a04ff4bbde97a5f0928d27404a155add9" dependencies = [ - "parity-util-mem", "smallvec", ] [[package]] name = "kvdb-memorydb" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece7e668abd21387aeb6628130a6f4c802787f014fa46bc83221448322250357" +checksum = "bf7a85fe66f9ff9cd74e169fdd2c94c6e1e74c412c99a73b4df3200b5d3760b2" dependencies = [ "kvdb", - "parity-util-mem", "parking_lot 0.12.1", ] [[package]] name = "kvdb-rocksdb" -version = "0.15.2" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca7fbdfd71cd663dceb0faf3367a99f8cf724514933e9867cec4995b6027cbc1" +checksum = "2182b8219fee6bd83aacaab7344e840179ae079d5216aa4e249b4d704646a844" dependencies = [ - "fs-swap", "kvdb", - "log", "num_cpus", - "owning_ref", - "parity-util-mem", "parking_lot 0.12.1", "regex", "rocksdb", @@ -4060,41 +4161,37 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.135" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libloading" -version = "0.5.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ - "cc", + "cfg-if", "winapi", ] [[package]] -name = "libloading" -version = "0.7.3" +name = "libm" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" -dependencies = [ - "cfg-if 1.0.0", - "winapi", -] +checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" [[package]] name = "libm" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "292a948cd991e376cf75541fe5b97a1081d713c618b4f1b9500f8844e49eb565" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] name = "libp2p" -version = "0.46.1" +version = "0.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81327106887e42d004fbdab1fef93675be2e2e07c1b95fce45e2cc813485611d" +checksum = "ec878fda12ebec479186b3914ebc48ff180fa4c51847e11a1a68bf65249e02c1" dependencies = [ "bytes", "futures 0.3.25", @@ -4102,12 +4199,8 @@ dependencies = [ "getrandom 0.2.8", "instant", "lazy_static", - "libp2p-autonat", "libp2p-core", - "libp2p-deflate", "libp2p-dns", - "libp2p-floodsub", - "libp2p-gossipsub", "libp2p-identify", "libp2p-kad", "libp2p-mdns", @@ -4115,49 +4208,24 @@ dependencies = [ "libp2p-mplex", "libp2p-noise", "libp2p-ping", - "libp2p-plaintext", - "libp2p-pnet", - "libp2p-relay", - "libp2p-rendezvous", "libp2p-request-response", "libp2p-swarm", "libp2p-swarm-derive", "libp2p-tcp", - "libp2p-uds", "libp2p-wasm-ext", "libp2p-websocket", "libp2p-yamux", "multiaddr", "parking_lot 0.12.1", "pin-project", - "rand 0.7.3", "smallvec", ] -[[package]] -name = "libp2p-autonat" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4decc51f3573653a9f4ecacb31b1b922dd20c25a6322bb15318ec04287ec46f9" -dependencies = [ - "async-trait", - "futures 0.3.25", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-request-response", - "libp2p-swarm", - "log", - "prost 0.10.4", - "prost-build 0.10.4", - "rand 0.8.5", -] - [[package]] name = "libp2p-core" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf9b94cefab7599b2d3dff2f93bee218c6621d68590b23ede4485813cbcece6" +checksum = "799676bb0807c788065e57551c6527d461ad572162b0519d1958946ff9e0539d" dependencies = [ "asn1_der", "bs58", @@ -4168,17 +4236,15 @@ dependencies = [ "futures-timer", "instant", "lazy_static", - "libsecp256k1", "log", "multiaddr", "multihash", "multistream-select", "parking_lot 0.12.1", "pin-project", - "prost 0.10.4", - "prost-build 0.10.4", + "prost", + "prost-build", "rand 0.8.5", - "ring", "rw-stream-sink", "sha2 0.10.6", "smallvec", @@ -4188,24 +4254,12 @@ dependencies = [ "zeroize", ] -[[package]] -name = "libp2p-deflate" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0183dc2a3da1fbbf85e5b6cf51217f55b14f5daea0c455a9536eef646bfec71" -dependencies = [ - "flate2", - "futures 0.3.25", - "libp2p-core", -] - [[package]] name = "libp2p-dns" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cbf54723250fa5d521383be789bf60efdabe6bacfb443f87da261019a49b4b5" +checksum = "2322c9fb40d99101def6a01612ee30500c89abbbecb6297b3cd252903a4c1720" dependencies = [ - "async-std-resolver", "futures 0.3.25", "libp2p-core", "log", @@ -4214,57 +4268,11 @@ dependencies = [ "trust-dns-resolver", ] -[[package]] -name = "libp2p-floodsub" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98a4b6ffd53e355775d24b76f583fdda54b3284806f678499b57913adb94f231" -dependencies = [ - "cuckoofilter", - "fnv", - "futures 0.3.25", - "libp2p-core", - "libp2p-swarm", - "log", - "prost 0.10.4", - "prost-build 0.10.4", - "rand 0.7.3", - "smallvec", -] - -[[package]] -name = "libp2p-gossipsub" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b4b888cfbeb1f5551acd3aa1366e01bf88ede26cc3c4645d0d2d004d5ca7b0" -dependencies = [ - "asynchronous-codec", - "base64", - "byteorder", - "bytes", - "fnv", - "futures 0.3.25", - "hex_fmt", - "instant", - "libp2p-core", - "libp2p-swarm", - "log", - "prometheus-client", - "prost 0.10.4", - "prost-build 0.10.4", - "rand 0.7.3", - "regex", - "sha2 0.10.6", - "smallvec", - "unsigned-varint", - "wasm-timer", -] - [[package]] name = "libp2p-identify" -version = "0.37.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50b585518f8efd06f93ac2f976bd672e17cdac794644b3117edd078e96bda06" +checksum = "dcf9a121f699e8719bda2e6e9e9b6ddafc6cff4602471d6481c1067930ccb29b" dependencies = [ "asynchronous-codec", "futures 0.3.25", @@ -4272,9 +4280,9 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "lru 0.7.8", - "prost 0.10.4", - "prost-build 0.10.4", + "lru", + "prost", + "prost-build", "prost-codec", "smallvec", "thiserror", @@ -4283,9 +4291,9 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.38.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740862893bb5f06ac24acc9d49bdeadc3a5e52e51818a30a25c1f3519da2c851" +checksum = "6721c200e2021f6c3fab8b6cf0272ead8912d871610ee194ebd628cecf428f22" dependencies = [ "arrayvec 0.7.2", "asynchronous-codec", @@ -4298,9 +4306,9 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "prost 0.10.4", - "prost-build 0.10.4", - "rand 0.7.3", + "prost", + "prost-build", + "rand 0.8.5", "sha2 0.10.6", "smallvec", "thiserror", @@ -4311,46 +4319,43 @@ dependencies = [ [[package]] name = "libp2p-mdns" -version = "0.38.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66e5e5919509603281033fd16306c61df7a4428ce274b67af5e14b07de5cdcb2" +checksum = "761704e727f7d68d58d7bc2231eafae5fc1b9814de24290f126df09d4bd37a15" dependencies = [ - "async-io", "data-encoding", "dns-parser", "futures 0.3.25", "if-watch", - "lazy_static", "libp2p-core", "libp2p-swarm", "log", "rand 0.8.5", "smallvec", "socket2", + "tokio", "void", ] [[package]] name = "libp2p-metrics" -version = "0.7.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8aff4a1abef42328fbb30b17c853fff9be986dc39af17ee39f9c5f755c5e0c" +checksum = "9ee31b08e78b7b8bfd1c4204a9dd8a87b4fcdf6dafc57eb51701c1c264a81cb9" dependencies = [ "libp2p-core", - "libp2p-gossipsub", "libp2p-identify", "libp2p-kad", "libp2p-ping", - "libp2p-relay", "libp2p-swarm", "prometheus-client", ] [[package]] name = "libp2p-mplex" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61fd1b20638ec209c5075dfb2e8ce6a7ea4ec3cd3ad7b77f7a477c06d53322e2" +checksum = "692664acfd98652de739a8acbb0a0d670f1d67190a49be6b4395e22c37337d89" dependencies = [ "asynchronous-codec", "bytes", @@ -4359,16 +4364,16 @@ dependencies = [ "log", "nohash-hasher", "parking_lot 0.12.1", - "rand 0.7.3", + "rand 0.8.5", "smallvec", "unsigned-varint", ] [[package]] name = "libp2p-noise" -version = "0.37.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "762408cb5d84b49a600422d7f9a42c18012d8da6ebcd570f9a4a4290ba41fb6f" +checksum = "048155686bd81fe6cb5efdef0c6290f25ad32a0a42e8f4f72625cf6a505a206f" dependencies = [ "bytes", "curve25519-dalek 3.2.0", @@ -4376,8 +4381,8 @@ dependencies = [ "lazy_static", "libp2p-core", "log", - "prost 0.10.4", - "prost-build 0.10.4", + "prost", + "prost-build", "rand 0.8.5", "sha2 0.10.6", "snow", @@ -4388,105 +4393,25 @@ dependencies = [ [[package]] name = "libp2p-ping" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "100a6934ae1dbf8a693a4e7dd1d730fd60b774dafc45688ed63b554497c6c925" -dependencies = [ - "futures 0.3.25", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-swarm", - "log", - "rand 0.7.3", - "void", -] - -[[package]] -name = "libp2p-plaintext" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be27bf0820a6238a4e06365b096d428271cce85a129cf16f2fe9eb1610c4df86" -dependencies = [ - "asynchronous-codec", - "bytes", - "futures 0.3.25", - "libp2p-core", - "log", - "prost 0.10.4", - "prost-build 0.10.4", - "unsigned-varint", - "void", -] - -[[package]] -name = "libp2p-pnet" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5a702574223aa55d8878bdc8bf55c84a6086f87ddaddc28ce730b4caa81538" -dependencies = [ - "futures 0.3.25", - "log", - "pin-project", - "rand 0.8.5", - "salsa20", - "sha3", -] - -[[package]] -name = "libp2p-relay" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4931547ee0cce03971ccc1733ff05bb0c4349fd89120a39e9861e2bbe18843c3" -dependencies = [ - "asynchronous-codec", - "bytes", - "either", - "futures 0.3.25", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-swarm", - "log", - "pin-project", - "prost 0.10.4", - "prost-build 0.10.4", - "prost-codec", - "rand 0.8.5", - "smallvec", - "static_assertions", - "thiserror", - "void", -] - -[[package]] -name = "libp2p-rendezvous" -version = "0.7.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9511c9672ba33284838e349623319c8cad2d18cfad243ae46c6b7e8a2982ea4e" +checksum = "7228b9318d34689521349a86eb39a3c3a802c9efc99a0568062ffb80913e3f91" dependencies = [ - "asynchronous-codec", - "bimap", "futures 0.3.25", "futures-timer", "instant", "libp2p-core", "libp2p-swarm", "log", - "prost 0.10.4", - "prost-build 0.10.4", "rand 0.8.5", - "sha2 0.10.6", - "thiserror", - "unsigned-varint", "void", ] [[package]] name = "libp2p-request-response" -version = "0.19.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "508a189e2795d892c8f5c1fa1e9e0b1845d32d7b0b249dbf7b05b18811361843" +checksum = "8827af16a017b65311a410bb626205a9ad92ec0473967618425039fa5231adc1" dependencies = [ "async-trait", "bytes", @@ -4495,16 +4420,16 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "rand 0.7.3", + "rand 0.8.5", "smallvec", "unsigned-varint", ] [[package]] name = "libp2p-swarm" -version = "0.37.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ac5be6c2de2d1ff3f7693fda6faf8a827b1f3e808202277783fea9f527d114" +checksum = "46d13df7c37807965d82930c0e4b04a659efcb6cca237373b206043db5398ecf" dependencies = [ "either", "fnv", @@ -4514,7 +4439,7 @@ dependencies = [ "libp2p-core", "log", "pin-project", - "rand 0.7.3", + "rand 0.8.5", "smallvec", "thiserror", "void", @@ -4522,48 +4447,36 @@ dependencies = [ [[package]] name = "libp2p-swarm-derive" -version = "0.28.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f54a64b6957249e0ce782f8abf41d97f69330d02bf229f0672d864f0650cc76" +checksum = "a0eddc4497a8b5a506013c40e8189864f9c3a00db2b25671f428ae9007f3ba32" dependencies = [ + "heck", "quote", "syn", ] [[package]] name = "libp2p-tcp" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a6771dc19aa3c65d6af9a8c65222bfc8fcd446630ddca487acd161fa6096f3b" +checksum = "9839d96761491c6d3e238e70554b856956fca0ab60feb9de2cd08eed4473fa92" dependencies = [ - "async-io", "futures 0.3.25", "futures-timer", "if-watch", - "ipnet", "libc", "libp2p-core", "log", "socket2", -] - -[[package]] -name = "libp2p-uds" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d125e3e5f0d58f3c6ac21815b20cf4b6a88b8db9dc26368ea821838f4161fd4d" -dependencies = [ - "async-std", - "futures 0.3.25", - "libp2p-core", - "log", + "tokio", ] [[package]] name = "libp2p-wasm-ext" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec894790eec3c1608f8d1a8a0bdf0dbeb79ed4de2dce964222011c2896dfa05a" +checksum = "a17b5b8e7a73e379e47b1b77f8a82c4721e97eca01abcd18e9cd91a23ca6ce97" dependencies = [ "futures 0.3.25", "js-sys", @@ -4575,9 +4488,9 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.36.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9808e57e81be76ff841c106b4c5974fb4d41a233a7bdd2afbf1687ac6def3818" +checksum = "3758ae6f89b2531a24b6d9f5776bda6a626b60a57600d7185d43dfa75ca5ecc4" dependencies = [ "either", "futures 0.3.25", @@ -4594,12 +4507,13 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.38.0" +version = "0.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6dea686217a06072033dc025631932810e2f6ad784e4fafa42e27d311c7a81c" +checksum = "0d6874d66543c4f7e26e3b8ca9a6bead351563a13ab4fafd43c7927f7c0d6c12" dependencies = [ "futures 0.3.25", "libp2p-core", + "log", "parking_lot 0.12.1", "thiserror", "yamux", @@ -4607,9 +4521,9 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "0.6.1+6.28.2" +version = "0.8.0+7.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc587013734dadb7cf23468e531aa120788b87243648be42e2d3a072186291" +checksum = "611804e4666a25136fcc5f8cf425ab4d26c7f74ea245ffe92ea23b85b6420b5d" dependencies = [ "bindgen", "bzip2-sys", @@ -4681,9 +4595,9 @@ dependencies = [ [[package]] name = "link-cplusplus" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" dependencies = [ "cc", ] @@ -4719,6 +4633,12 @@ version = "0.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + [[package]] name = "lock_api" version = "0.4.9" @@ -4735,7 +4655,7 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "value-bag", ] @@ -4749,15 +4669,6 @@ dependencies = [ "log", ] -[[package]] -name = "lru" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" -dependencies = [ - "hashbrown", -] - [[package]] name = "lru" version = "0.8.1" @@ -4843,18 +4754,18 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memfd" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "480b5a5de855d11ff13195950bdc8b98b5e942ef47afc447f6615cdcc4e15d80" +checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" dependencies = [ - "rustix", + "rustix 0.36.5", ] [[package]] name = "memmap2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498" +checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" dependencies = [ "libc", ] @@ -4869,23 +4780,22 @@ dependencies = [ ] [[package]] -name = "memory-db" -version = "0.29.0" +name = "memoffset" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6566c70c1016f525ced45d7b7f97730a2bafb037c788211d0c186ef5b2189f0a" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" dependencies = [ - "hash-db", - "hashbrown", - "parity-util-mem", + "autocfg", ] [[package]] -name = "memory-lru" -version = "0.1.1" +name = "memory-db" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce95ae042940bad7e312857b929ee3d11b8f799a80cb7b9c7ec5125516906395" +checksum = "5e0c7cba9ce19ac7ffd2053ac9f49843bbd3f4318feedfd74e85c19d5fb0ba66" dependencies = [ - "lru 0.8.1", + "hash-db", + "hashbrown", ] [[package]] @@ -4925,23 +4835,86 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.5.4" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.36.1", + "windows-sys 0.42.0", +] + +[[package]] +name = "mmr-gadget" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" +dependencies = [ + "futures 0.3.25", + "log", + "parity-scale-codec 3.2.1", + "sc-client-api", + "sc-offchain", + "sp-api", + "sp-beefy", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-io", + "sp-mmr-primitives", + "sp-runtime", +] + +[[package]] +name = "mmr-rpc" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" +dependencies = [ + "anyhow", + "jsonrpsee", + "parity-scale-codec 3.2.1", + "serde", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-mmr-primitives", + "sp-runtime", +] + +[[package]] +name = "mockall" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e4a1c770583dac7ab5e2f6c139153b783a53a1bbee9729613f193e59828326" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "832663583d5fa284ca8810bf7015e46c9fff9622d3cf34bd1eea5003fec06dd0" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -4983,10 +4956,10 @@ dependencies = [ "blake2s_simd", "blake3", "core2", - "digest 0.10.5", + "digest 0.10.6", "multihash-derive", "sha2 0.10.6", - "sha3", + "sha3 0.10.6", "unsigned-varint", ] @@ -5012,9 +4985,9 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "multistream-select" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "363a84be6453a70e63513660f4894ef815daf88e3356bffcda9ca27d810ce83b" +checksum = "c8552ab875c1313b97b8d20cb857b9fd63e2d1d6a0a1b53ce9821e575405f27a" dependencies = [ "bytes", "futures 0.3.25", @@ -5034,7 +5007,7 @@ dependencies = [ "matrixmultiply", "nalgebra-macros", "num-complex", - "num-rational 0.4.1", + "num-rational", "num-traits", "rand 0.8.5", "rand_distr", @@ -5136,21 +5109,15 @@ dependencies = [ [[package]] name = "nix" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ "bitflags", - "cfg-if 1.0.0", + "cfg-if", "libc", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "nohash-hasher" version = "0.2.0" @@ -5168,14 +5135,19 @@ dependencies = [ ] [[package]] -name = "num-bigint" -version = "0.2.6" +name = "normalize-line-endings" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ - "autocfg", - "num-integer", - "num-traits", + "overload", + "winapi", ] [[package]] @@ -5200,9 +5172,9 @@ dependencies = [ [[package]] name = "num-format" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b862ff8df690cf089058c98b183676a7ed0f974cc08b426800093227cbff3b" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ "arrayvec 0.7.2", "itoa", @@ -5218,18 +5190,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-rational" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" -dependencies = [ - "autocfg", - "num-bigint 0.2.6", - "num-integer", - "num-traits", -] - [[package]] name = "num-rational" version = "0.4.1" @@ -5237,7 +5197,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", - "num-bigint 0.4.3", + "num-bigint", "num-integer", "num-traits", ] @@ -5249,26 +5209,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", - "libm", + "libm 0.2.6", ] [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] [[package]] -name = "num_threads" -version = "0.1.6" +name = "num_enum" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" dependencies = [ - "libc", + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -5283,15 +5255,24 @@ dependencies = [ "memchr", ] +[[package]] +name = "object" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "opal-runtime" -version = "0.9.30" +version = "0.9.36" dependencies = [ "app-promotion-rpc", "cumulus-pallet-aura-ext", @@ -5304,6 +5285,7 @@ dependencies = [ "cumulus-primitives-utility", "derivative", "evm-coder", + "fp-evm", "fp-evm-mapping", "fp-rpc", "fp-self-contained", @@ -5318,6 +5300,7 @@ dependencies = [ "impl-trait-for-tuples", "log", "logtest", + "num_enum", "orml-tokens", "orml-traits", "orml-vesting", @@ -5333,6 +5316,7 @@ dependencies = [ "pallet-evm-coder-substrate", "pallet-evm-contract-helpers", "pallet-evm-migration", + "pallet-evm-precompile-simple", "pallet-evm-transaction-payment", "pallet-foreign-assets", "pallet-fungible", @@ -5346,16 +5330,18 @@ dependencies = [ "pallet-structure", "pallet-sudo", "pallet-template-transaction-payment", + "pallet-test-utils", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-treasury", "pallet-unique", - "pallet-unique-scheduler", + "pallet-unique-scheduler-v2", "pallet-xcm", "parachain-info", "parity-scale-codec 3.2.1", "polkadot-parachain", + "precompile-utils-macro", "rmrk-rpc", "scale-info", "serde", @@ -5376,6 +5362,7 @@ dependencies = [ "substrate-wasm-builder", "up-common", "up-data-structs", + "up-pov-estimate-rpc", "up-rpc", "up-sponsorship", "xcm", @@ -5403,8 +5390,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "orchestra" -version = "0.0.1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aab54694ddaa8a9b703724c6ef04272b2d27bc32d2c855aae5cdd1857216b43" dependencies = [ "async-trait", "dyn-clonable", @@ -5419,8 +5407,9 @@ dependencies = [ [[package]] name = "orchestra-proc-macro" -version = "0.0.1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a702b2f6bf592b3eb06c00d80d05afaf7a8eff6b41bb361e397d799acc21b45a" dependencies = [ "expander 0.0.6", "itertools", @@ -5443,7 +5432,7 @@ dependencies = [ [[package]] name = "orml-tokens" version = "0.4.1-dev" -source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=polkadot-v0.9.30#4020ff64cfcad3dcc7f4f090cc9bc7699a78cc9c" +source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=feature/polkadot-v0.9.36#3f70b9adb6c0599db7b8688abb49d0d459634b68" dependencies = [ "frame-support", "frame-system", @@ -5458,7 +5447,7 @@ dependencies = [ [[package]] name = "orml-traits" version = "0.4.1-dev" -source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=polkadot-v0.9.30#4020ff64cfcad3dcc7f4f090cc9bc7699a78cc9c" +source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=feature/polkadot-v0.9.36#3f70b9adb6c0599db7b8688abb49d0d459634b68" dependencies = [ "frame-support", "impl-trait-for-tuples", @@ -5476,7 +5465,7 @@ dependencies = [ [[package]] name = "orml-utilities" version = "0.4.1-dev" -source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=polkadot-v0.9.30#4020ff64cfcad3dcc7f4f090cc9bc7699a78cc9c" +source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=feature/polkadot-v0.9.36#3f70b9adb6c0599db7b8688abb49d0d459634b68" dependencies = [ "frame-support", "parity-scale-codec 3.2.1", @@ -5490,7 +5479,7 @@ dependencies = [ [[package]] name = "orml-vesting" version = "0.4.1-dev" -source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=polkadot-v0.9.30#4020ff64cfcad3dcc7f4f090cc9bc7699a78cc9c" +source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=feature/polkadot-v0.9.36#3f70b9adb6c0599db7b8688abb49d0d459634b68" dependencies = [ "frame-support", "frame-system", @@ -5505,7 +5494,7 @@ dependencies = [ [[package]] name = "orml-xcm-support" version = "0.4.1-dev" -source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=polkadot-v0.9.30#4020ff64cfcad3dcc7f4f090cc9bc7699a78cc9c" +source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=feature/polkadot-v0.9.36#3f70b9adb6c0599db7b8688abb49d0d459634b68" dependencies = [ "frame-support", "orml-traits", @@ -5519,7 +5508,7 @@ dependencies = [ [[package]] name = "orml-xtokens" version = "0.4.1-dev" -source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=polkadot-v0.9.30#4020ff64cfcad3dcc7f4f090cc9bc7699a78cc9c" +source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=feature/polkadot-v0.9.36#3f70b9adb6c0599db7b8688abb49d0d459634b68" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -5538,23 +5527,30 @@ dependencies = [ ] [[package]] -name = "os_str_bytes" -version = "6.3.0" +name = "os_str_bytes" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" + +[[package]] +name = "overload" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] -name = "owning_ref" -version = "0.4.1" +name = "packed_simd_2" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" +checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" dependencies = [ - "stable_deref_trait", + "cfg-if", + "libm 0.1.4", ] [[package]] name = "pallet-app-promotion" -version = "0.1.1" +version = "0.1.3" dependencies = [ "frame-benchmarking", "frame-support", @@ -5581,7 +5577,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "frame-system", @@ -5597,7 +5593,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "frame-system", @@ -5613,7 +5609,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "frame-system", @@ -5628,7 +5624,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -5652,7 +5648,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5672,7 +5668,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -5687,7 +5683,7 @@ dependencies = [ [[package]] name = "pallet-base-fee" version = "1.0.0" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ "fp-evm", "frame-support", @@ -5702,15 +5698,15 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "beefy-primitives", "frame-support", "frame-system", "pallet-session", "parity-scale-codec 3.2.1", "scale-info", "serde", + "sp-beefy", "sp-runtime", "sp-std", ] @@ -5718,11 +5714,10 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "beefy-merkle-tree", - "beefy-primitives", "frame-support", "frame-system", "log", @@ -5732,6 +5727,7 @@ dependencies = [ "parity-scale-codec 3.2.1", "scale-info", "serde", + "sp-beefy", "sp-core", "sp-io", "sp-runtime", @@ -5741,7 +5737,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -5759,7 +5755,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -5778,7 +5774,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -5794,9 +5790,9 @@ dependencies = [ [[package]] name = "pallet-common" -version = "0.1.8" +version = "0.1.12" dependencies = [ - "ethereum", + "ethereum 0.14.0", "evm-coder", "fp-evm-mapping", "frame-benchmarking", @@ -5811,6 +5807,7 @@ dependencies = [ "sp-runtime", "sp-std", "up-data-structs", + "up-pov-estimate-rpc", ] [[package]] @@ -5830,17 +5827,36 @@ dependencies = [ "xcm", ] +[[package]] +name = "pallet-conviction-voting" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" +dependencies = [ + "assert_matches", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec 3.2.1", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "parity-scale-codec 3.2.1", "scale-info", "serde", + "sp-core", "sp-io", "sp-runtime", "sp-std", @@ -5849,7 +5865,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5873,7 +5889,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5886,7 +5902,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -5904,12 +5920,13 @@ dependencies = [ [[package]] name = "pallet-ethereum" version = "4.0.0-dev" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ - "ethereum", - "ethereum-types", + "ethereum 0.14.0", + "ethereum-types 0.14.1", "evm", "fp-consensus", + "fp-ethereum", "fp-evm", "fp-evm-mapping", "fp-rpc", @@ -5917,14 +5934,12 @@ dependencies = [ "fp-storage", "frame-support", "frame-system", - "log", "pallet-evm", "pallet-timestamp", "parity-scale-codec 3.2.1", "rlp", "scale-info", "serde", - "sha3", "sp-io", "sp-runtime", "sp-std", @@ -5933,8 +5948,9 @@ dependencies = [ [[package]] name = "pallet-evm" version = "6.0.0-dev" -source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" dependencies = [ + "environmental", "evm", "fp-evm", "fp-evm-mapping", @@ -5946,11 +5962,10 @@ dependencies = [ "log", "pallet-timestamp", "parity-scale-codec 3.2.1", - "primitive-types", + "primitive-types 0.12.1", "rlp", "scale-info", "serde", - "sha3", "sp-core", "sp-io", "sp-runtime", @@ -5961,7 +5976,7 @@ dependencies = [ name = "pallet-evm-coder-substrate" version = "0.1.3" dependencies = [ - "ethereum", + "ethereum 0.14.0", "evm-coder", "frame-benchmarking", "frame-support", @@ -5979,7 +5994,7 @@ dependencies = [ name = "pallet-evm-contract-helpers" version = "0.3.0" dependencies = [ - "ethereum", + "ethereum 0.14.0", "evm-coder", "fp-evm-mapping", "frame-support", @@ -6002,7 +6017,7 @@ dependencies = [ name = "pallet-evm-migration" version = "0.1.1" dependencies = [ - "ethereum", + "ethereum 0.14.0", "fp-evm", "frame-benchmarking", "frame-support", @@ -6016,6 +6031,16 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-evm-precompile-simple" +version = "2.0.0-dev" +source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.36#cf1894629c7df1c4dafe58aa773627a3d940da14" +dependencies = [ + "fp-evm", + "ripemd", + "sp-io", +] + [[package]] name = "pallet-evm-transaction-payment" version = "0.1.1" @@ -6038,16 +6063,13 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-election-provider-support", "frame-support", "frame-system", "log", - "pallet-balances", - "pallet-staking", - "pallet-timestamp", "parity-scale-codec 3.2.1", "scale-info", "sp-io", @@ -6086,9 +6108,9 @@ dependencies = [ [[package]] name = "pallet-fungible" -version = "0.1.5" +version = "0.1.9" dependencies = [ - "ethereum", + "ethereum 0.14.0", "evm-coder", "frame-benchmarking", "frame-support", @@ -6105,25 +6127,10 @@ dependencies = [ "up-data-structs", ] -[[package]] -name = "pallet-gilt" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "parity-scale-codec 3.2.1", - "scale-info", - "sp-arithmetic", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -6146,7 +6153,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6162,7 +6169,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -6182,7 +6189,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -6230,7 +6237,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -6247,9 +6254,8 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "ckb-merkle-mountain-range", "frame-benchmarking", "frame-support", "frame-system", @@ -6263,31 +6269,33 @@ dependencies = [ ] [[package]] -name = "pallet-mmr-rpc" -version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +name = "pallet-multisig" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "jsonrpsee", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", "parity-scale-codec 3.2.1", - "serde", - "sp-api", - "sp-blockchain", - "sp-core", - "sp-mmr-primitives", + "scale-info", + "sp-io", "sp-runtime", + "sp-std", ] [[package]] -name = "pallet-multisig" +name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "parity-scale-codec 3.2.1", "scale-info", - "sp-io", + "sp-arithmetic", + "sp-core", "sp-runtime", "sp-std", ] @@ -6295,7 +6303,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "frame-system", @@ -6312,7 +6320,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6332,7 +6340,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", "sp-api", @@ -6341,9 +6349,9 @@ dependencies = [ [[package]] name = "pallet-nonfungible" -version = "0.1.5" +version = "0.1.12" dependencies = [ - "ethereum", + "ethereum 0.14.0", "evm-coder", "frame-benchmarking", "frame-support", @@ -6364,7 +6372,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "frame-system", @@ -6381,7 +6389,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6404,11 +6412,12 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "parity-scale-codec 3.2.1", "scale-info", "sp-core", @@ -6420,7 +6429,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -6435,7 +6444,7 @@ dependencies = [ [[package]] name = "pallet-randomness-collective-flip" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "frame-system", @@ -6446,16 +6455,53 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-ranked-collective" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec 3.2.1", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec 3.2.1", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-referenda" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ + "assert_matches", "frame-benchmarking", "frame-support", "frame-system", + "log", "parity-scale-codec 3.2.1", "scale-info", + "serde", + "sp-arithmetic", "sp-io", "sp-runtime", "sp-std", @@ -6463,10 +6509,10 @@ dependencies = [ [[package]] name = "pallet-refungible" -version = "0.2.4" +version = "0.2.11" dependencies = [ "derivative", - "ethereum", + "ethereum 0.14.0", "evm-coder", "frame-benchmarking", "frame-support", @@ -6528,7 +6574,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -6539,12 +6585,13 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", + "sp-weights", ] [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "frame-system", @@ -6565,7 +6612,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -6581,7 +6628,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "frame-system", @@ -6595,7 +6642,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6618,7 +6665,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6629,12 +6676,29 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "log", "sp-arithmetic", ] +[[package]] +name = "pallet-state-trie-migration" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec 3.2.1", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-structure" version = "0.1.2" @@ -6653,7 +6717,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "frame-system", @@ -6667,7 +6731,7 @@ dependencies = [ [[package]] name = "pallet-template-transaction-payment" version = "3.0.0" -source = "git+https://github.com/uniquenetwork/pallet-sponsoring?branch=polkadot-v0.9.30#39dd82158d6caa9d89105441bf2f7111a6e686e5" +source = "git+https://github.com/uniquenetwork/pallet-sponsoring?branch=polkadot-v0.9.36#55943b982e9b0b80465885f31f76db3dba91dac4" dependencies = [ "frame-benchmarking", "frame-support", @@ -6684,10 +6748,22 @@ dependencies = [ "up-sponsorship", ] +[[package]] +name = "pallet-test-utils" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "pallet-unique-scheduler-v2", + "parity-scale-codec 3.2.1", + "scale-info", + "sp-std", +] + [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -6705,7 +6781,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -6724,7 +6800,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-support", "frame-system", @@ -6740,7 +6816,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -6750,23 +6826,25 @@ dependencies = [ "sp-core", "sp-rpc", "sp-runtime", + "sp-weights", ] [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "pallet-transaction-payment", "parity-scale-codec 3.2.1", "sp-api", "sp-runtime", + "sp-weights", ] [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -6782,9 +6860,9 @@ dependencies = [ [[package]] name = "pallet-unique" -version = "0.2.0" +version = "0.2.1" dependencies = [ - "ethereum", + "ethereum 0.12.0", "evm-coder", "frame-benchmarking", "frame-support", @@ -6805,28 +6883,27 @@ dependencies = [ ] [[package]] -name = "pallet-unique-scheduler" -version = "0.1.1" +name = "pallet-unique-scheduler-v2" +version = "0.1.0" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "log", + "pallet-preimage", "parity-scale-codec 3.2.1", "scale-info", - "serde", "sp-core", "sp-io", "sp-runtime", "sp-std", "substrate-test-utils", - "up-sponsorship", ] [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -6842,7 +6919,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-benchmarking", "frame-support", @@ -6854,10 +6931,25 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-whitelist" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec 3.2.1", + "scale-info", + "sp-api", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-xcm" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "frame-support", "frame-system", @@ -6874,8 +6966,8 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "frame-benchmarking", "frame-support", @@ -6892,23 +6984,22 @@ dependencies = [ [[package]] name = "parachain-info" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.30#7b1fc0ed107fe42bb7e6a5dfefb586f4c3ae4328" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.36#afe528af891f464b318293f183f6d3eefbc979b0" dependencies = [ "cumulus-primitives-core", "frame-support", "frame-system", "parity-scale-codec 3.2.1", "scale-info", - "serde", ] [[package]] name = "parity-db" -version = "0.3.17" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8fdb726a43661fa54b43e7114e6b88b2289cae388eb3ad766d9d1754d83fce" +checksum = "3a7511a0bec4a336b5929999d02b560d2439c993cccf98c26481484e811adc43" dependencies = [ - "blake2-rfc", + "blake2", "crc32fast", "fs2", "hex", @@ -6980,44 +7071,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" -[[package]] -name = "parity-util-mem" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c32561d248d352148124f036cac253a644685a21dc9fea383eb4907d7bd35a8f" -dependencies = [ - "cfg-if 1.0.0", - "ethereum-types", - "hashbrown", - "impl-trait-for-tuples", - "lru 0.7.8", - "parity-util-mem-derive", - "parking_lot 0.12.1", - "primitive-types", - "smallvec", - "winapi", -] - -[[package]] -name = "parity-util-mem-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" -dependencies = [ - "proc-macro2", - "syn", - "synstructure", -] - -[[package]] -name = "parity-wasm" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ad52817c4d343339b3bc2e26861bd21478eda0b7509acf83505727000512ac" -dependencies = [ - "byteorder", -] - [[package]] name = "parity-wasm" version = "0.45.0" @@ -7038,7 +7091,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core 0.8.5", + "parking_lot_core 0.8.6", ] [[package]] @@ -7048,16 +7101,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.4", + "parking_lot_core 0.9.5", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "instant", "libc", "redox_syscall", @@ -7067,11 +7120,11 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "smallvec", @@ -7080,9 +7133,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" +checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" [[package]] name = "pbkdf2" @@ -7116,9 +7169,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.4.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc7bc69c062e492337d74d59b120c274fd3d261b6bf6d3207d499b4b379c41a" +checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0" dependencies = [ "thiserror", "ucd-trie", @@ -7126,9 +7179,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.4.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b75706b9642ebcb34dab3bc7750f811609a0eb1dd8b88c2d15bf628c1c65b2" +checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344" dependencies = [ "pest", "pest_generator", @@ -7136,9 +7189,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.4.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f9272122f5979a6511a749af9db9bfc810393f63119970d7085fed1c4ea0db" +checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c" dependencies = [ "pest", "pest_meta", @@ -7149,9 +7202,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.4.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8717927f9b79515e565a64fe46c38b8cd0427e64c40680b14a7365ab09ac8d" +checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20" dependencies = [ "once_cell", "pest", @@ -7208,20 +7261,19 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkcs8" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ "der", "spki", - "zeroize", ] [[package]] name = "pkg-config" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "platforms" @@ -7229,10 +7281,16 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8d0eef3571242013a0d5dc84861c3ae4a652e56e12adf8bdc26ff5f8cb34c94" +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + [[package]] name = "polkadot-approval-distribution" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "futures 0.3.25", "polkadot-node-network-protocol", @@ -7246,8 +7304,8 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "futures 0.3.25", "polkadot-node-network-protocol", @@ -7260,13 +7318,13 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "derive_more", "fatality", "futures 0.3.25", - "lru 0.7.8", + "lru", "parity-scale-codec 3.2.1", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -7283,12 +7341,12 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "fatality", "futures 0.3.25", - "lru 0.7.8", + "lru", "parity-scale-codec 3.2.1", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -7304,8 +7362,8 @@ dependencies = [ [[package]] name = "polkadot-cli" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "clap", "frame-benchmarking-cli", @@ -7317,12 +7375,13 @@ dependencies = [ "polkadot-performance-test", "polkadot-service", "sc-cli", + "sc-executor", "sc-service", "sc-sysinfo", "sc-tracing", "sp-core", + "sp-io", "sp-keyring", - "sp-trie", "substrate-build-script-utils", "thiserror", "try-runtime-cli", @@ -7330,14 +7389,15 @@ dependencies = [ [[package]] name = "polkadot-client" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ - "beefy-primitives", + "async-trait", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", "frame-system-rpc-runtime-api", + "futures 0.3.25", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "polkadot-core-primitives", @@ -7351,6 +7411,7 @@ dependencies = [ "sc-service", "sp-api", "sp-authority-discovery", + "sp-beefy", "sp-block-builder", "sp-blockchain", "sp-consensus", @@ -7370,10 +7431,11 @@ dependencies = [ [[package]] name = "polkadot-collator-protocol" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "always-assert", + "bitvec 1.0.1", "fatality", "futures 0.3.25", "futures-timer", @@ -7391,11 +7453,10 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "parity-scale-codec 3.2.1", - "parity-util-mem", "scale-info", "sp-core", "sp-runtime", @@ -7404,13 +7465,15 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "derive_more", "fatality", "futures 0.3.25", - "lru 0.7.8", + "futures-timer", + "indexmap", + "lru", "parity-scale-codec 3.2.1", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -7427,8 +7490,8 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "parity-scale-codec 3.2.1", "polkadot-node-primitives", @@ -7441,8 +7504,8 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "futures 0.3.25", "futures-timer", @@ -7461,8 +7524,8 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "always-assert", "async-trait", @@ -7485,8 +7548,8 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "futures 0.3.25", "parity-scale-codec 3.2.1", @@ -7503,15 +7566,15 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "bitvec 1.0.1", "derive_more", "futures 0.3.25", "futures-timer", "kvdb", - "lru 0.7.8", + "lru", "merlin", "parity-scale-codec 3.2.1", "polkadot-node-jaeger", @@ -7532,8 +7595,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "bitvec 1.0.1", "futures 0.3.25", @@ -7552,8 +7615,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "bitvec 1.0.1", "fatality", @@ -7571,8 +7634,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "futures 0.3.25", "polkadot-node-subsystem", @@ -7586,11 +7649,12 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "async-trait", "futures 0.3.25", + "futures-timer", "parity-scale-codec 3.2.1", "polkadot-node-core-pvf", "polkadot-node-primitives", @@ -7604,8 +7668,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "futures 0.3.25", "polkadot-node-subsystem", @@ -7619,8 +7683,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "futures 0.3.25", "futures-timer", @@ -7636,13 +7700,13 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "fatality", "futures 0.3.25", "kvdb", - "lru 0.7.8", + "lru", "parity-scale-codec 3.2.1", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7655,13 +7719,14 @@ dependencies = [ [[package]] name = "polkadot-node-core-parachains-inherent" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "async-trait", "futures 0.3.25", "futures-timer", "polkadot-node-subsystem", + "polkadot-overseer", "polkadot-primitives", "sp-blockchain", "sp-inherents", @@ -7672,8 +7737,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "bitvec 1.0.1", "fatality", @@ -7690,13 +7755,14 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "always-assert", "assert_matches", "async-process", "async-std", + "cpu-time", "futures 0.3.25", "futures-timer", "parity-scale-codec 3.2.1", @@ -7722,8 +7788,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf-checker" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "futures 0.3.25", "polkadot-node-primitives", @@ -7738,12 +7804,11 @@ dependencies = [ [[package]] name = "polkadot-node-core-runtime-api" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "futures 0.3.25", - "memory-lru", - "parity-util-mem", + "lru", "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", @@ -7754,10 +7819,9 @@ dependencies = [ [[package]] name = "polkadot-node-jaeger" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ - "async-std", "lazy_static", "log", "mick-jaeger", @@ -7768,12 +7832,13 @@ dependencies = [ "sc-network", "sp-core", "thiserror", + "tokio", ] [[package]] name = "polkadot-node-metrics" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "bs58", "futures 0.3.25", @@ -7791,8 +7856,8 @@ dependencies = [ [[package]] name = "polkadot-node-network-protocol" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "async-trait", "derive_more", @@ -7814,8 +7879,8 @@ dependencies = [ [[package]] name = "polkadot-node-primitives" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "bounded-vec", "futures 0.3.25", @@ -7836,8 +7901,8 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -7846,8 +7911,8 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "async-trait", "derive_more", @@ -7869,8 +7934,8 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "async-trait", "derive_more", @@ -7878,10 +7943,9 @@ dependencies = [ "futures 0.3.25", "itertools", "kvdb", - "lru 0.7.8", + "lru", "parity-db", "parity-scale-codec 3.2.1", - "parity-util-mem", "parking_lot 0.11.2", "pin-project", "polkadot-node-jaeger", @@ -7902,15 +7966,14 @@ dependencies = [ [[package]] name = "polkadot-overseer" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "async-trait", "futures 0.3.25", "futures-timer", - "lru 0.7.8", + "lru", "orchestra", - "parity-util-mem", "parking_lot 0.12.1", "polkadot-node-metrics", "polkadot-node-network-protocol", @@ -7920,18 +7983,18 @@ dependencies = [ "sc-client-api", "sp-api", "sp-core", + "tikv-jemalloc-ctl", "tracing-gum", ] [[package]] name = "polkadot-parachain" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "derive_more", "frame-support", "parity-scale-codec 3.2.1", - "parity-util-mem", "polkadot-core-primitives", "scale-info", "serde", @@ -7942,8 +8005,8 @@ dependencies = [ [[package]] name = "polkadot-performance-test" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "env_logger", "kusama-runtime", @@ -7957,14 +8020,12 @@ dependencies = [ [[package]] name = "polkadot-primitives" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "bitvec 1.0.1", - "frame-system", "hex-literal", "parity-scale-codec 3.2.1", - "parity-util-mem", "polkadot-core-primitives", "polkadot-parachain", "scale-info", @@ -7981,19 +8042,17 @@ dependencies = [ "sp-runtime", "sp-staking", "sp-std", - "sp-trie", - "sp-version", ] [[package]] name = "polkadot-rpc" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "beefy-gadget", "beefy-gadget-rpc", "jsonrpsee", - "pallet-mmr-rpc", + "mmr-rpc", "pallet-transaction-payment-rpc", "polkadot-primitives", "sc-chain-spec", @@ -8019,10 +8078,9 @@ dependencies = [ [[package]] name = "polkadot-runtime" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ - "beefy-primitives", "bitvec 1.0.1", "frame-benchmarking", "frame-election-provider-support", @@ -8085,6 +8143,7 @@ dependencies = [ "smallvec", "sp-api", "sp-authority-discovery", + "sp-beefy", "sp-block-builder", "sp-consensus-babe", "sp-core", @@ -8108,10 +8167,9 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ - "beefy-primitives", "bitvec 1.0.1", "frame-benchmarking", "frame-election-provider-support", @@ -8128,6 +8186,7 @@ dependencies = [ "pallet-election-provider-multi-phase", "pallet-session", "pallet-staking", + "pallet-staking-reward-fn", "pallet-timestamp", "pallet-transaction-payment", "pallet-treasury", @@ -8141,6 +8200,7 @@ dependencies = [ "serde_derive", "slot-range-helper", "sp-api", + "sp-beefy", "sp-core", "sp-inherents", "sp-io", @@ -8155,20 +8215,22 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "frame-support", "polkadot-primitives", "polkadot-runtime-common", "smallvec", + "sp-core", "sp-runtime", + "sp-weights", ] [[package]] name = "polkadot-runtime-metrics" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "bs58", "parity-scale-codec 3.2.1", @@ -8179,8 +8241,8 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "bitflags", "bitvec 1.0.1", @@ -8222,12 +8284,11 @@ dependencies = [ [[package]] name = "polkadot-service" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "async-trait", "beefy-gadget", - "beefy-primitives", "frame-support", "frame-system-rpc-runtime-api", "futures 0.3.25", @@ -8235,7 +8296,8 @@ dependencies = [ "kusama-runtime", "kvdb", "kvdb-rocksdb", - "lru 0.7.8", + "lru", + "mmr-gadget", "pallet-babe", "pallet-im-online", "pallet-staking", @@ -8301,6 +8363,7 @@ dependencies = [ "serde_json", "sp-api", "sp-authority-discovery", + "sp-beefy", "sp-block-builder", "sp-blockchain", "sp-consensus", @@ -8310,6 +8373,7 @@ dependencies = [ "sp-inherents", "sp-io", "sp-keystore", + "sp-mmr-primitives", "sp-offchain", "sp-runtime", "sp-session", @@ -8326,8 +8390,8 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "arrayvec 0.5.2", "fatality", @@ -8347,8 +8411,8 @@ dependencies = [ [[package]] name = "polkadot-statement-table" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "parity-scale-codec 3.2.1", "polkadot-primitives", @@ -8357,10 +8421,9 @@ dependencies = [ [[package]] name = "polkadot-test-runtime" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ - "beefy-primitives", "bitvec 1.0.1", "frame-election-provider-support", "frame-executive", @@ -8396,6 +8459,7 @@ dependencies = [ "smallvec", "sp-api", "sp-authority-discovery", + "sp-beefy", "sp-block-builder", "sp-consensus-babe", "sp-core", @@ -8418,8 +8482,8 @@ dependencies = [ [[package]] name = "polkadot-test-service" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "frame-benchmarking", "frame-system", @@ -8472,16 +8536,16 @@ dependencies = [ [[package]] name = "polling" -version = "2.3.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899b00b9c8ab553c743b3e11e87c5c7d423b2a2de229ba95b24a756344748011" +checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "libc", "log", "wepoll-ffi", - "winapi", + "windows-sys 0.42.0", ] [[package]] @@ -8496,22 +8560,73 @@ dependencies = [ ] [[package]] -name = "polyval" -version = "0.5.3" +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug 0.3.0", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precompile-utils-macro" +version = "0.1.0" +dependencies = [ + "num_enum", + "proc-macro2", + "quote", + "sha3 0.8.2", + "syn", +] + +[[package]] +name = "predicates" +version = "2.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f54fc5dc63ed3bbf19494623db4f3af16842c0d975818e469022d09e53f0aa05" +dependencies = [ + "difflib", + "float-cmp", + "itertools", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +checksum = "72f883590242d3c6fc5bf50299011695fa6590c2c70eac95ee1bdb9a733ad1a2" + +[[package]] +name = "predicates-tree" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54ff541861505aabf6ea722d2131ee980b8276e10a1297b94e896dd8b621850d" dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "opaque-debug 0.3.0", - "universal-hash", + "predicates-core", + "termtree", ] [[package]] -name = "ppv-lite86" -version = "0.2.16" +name = "prettyplease" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "2c8992a85d8e93a28bdf76137db888d3874e3b230dee5ed8bebac4c9f7617773" +dependencies = [ + "proc-macro2", + "syn", +] [[package]] name = "primitive-types" @@ -8519,7 +8634,20 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" dependencies = [ - "fixed-hash", + "fixed-hash 0.7.0", + "impl-codec", + "impl-rlp", + "scale-info", + "uint", +] + +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash 0.8.0", "impl-codec", "impl-rlp", "impl-serde", @@ -8530,7 +8658,8 @@ dependencies = [ [[package]] name = "prioritized-metered-channel" version = "0.2.0" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382698e48a268c832d0b181ed438374a6bb708a82a8ca273bb0f61c74cf209c4" dependencies = [ "coarsetime", "crossbeam-queue", @@ -8579,9 +8708,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] @@ -8592,7 +8721,7 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fnv", "lazy_static", "memchr", @@ -8602,21 +8731,21 @@ dependencies = [ [[package]] name = "prometheus-client" -version = "0.16.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1abe0255c04d15f571427a2d1e00099016506cf3297b53853acd2b7eb87825" +checksum = "83cd1b99916654a69008fd66b4f9397fbe08e6e51dfe23d4417acf5d3b8cb87c" dependencies = [ "dtoa", "itoa", - "owning_ref", + "parking_lot 0.12.1", "prometheus-client-derive-text-encode", ] [[package]] name = "prometheus-client-derive-text-encode" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8e12d01b9d66ad9eb4529c57666b6263fc1993cb30261d83ead658fdd932652" +checksum = "66a455fbcb954c1a7decf3c586e860fd7889cddf4b8e164be736dbac95a953cd" dependencies = [ "proc-macro2", "quote", @@ -8625,51 +8754,19 @@ dependencies = [ [[package]] name = "prost" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71adf41db68aa0daaefc69bb30bcd68ded9b9abaad5d1fbb6304c4fb390e083e" -dependencies = [ - "bytes", - "prost-derive 0.10.1", -] - -[[package]] -name = "prost" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "399c3c31cdec40583bb68f0b18403400d01ec4289c383aa047560439952c4dd7" -dependencies = [ - "bytes", - "prost-derive 0.11.0", -] - -[[package]] -name = "prost-build" -version = "0.10.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae5a4388762d5815a9fc0dea33c56b021cdc8dde0c55e0c9ca57197254b0cab" +checksum = "c01db6702aa05baa3f57dec92b8eeeeb4cb19e894e73996b32a4093289e54592" dependencies = [ "bytes", - "cfg-if 1.0.0", - "cmake", - "heck", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prost 0.10.4", - "prost-types 0.10.1", - "regex", - "tempfile", - "which", + "prost-derive", ] [[package]] name = "prost-build" -version = "0.11.1" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f835c582e6bd972ba8347313300219fed5bfa52caf175298d860b61ff6069bb" +checksum = "cb5320c680de74ba083512704acb90fe00f28f79207286a848e730c45dd73ed6" dependencies = [ "bytes", "heck", @@ -8678,44 +8775,33 @@ dependencies = [ "log", "multimap", "petgraph", - "prost 0.11.0", - "prost-types 0.11.1", + "prettyplease", + "prost", + "prost-types", "regex", + "syn", "tempfile", "which", ] [[package]] name = "prost-codec" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00af1e92c33b4813cc79fda3f2dbf56af5169709be0202df730e9ebc3e4cd007" +checksum = "011ae9ff8359df7915f97302d591cdd9e0e27fbd5a4ddc5bd13b71079bb20987" dependencies = [ "asynchronous-codec", "bytes", - "prost 0.10.4", + "prost", "thiserror", "unsigned-varint", ] [[package]] name = "prost-derive" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "prost-derive" -version = "0.11.0" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7345d5f0e08c0536d7ac7229952590239e77abf0a0100a1b1d890add6ea96364" +checksum = "c8842bad1a5419bca14eac663ba798f6bc19c413c2fdceb5f3ba3b0932d96720" dependencies = [ "anyhow", "itertools", @@ -8726,22 +8812,12 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" -dependencies = [ - "bytes", - "prost 0.10.4", -] - -[[package]] -name = "prost-types" -version = "0.11.1" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dfaa718ad76a44b3415e6c4d53b17c8f99160dcb3a99b10470fce8ad43f6e3e" +checksum = "017f79637768cde62820bc2d4fe0e45daaa027755c323ad077767c6c5f173091" dependencies = [ "bytes", - "prost 0.11.0", + "prost", ] [[package]] @@ -8755,7 +8831,7 @@ dependencies = [ [[package]] name = "quartz-runtime" -version = "0.9.30" +version = "0.9.36" dependencies = [ "app-promotion-rpc", "cumulus-pallet-aura-ext", @@ -8768,6 +8844,7 @@ dependencies = [ "cumulus-primitives-utility", "derivative", "evm-coder", + "fp-evm", "fp-evm-mapping", "fp-rpc", "fp-self-contained", @@ -8782,6 +8859,7 @@ dependencies = [ "impl-trait-for-tuples", "log", "logtest", + "num_enum", "orml-tokens", "orml-traits", "orml-vesting", @@ -8797,6 +8875,7 @@ dependencies = [ "pallet-evm-coder-substrate", "pallet-evm-contract-helpers", "pallet-evm-migration", + "pallet-evm-precompile-simple", "pallet-evm-transaction-payment", "pallet-foreign-assets", "pallet-fungible", @@ -8815,11 +8894,11 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pallet-treasury", "pallet-unique", - "pallet-unique-scheduler", "pallet-xcm", "parachain-info", "parity-scale-codec 3.2.1", "polkadot-parachain", + "precompile-utils-macro", "rmrk-rpc", "scale-info", "serde", @@ -8840,6 +8919,7 @@ dependencies = [ "substrate-wasm-builder", "up-common", "up-data-structs", + "up-pov-estimate-rpc", "up-rpc", "up-sponsorship", "xcm", @@ -8866,9 +8946,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -8993,21 +9073,19 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.5.3" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" dependencies = [ - "autocfg", - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.9.3" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -9050,18 +9128,18 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12a733f1746c929b4913fe48f8697fcf9c55e3304ba251a79ffb41adfeaf49c2" +checksum = "8c78fb8c9293bcd48ef6fce7b4ca950ceaf21210de6e105a883ee280c0f7b9ed" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5887de4a01acafd221861463be6113e6e87275e79804e56779f4cdc131c60368" +checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f" dependencies = [ "proc-macro2", "quote", @@ -9082,9 +9160,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" dependencies = [ "aho-corasick", "memchr", @@ -9102,26 +9180,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.27" +version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" - -[[package]] -name = "remote-externalities" -version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" -dependencies = [ - "env_logger", - "jsonrpsee", - "log", - "parity-scale-codec 3.2.1", - "serde", - "serde_json", - "sp-core", - "sp-io", - "sp-runtime", - "sp-version", -] +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "remove_dir_all" @@ -9144,12 +9205,12 @@ dependencies = [ [[package]] name = "rfc6979" -version = "0.1.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ "crypto-bigint", - "hmac 0.11.0", + "hmac 0.12.1", "zeroize", ] @@ -9168,6 +9229,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.6", +] + [[package]] name = "rlp" version = "0.5.2" @@ -9175,6 +9245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ "bytes", + "rlp-derive", "rustc-hex", ] @@ -9213,9 +9284,9 @@ dependencies = [ [[package]] name = "rocksdb" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "620f4129485ff1a7128d184bc687470c21c7951b64779ebc9cfdad3dcd920290" +checksum = "7e9562ea1d70c0cc63a34a22d977753b50cca91cc6b6527750463bd5dd8697bc" dependencies = [ "libc", "librocksdb-sys", @@ -9223,11 +9294,10 @@ dependencies = [ [[package]] name = "rococo-runtime" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "beefy-merkle-tree", - "beefy-primitives", "frame-benchmarking", "frame-executive", "frame-support", @@ -9247,7 +9317,6 @@ dependencies = [ "pallet-collective", "pallet-democracy", "pallet-elections-phragmen", - "pallet-gilt", "pallet-grandpa", "pallet-identity", "pallet-im-online", @@ -9255,6 +9324,7 @@ dependencies = [ "pallet-membership", "pallet-mmr", "pallet-multisig", + "pallet-nis", "pallet-offences", "pallet-preimage", "pallet-proxy", @@ -9263,6 +9333,7 @@ dependencies = [ "pallet-session", "pallet-society", "pallet-staking", + "pallet-state-trie-migration", "pallet-sudo", "pallet-timestamp", "pallet-tips", @@ -9285,6 +9356,7 @@ dependencies = [ "smallvec", "sp-api", "sp-authority-discovery", + "sp-beefy", "sp-block-builder", "sp-consensus-babe", "sp-core", @@ -9307,23 +9379,26 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "frame-support", "polkadot-primitives", "polkadot-runtime-common", "smallvec", + "sp-core", "sp-runtime", + "sp-weights", ] [[package]] name = "rpassword" -version = "7.1.0" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20c9f5d2a0c3e2ea729ab3706d22217177770654c3ef5056b68b69d07332d3f5" +checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" dependencies = [ "libc", + "rtoolbox", "winapi", ] @@ -9342,6 +9417,16 @@ dependencies = [ "thiserror", ] +[[package]] +name = "rtoolbox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "rustc-demangle" version = "0.1.21" @@ -9375,21 +9460,35 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.14", + "semver 1.0.16", ] [[package]] name = "rustix" -version = "0.35.11" +version = "0.35.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbb2fda4666def1433b1b05431ab402e42a1084285477222b72d6c564c417cef" +checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" dependencies = [ "bitflags", "errno", - "io-lifetimes", + "io-lifetimes 0.7.5", "libc", - "linux-raw-sys", - "windows-sys 0.36.1", + "linux-raw-sys 0.0.46", + "windows-sys 0.42.0", +] + +[[package]] +name = "rustix" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes 1.0.3", + "libc", + "linux-raw-sys 0.1.4", + "windows-sys 0.42.0", ] [[package]] @@ -9427,9 +9526,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" [[package]] name = "rw-stream-sink" @@ -9444,9 +9543,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] name = "safe-mix" @@ -9457,15 +9556,6 @@ dependencies = [ "rustc_version 0.2.3", ] -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher 0.4.3", -] - [[package]] name = "same-file" version = "1.0.6" @@ -9478,7 +9568,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "log", "sp-core", @@ -9489,7 +9579,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "futures 0.3.25", @@ -9498,8 +9588,8 @@ dependencies = [ "libp2p", "log", "parity-scale-codec 3.2.1", - "prost 0.10.4", - "prost-build 0.10.4", + "prost", + "prost-build", "rand 0.7.3", "sc-client-api", "sc-network-common", @@ -9516,7 +9606,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "futures 0.3.25", "futures-timer", @@ -9539,7 +9629,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", "sc-client-api", @@ -9555,7 +9645,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "impl-trait-for-tuples", "memmap2", @@ -9572,7 +9662,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -9583,9 +9673,9 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "chrono", "clap", "fdlimit", @@ -9623,7 +9713,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "fnv", "futures 0.3.25", @@ -9651,7 +9741,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "hash-db", "kvdb", @@ -9676,13 +9766,14 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "futures 0.3.25", "futures-timer", "libp2p", "log", + "mockall", "parking_lot 0.12.1", "sc-client-api", "sc-utils", @@ -9700,7 +9791,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "futures 0.3.25", @@ -9729,19 +9820,18 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "fork-tree", "futures 0.3.25", "log", "merlin", - "num-bigint 0.2.6", - "num-rational 0.2.4", + "num-bigint", + "num-rational", "num-traits", "parity-scale-codec 3.2.1", "parking_lot 0.12.1", - "rand 0.7.3", "sc-client-api", "sc-consensus", "sc-consensus-epochs", @@ -9771,7 +9861,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "futures 0.3.25", "jsonrpsee", @@ -9793,7 +9883,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "fork-tree", "parity-scale-codec 3.2.1", @@ -9806,7 +9896,7 @@ dependencies = [ [[package]] name = "sc-consensus-manual-seal" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "assert_matches", "async-trait", @@ -9840,7 +9930,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "futures 0.3.25", @@ -9864,10 +9954,9 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "lazy_static", - "lru 0.7.8", + "lru", "parity-scale-codec 3.2.1", "parking_lot 0.12.1", "sc-executor-common", @@ -9875,12 +9964,10 @@ dependencies = [ "sc-executor-wasmtime", "sp-api", "sp-core", - "sp-core-hashing-proc-macro", "sp-externalities", "sp-io", "sp-panic-handler", "sp-runtime-interface", - "sp-tasks", "sp-trie", "sp-version", "sp-wasm-interface", @@ -9891,13 +9978,10 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "environmental", - "parity-scale-codec 3.2.1", "sc-allocator", "sp-maybe-compressed-blob", - "sp-sandbox", "sp-wasm-interface", "thiserror", "wasm-instrument", @@ -9907,14 +9991,12 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "log", - "parity-scale-codec 3.2.1", "sc-allocator", "sc-executor-common", "sp-runtime-interface", - "sp-sandbox", "sp-wasm-interface", "wasmi", ] @@ -9922,19 +10004,16 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "log", "once_cell", - "parity-scale-codec 3.2.1", - "parity-wasm 0.45.0", - "rustix", + "rustix 0.35.13", "sc-allocator", "sc-executor-common", "sp-runtime-interface", - "sp-sandbox", "sp-wasm-interface", "wasmtime", ] @@ -9942,10 +10021,10 @@ dependencies = [ [[package]] name = "sc-finality-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "ahash", - "array-bytes", + "array-bytes 4.2.0", "async-trait", "dyn-clone", "finality-grandpa", @@ -9983,7 +10062,7 @@ dependencies = [ [[package]] name = "sc-finality-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "finality-grandpa", "futures 0.3.25", @@ -10004,13 +10083,12 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "ansi_term", "futures 0.3.25", "futures-timer", "log", - "parity-util-mem", "sc-client-api", "sc-network-common", "sc-transaction-pool-api", @@ -10021,9 +10099,9 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "async-trait", "parking_lot 0.12.1", "serde_json", @@ -10036,9 +10114,9 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "async-trait", "asynchronous-codec", "bitflags", @@ -10054,11 +10132,11 @@ dependencies = [ "linked-hash-map", "linked_hash_set", "log", - "lru 0.7.8", + "lru", "parity-scale-codec 3.2.1", "parking_lot 0.12.1", "pin-project", - "prost 0.10.4", + "prost", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -10083,14 +10161,14 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "cid", "futures 0.3.25", "libp2p", "log", - "prost 0.11.0", - "prost-build 0.11.1", + "prost", + "prost-build", "sc-client-api", "sc-network-common", "sp-blockchain", @@ -10103,7 +10181,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "bitflags", @@ -10113,7 +10191,7 @@ dependencies = [ "libp2p", "linked_hash_set", "parity-scale-codec 3.2.1", - "prost-build 0.10.4", + "prost-build", "sc-consensus", "sc-peerset", "serde", @@ -10129,14 +10207,14 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "ahash", "futures 0.3.25", "futures-timer", "libp2p", "log", - "lru 0.7.8", + "lru", "sc-network-common", "sc-peerset", "sp-runtime", @@ -10147,15 +10225,15 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "futures 0.3.25", "libp2p", "log", "parity-scale-codec 3.2.1", - "prost 0.10.4", - "prost-build 0.10.4", + "prost", + "prost-build", "sc-client-api", "sc-network-common", "sc-peerset", @@ -10168,21 +10246,24 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", + "async-trait", "fork-tree", "futures 0.3.25", "libp2p", "log", - "lru 0.7.8", + "lru", + "mockall", "parity-scale-codec 3.2.1", - "prost 0.10.4", - "prost-build 0.10.4", + "prost", + "prost-build", "sc-client-api", "sc-consensus", "sc-network-common", "sc-peerset", + "sc-utils", "smallvec", "sp-arithmetic", "sp-blockchain", @@ -10190,15 +10271,16 @@ dependencies = [ "sp-core", "sp-finality-grandpa", "sp-runtime", + "substrate-prometheus-endpoint", "thiserror", ] [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "futures 0.3.25", "hex", "libp2p", @@ -10215,9 +10297,9 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "bytes", "fnv", "futures 0.3.25", @@ -10245,7 +10327,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "futures 0.3.25", "libp2p", @@ -10258,7 +10340,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10267,7 +10349,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "futures 0.3.25", "hash-db", @@ -10297,7 +10379,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "futures 0.3.25", "jsonrpsee", @@ -10320,20 +10402,42 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "futures 0.3.25", + "http", "jsonrpsee", "log", "serde_json", "substrate-prometheus-endpoint", "tokio", + "tower", + "tower-http", +] + +[[package]] +name = "sc-rpc-spec-v2" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" +dependencies = [ + "futures 0.3.25", + "hex", + "jsonrpsee", + "parity-scale-codec 3.2.1", + "sc-chain-spec", + "sc-transaction-pool-api", + "serde", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-runtime", + "thiserror", ] [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "directories", @@ -10344,7 +10448,6 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec 3.2.1", - "parity-util-mem", "parking_lot 0.12.1", "pin-project", "rand 0.7.3", @@ -10365,6 +10468,7 @@ dependencies = [ "sc-offchain", "sc-rpc", "sc-rpc-server", + "sc-rpc-spec-v2", "sc-sysinfo", "sc-telemetry", "sc-tracing", @@ -10403,12 +10507,10 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "log", "parity-scale-codec 3.2.1", - "parity-util-mem", - "parity-util-mem-derive", "parking_lot 0.12.1", "sc-client-api", "sp-core", @@ -10417,7 +10519,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "jsonrpsee", "parity-scale-codec 3.2.1", @@ -10436,7 +10538,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "futures 0.3.25", "libc", @@ -10455,7 +10557,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "chrono", "futures 0.3.25", @@ -10473,7 +10575,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "ansi_term", "atty", @@ -10504,7 +10606,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10515,14 +10617,14 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ + "async-trait", "futures 0.3.25", "futures-timer", "linked-hash-map", "log", "parity-scale-codec 3.2.1", - "parity-util-mem", "parking_lot 0.12.1", "sc-client-api", "sc-transaction-pool-api", @@ -10541,8 +10643,9 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ + "async-trait", "futures 0.3.25", "log", "serde", @@ -10554,7 +10657,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "futures 0.3.25", "futures-timer", @@ -10566,12 +10669,12 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "333af15b02563b8182cd863f925bd31ef8fa86a0e095d30c091956057d436153" +checksum = "001cf62ece89779fd16105b5f515ad0e5cedcd5440d3dd806bb067978e7c3608" dependencies = [ "bitvec 1.0.1", - "cfg-if 1.0.0", + "cfg-if", "derive_more", "parity-scale-codec 3.2.1", "scale-info-derive", @@ -10580,9 +10683,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53f56acbd0743d29ffa08f911ab5397def774ad01bab3786804cf6ee057fb5e1" +checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10626,9 +10729,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scratch" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" [[package]] name = "sct" @@ -10642,10 +10745,11 @@ dependencies = [ [[package]] name = "sec1" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ + "base16ct", "der", "generic-array 0.14.6", "pkcs8", @@ -10655,9 +10759,9 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.24.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7649a0b3ffb32636e60c7ce0d70511eda9c52c658cd0634e194d5a19943aeff" +checksum = "d9512ffd81e3a3503ed401f79c33168b9148c75038956039166cd750eaa037c3" dependencies = [ "secp256k1-sys", ] @@ -10723,9 +10827,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" dependencies = [ "serde", ] @@ -10738,18 +10842,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.146" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6df50b7a60a0ad48e1b42eb38373eac8ff785d619fb14db917b4e63d5439361f" +checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.146" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a714fd32ba1d66047ce7d53dabd809e9922d538f9047de13cc4cffca47b36205" +checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" dependencies = [ "proc-macro2", "quote", @@ -10758,9 +10862,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.87" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ "itoa", "ryu", @@ -10783,7 +10887,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", @@ -10795,9 +10899,9 @@ version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", - "digest 0.10.5", + "digest 0.10.6", ] [[package]] @@ -10819,7 +10923,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", @@ -10831,9 +10935,22 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", - "digest 0.10.5", + "digest 0.10.6", +] + +[[package]] +name = "sha3" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" +dependencies = [ + "block-buffer 0.7.3", + "byte-tools", + "digest 0.8.1", + "keccak", + "opaque-debug 0.2.3", ] [[package]] @@ -10842,10 +10959,16 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" dependencies = [ - "digest 0.10.5", + "digest 0.10.6", "keccak", ] +[[package]] +name = "sha3-const" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b04774de876479a8f712e787f8271b14712971329a4be66c6dff144db7cfc343" + [[package]] name = "sharded-slab" version = "0.1.4" @@ -10882,11 +11005,11 @@ dependencies = [ [[package]] name = "signature" -version = "1.4.0" +version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ - "digest 0.9.0", + "digest 0.10.6", "rand_core 0.6.4", ] @@ -10902,6 +11025,26 @@ dependencies = [ "paste", ] +[[package]] +name = "similar" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" +dependencies = [ + "bstr", + "unicode-segmentation", +] + +[[package]] +name = "similar-asserts" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbf644ad016b75129f01a34a355dcb8d66a5bc803e417c7a77cc5d5ee9fa0f18" +dependencies = [ + "console", + "similar", +] + [[package]] name = "slab" version = "0.4.7" @@ -10919,8 +11062,8 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "slot-range-helper" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "enumn", "parity-scale-codec 3.2.1", @@ -10946,9 +11089,9 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "snap" -version = "1.0.5" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451" +checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" @@ -10959,7 +11102,7 @@ dependencies = [ "aes-gcm", "blake2", "chacha20poly1305", - "curve25519-dalek 4.0.0-pre.1", + "curve25519-dalek 4.0.0-pre.5", "rand_core 0.6.4", "ring", "rustc_version 0.4.0", @@ -10987,6 +11130,7 @@ dependencies = [ "bytes", "flate2", "futures 0.3.25", + "http", "httparse", "log", "rand 0.8.5", @@ -10996,7 +11140,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "hash-db", "log", @@ -11014,7 +11158,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "blake2", "proc-macro-crate", @@ -11025,8 +11169,8 @@ dependencies = [ [[package]] name = "sp-application-crypto" -version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", "scale-info", @@ -11038,8 +11182,8 @@ dependencies = [ [[package]] name = "sp-arithmetic" -version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "integer-sqrt", "num-traits", @@ -11054,7 +11198,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", "scale-info", @@ -11067,7 +11211,7 @@ dependencies = [ [[package]] name = "sp-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "parity-scale-codec 3.2.1", @@ -11076,10 +11220,27 @@ dependencies = [ "sp-std", ] +[[package]] +name = "sp-beefy" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" +dependencies = [ + "parity-scale-codec 3.2.1", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-mmr-primitives", + "sp-runtime", + "sp-std", +] + [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", "sp-api", @@ -11091,11 +11252,11 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "futures 0.3.25", "log", - "lru 0.7.8", + "lru", "parity-scale-codec 3.2.1", "parking_lot 0.12.1", "sp-api", @@ -11109,7 +11270,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "futures 0.3.25", @@ -11128,7 +11289,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "parity-scale-codec 3.2.1", @@ -11146,7 +11307,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "merlin", @@ -11169,7 +11330,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", "scale-info", @@ -11183,7 +11344,7 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", "scale-info", @@ -11195,10 +11356,10 @@ dependencies = [ [[package]] name = "sp-core" -version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "base58", "bitflags", "blake2", @@ -11215,9 +11376,8 @@ dependencies = [ "merlin", "num-traits", "parity-scale-codec 3.2.1", - "parity-util-mem", "parking_lot 0.12.1", - "primitive-types", + "primitive-types 0.12.1", "rand 0.7.3", "regex", "scale-info", @@ -11241,14 +11401,14 @@ dependencies = [ [[package]] name = "sp-core-hashing" -version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "blake2", "byteorder", - "digest 0.10.5", + "digest 0.10.6", "sha2 0.10.6", - "sha3", + "sha3 0.10.6", "sp-std", "twox-hash", ] @@ -11256,7 +11416,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "proc-macro2", "quote", @@ -11267,7 +11427,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -11275,8 +11435,8 @@ dependencies = [ [[package]] name = "sp-debug-derive" -version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "proc-macro2", "quote", @@ -11285,8 +11445,8 @@ dependencies = [ [[package]] name = "sp-externalities" -version = "0.12.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "0.13.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "environmental", "parity-scale-codec 3.2.1", @@ -11297,7 +11457,7 @@ dependencies = [ [[package]] name = "sp-finality-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "finality-grandpa", "log", @@ -11315,7 +11475,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -11328,10 +11488,11 @@ dependencies = [ [[package]] name = "sp-io" -version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "bytes", + "ed25519-dalek", "futures 0.3.25", "hash-db", "libsecp256k1", @@ -11354,8 +11515,8 @@ dependencies = [ [[package]] name = "sp-keyring" -version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "lazy_static", "sp-core", @@ -11365,8 +11526,8 @@ dependencies = [ [[package]] name = "sp-keystore" -version = "0.12.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "0.13.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "futures 0.3.25", @@ -11383,7 +11544,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "thiserror", "zstd", @@ -11392,22 +11553,25 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ + "ckb-merkle-mountain-range", "log", "parity-scale-codec 3.2.1", + "scale-info", "serde", "sp-api", "sp-core", "sp-debug-derive", "sp-runtime", "sp-std", + "thiserror", ] [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", "scale-info", @@ -11421,7 +11585,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "sp-api", "sp-core", @@ -11430,8 +11594,8 @@ dependencies = [ [[package]] name = "sp-panic-handler" -version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "backtrace", "lazy_static", @@ -11441,7 +11605,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "rustc-hash", "serde", @@ -11450,15 +11614,14 @@ dependencies = [ [[package]] name = "sp-runtime" -version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "either", "hash256-std-hasher", "impl-trait-for-tuples", "log", "parity-scale-codec 3.2.1", - "parity-util-mem", "paste", "rand 0.7.3", "scale-info", @@ -11473,13 +11636,13 @@ dependencies = [ [[package]] name = "sp-runtime-interface" -version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "bytes", "impl-trait-for-tuples", "parity-scale-codec 3.2.1", - "primitive-types", + "primitive-types 0.12.1", "sp-externalities", "sp-runtime-interface-proc-macro", "sp-std", @@ -11491,8 +11654,8 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" -version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "Inflector", "proc-macro-crate", @@ -11501,24 +11664,10 @@ dependencies = [ "syn", ] -[[package]] -name = "sp-sandbox" -version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" -dependencies = [ - "log", - "parity-scale-codec 3.2.1", - "sp-core", - "sp-io", - "sp-std", - "sp-wasm-interface", - "wasmi", -] - [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", "scale-info", @@ -11532,18 +11681,19 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", "scale-info", + "sp-core", "sp-runtime", "sp-std", ] [[package]] name = "sp-state-machine" -version = "0.12.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "0.13.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "hash-db", "log", @@ -11564,13 +11714,13 @@ dependencies = [ [[package]] name = "sp-std" -version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" [[package]] name = "sp-storage" -version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "impl-serde", "parity-scale-codec 3.2.1", @@ -11580,23 +11730,10 @@ dependencies = [ "sp-std", ] -[[package]] -name = "sp-tasks" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" -dependencies = [ - "log", - "sp-core", - "sp-externalities", - "sp-io", - "sp-runtime-interface", - "sp-std", -] - [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "futures-timer", @@ -11611,8 +11748,8 @@ dependencies = [ [[package]] name = "sp-tracing" -version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", "sp-std", @@ -11624,7 +11761,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "sp-api", "sp-runtime", @@ -11633,7 +11770,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "async-trait", "log", @@ -11648,14 +11785,14 @@ dependencies = [ [[package]] name = "sp-trie" -version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "ahash", "hash-db", "hashbrown", "lazy_static", - "lru 0.7.8", + "lru", "memory-db", "nohash-hasher", "parity-scale-codec 3.2.1", @@ -11672,11 +11809,11 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "impl-serde", "parity-scale-codec 3.2.1", - "parity-wasm 0.45.0", + "parity-wasm", "scale-info", "serde", "sp-core-hashing-proc-macro", @@ -11689,7 +11826,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "parity-scale-codec 3.2.1", "proc-macro2", @@ -11699,8 +11836,8 @@ dependencies = [ [[package]] name = "sp-wasm-interface" -version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "impl-trait-for-tuples", "log", @@ -11713,7 +11850,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec 3.2.1", @@ -11734,9 +11871,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spki" -version = "0.5.4" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ "base64ct", "der", @@ -11744,9 +11881,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.33.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab7554f8a8b6f8d71cd5a8e6536ef116e2ce0504cf97ebf16311d58065dc8a6" +checksum = "23d92659e7d18d82b803824a9ba5a6022cff101c3491d027c1c1d8d30e749284" dependencies = [ "Inflector", "num-format", @@ -11791,7 +11928,7 @@ dependencies = [ "cfg_aliases", "libc", "parking_lot 0.11.2", - "parking_lot_core 0.8.5", + "parking_lot_core 0.8.6", "static_init_macro 1.0.2", "winapi", ] @@ -11887,15 +12024,15 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "platforms", + "platforms 2.0.0", ] [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "frame-system-rpc-runtime-api", "futures 0.3.25", @@ -11916,7 +12053,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "futures-util", "hyper", @@ -11926,10 +12063,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "substrate-rpc-client" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" +dependencies = [ + "async-trait", + "jsonrpsee", + "log", + "sc-rpc-api", + "serde", + "sp-runtime", +] + [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "jsonrpsee", "log", @@ -11950,9 +12100,9 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ - "array-bytes", + "array-bytes 4.2.0", "async-trait", "futures 0.3.25", "parity-scale-codec 3.2.1", @@ -11976,7 +12126,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "futures 0.3.25", "substrate-test-utils-derive", @@ -11986,7 +12136,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11997,7 +12147,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "ansi_term", "build-helper", @@ -12008,7 +12158,7 @@ dependencies = [ "tempfile", "toml", "walkdir", - "wasm-gc-api", + "wasm-opt", ] [[package]] @@ -12019,9 +12169,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.103" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -12069,9 +12219,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1" +checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" [[package]] name = "tempfile" @@ -12079,7 +12229,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "libc", "redox_syscall", @@ -12096,16 +12246,34 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "termtree" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8" + [[package]] name = "test-runtime-constants" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "frame-support", "polkadot-primitives", "polkadot-runtime-common", "smallvec", + "sp-core", "sp-runtime", + "sp-weights", ] [[package]] @@ -12138,26 +12306,20 @@ dependencies = [ "up-sponsorship", ] -[[package]] -name = "textwrap" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" - [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", @@ -12202,45 +12364,38 @@ dependencies = [ ] [[package]] -name = "tikv-jemalloc-sys" -version = "0.4.3+5.2.1-patched.2" +name = "tikv-jemalloc-ctl" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1792ccb507d955b46af42c123ea8863668fae24d03721e40cad6a41773dbb49" +checksum = "e37706572f4b151dff7a0146e040804e9c26fe3a3118591112f05cf12a4216c1" dependencies = [ - "cc", - "fs_extra", "libc", + "paste", + "tikv-jemalloc-sys", ] [[package]] -name = "time" -version = "0.1.44" +name = "tikv-jemalloc-sys" +version = "0.5.2+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3" dependencies = [ + "cc", + "fs_extra", "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", ] [[package]] name = "time" -version = "0.3.9" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ - "itoa", "libc", - "num_threads", - "time-macros", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", ] -[[package]] -name = "time-macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" - [[package]] name = "tiny-bip39" version = "0.8.2" @@ -12286,9 +12441,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.21.2" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" dependencies = [ "autocfg", "bytes", @@ -12301,14 +12456,14 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "winapi", + "windows-sys 0.42.0", ] [[package]] name = "tokio-macros" -version = "1.8.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ "proc-macro2", "quote", @@ -12354,13 +12509,48 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" dependencies = [ "serde", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite 0.2.9", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -12373,7 +12563,8 @@ version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", + "log", "pin-project-lite 0.2.9", "tracing-attributes", "tracing-core", @@ -12412,8 +12603,8 @@ dependencies = [ [[package]] name = "tracing-gum" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "polkadot-node-jaeger", "polkadot-primitives", @@ -12423,8 +12614,8 @@ dependencies = [ [[package]] name = "tracing-gum-proc-macro" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "expander 0.0.6", "proc-macro-crate", @@ -12511,12 +12702,12 @@ dependencies = [ [[package]] name = "trust-dns-proto" -version = "0.21.2" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" +checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" dependencies = [ "async-trait", - "cfg-if 1.0.0", + "cfg-if", "data-encoding", "enum-as-inner", "futures-channel", @@ -12525,30 +12716,32 @@ dependencies = [ "idna 0.2.3", "ipnet", "lazy_static", - "log", "rand 0.8.5", "smallvec", "thiserror", "tinyvec", + "tokio", + "tracing", "url", ] [[package]] name = "trust-dns-resolver" -version = "0.21.2" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" +checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "futures-util", "ipconfig", "lazy_static", - "log", "lru-cache", "parking_lot 0.12.1", "resolv-conf", "smallvec", "thiserror", + "tokio", + "tracing", "trust-dns-proto", ] @@ -12561,34 +12754,54 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.30#a3ed0119c45cdd0d571ad34e5b3ee7518c8cef8d" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" dependencies = [ "clap", + "frame-remote-externalities", "frame-try-runtime", - "jsonrpsee", + "hex", "log", "parity-scale-codec 3.2.1", - "remote-externalities", "sc-chain-spec", "sc-cli", "sc-executor", "sc-service", "serde", + "sp-api", "sp-core", + "sp-debug-derive", "sp-externalities", "sp-io", "sp-keystore", + "sp-rpc", "sp-runtime", "sp-state-machine", "sp-version", + "sp-weights", + "substrate-rpc-client", "zstd", ] +[[package]] +name = "trybuild" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed01de3de062db82c0920b5cabe804f88d599a3f217932292597c678c903754d" +dependencies = [ + "glob", + "once_cell", + "serde", + "serde_derive", + "serde_json", + "termcolor", + "toml", +] + [[package]] name = "tt-call" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e66dcbec4290c69dd03c57e76c2469ea5c7ce109c6dd4351c13055cf71ea055" +checksum = "f4f195fd851901624eee5a58c4bb2b4f06399148fcd0ed336e6f1cb60a9881df" [[package]] name = "twox-hash" @@ -12596,17 +12809,17 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 1.0.0", - "digest 0.10.5", + "cfg-if", + "digest 0.10.6", "rand 0.8.5", "static_assertions", ] [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "uc-rpc" @@ -12614,18 +12827,34 @@ version = "0.1.4" dependencies = [ "anyhow", "app-promotion-rpc", + "frame-benchmarking", "jsonrpsee", + "opal-runtime", "pallet-common", "pallet-evm", "parity-scale-codec 3.2.1", + "quartz-runtime", "rmrk-rpc", + "sc-client-api", + "sc-executor", + "sc-rpc-api", + "sc-service", "sp-api", "sp-blockchain", "sp-core", + "sp-externalities", + "sp-keystore", "sp-rpc", "sp-runtime", + "sp-state-machine", + "sp-trie", + "trie-db", + "unique-runtime", + "up-common", "up-data-structs", + "up-pov-estimate-rpc", "up-rpc", + "zstd", ] [[package]] @@ -12636,9 +12865,9 @@ checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "uint" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45526d29728d135c2900b0d30573fe3ee79fceb12ef534c7bb30e810a91b601" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ "byteorder", "crunchy", @@ -12646,15 +12875,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.8" @@ -12663,9 +12883,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unicode-normalization" @@ -12676,6 +12896,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" + [[package]] name = "unicode-width" version = "0.1.10" @@ -12690,7 +12916,7 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "unique-node" -version = "0.9.30" +version = "0.9.36" dependencies = [ "app-promotion-rpc", "clap", @@ -12704,7 +12930,7 @@ dependencies = [ "cumulus-primitives-parachain-inherent", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", - "cumulus-relay-chain-rpc-interface", + "cumulus-relay-chain-minimal-node", "fc-consensus", "fc-db", "fc-mapping-sync", @@ -12758,6 +12984,7 @@ dependencies = [ "sp-core", "sp-finality-grandpa", "sp-inherents", + "sp-io", "sp-keystore", "sp-offchain", "sp-runtime", @@ -12770,10 +12997,12 @@ dependencies = [ "substrate-prometheus-endpoint", "tokio", "try-runtime-cli", + "uc-rpc", "unique-rpc", "unique-runtime", "up-common", "up-data-structs", + "up-pov-estimate-rpc", "up-rpc", ] @@ -12824,12 +13053,13 @@ dependencies = [ "uc-rpc", "up-common", "up-data-structs", + "up-pov-estimate-rpc", "up-rpc", ] [[package]] name = "unique-runtime" -version = "0.9.30" +version = "0.9.36" dependencies = [ "app-promotion-rpc", "cumulus-pallet-aura-ext", @@ -12842,6 +13072,7 @@ dependencies = [ "cumulus-primitives-utility", "derivative", "evm-coder", + "fp-evm", "fp-evm-mapping", "fp-rpc", "fp-self-contained", @@ -12856,6 +13087,7 @@ dependencies = [ "impl-trait-for-tuples", "log", "logtest", + "num_enum", "orml-tokens", "orml-traits", "orml-vesting", @@ -12871,6 +13103,7 @@ dependencies = [ "pallet-evm-coder-substrate", "pallet-evm-contract-helpers", "pallet-evm-migration", + "pallet-evm-precompile-simple", "pallet-evm-transaction-payment", "pallet-foreign-assets", "pallet-fungible", @@ -12889,11 +13122,11 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pallet-treasury", "pallet-unique", - "pallet-unique-scheduler", "pallet-xcm", "parachain-info", "parity-scale-codec 3.2.1", "polkadot-parachain", + "precompile-utils-macro", "rmrk-rpc", "scale-info", "serde", @@ -12914,6 +13147,7 @@ dependencies = [ "substrate-wasm-builder", "up-common", "up-data-structs", + "up-pov-estimate-rpc", "up-rpc", "up-sponsorship", "xcm", @@ -12951,8 +13185,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "up-common" -version = "0.9.30" +version = "0.9.36" dependencies = [ + "cumulus-primitives-core", "fp-rpc", "frame-support", "pallet-evm", @@ -12981,6 +13216,19 @@ dependencies = [ "struct-versioning", ] +[[package]] +name = "up-pov-estimate-rpc" +version = "0.1.0" +dependencies = [ + "parity-scale-codec 3.2.1", + "scale-info", + "serde", + "sp-api", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "up-rpc" version = "0.1.3" @@ -12998,7 +13246,7 @@ dependencies = [ [[package]] name = "up-sponsorship" version = "0.1.0" -source = "git+https://github.com/uniquenetwork/pallet-sponsoring?branch=polkadot-v0.9.30#39dd82158d6caa9d89105441bf2f7111a6e686e5" +source = "git+https://github.com/uniquenetwork/pallet-sponsoring?branch=polkadot-v0.9.36#55943b982e9b0b80465885f31f76db3dba91dac4" dependencies = [ "impl-trait-for-tuples", ] @@ -13099,7 +13347,7 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] @@ -13124,7 +13372,7 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -13160,23 +13408,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] -name = "wasm-gc-api" -version = "0.1.11" +name = "wasm-instrument" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c32691b6c7e6c14e7f8fd55361a9088b507aa49620fcd06c09b3a1082186b9" +checksum = "aa1dafb3e60065305741e83db35c6c2584bb3725b692b5b66148a38d72ace6cd" dependencies = [ - "log", - "parity-wasm 0.32.0", - "rustc-demangle", + "parity-wasm", ] [[package]] -name = "wasm-instrument" -version = "0.3.0" +name = "wasm-opt" +version = "0.110.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa1dafb3e60065305741e83db35c6c2584bb3725b692b5b66148a38d72ace6cd" +checksum = "b68e8037b4daf711393f4be2056246d12d975651b14d581520ad5d1f19219cec" +dependencies = [ + "anyhow", + "libc", + "strum", + "strum_macros", + "tempfile", + "thiserror", + "wasm-opt-cxx-sys", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-cxx-sys" +version = "0.110.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91adbad477e97bba3fbd21dd7bfb594e7ad5ceb9169ab1c93ab9cb0ada636b6f" +dependencies = [ + "anyhow", + "cxx", + "cxx-build", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-sys" +version = "0.110.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4fa5a322a4e6ac22fd141f498d56afbdbf9df5debeac32380d2dcaa3e06941" dependencies = [ - "parity-wasm 0.45.0", + "anyhow", + "cc", + "cxx", + "cxx-build", + "regex", ] [[package]] @@ -13200,7 +13478,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06c326c93fbf86419608361a2c925a31754cf109da1b8b55737070b4d6669422" dependencies = [ - "parity-wasm 0.45.0", + "parity-wasm", "wasmi-validation", "wasmi_core", ] @@ -13211,7 +13489,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ff416ad1ff0c42e5a926ed5d5fab74c0f098749aa0ad8b2a34b982ce0e867b" dependencies = [ - "parity-wasm 0.45.0", + "parity-wasm", ] [[package]] @@ -13221,9 +13499,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57d20cb3c59b788653d99541c646c561c9dd26506f25c0cebfe810659c54c6d7" dependencies = [ "downcast-rs", - "libm", + "libm 0.2.6", "memory_units", - "num-rational 0.4.1", + "num-rational", "num-traits", ] @@ -13238,17 +13516,17 @@ dependencies = [ [[package]] name = "wasmtime" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f511c4917c83d04da68333921107db75747c4e11a2f654a8e909cc5e0520dc" +checksum = "4ad5af6ba38311282f2a21670d96e78266e8c8e2f38cbcd52c254df6ccbc7731" dependencies = [ "anyhow", "bincode", - "cfg-if 1.0.0", + "cfg-if", "indexmap", "libc", "log", - "object", + "object 0.29.0", "once_cell", "paste", "psm", @@ -13266,18 +13544,18 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39bf3debfe744bf19dd3732990ce6f8c0ced7439e2370ba4e1d8f5a3660a3178" +checksum = "45de63ddfc8b9223d1adc8f7b2ee5f35d1f6d112833934ad7ea66e4f4339e597" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece42fa4676a263f7558cdaaf5a71c2592bebcbac22a0580e33cf3406c103da2" +checksum = "bcd849399d17d2270141cfe47fa0d91ee52d5f8ea9b98cf7ddde0d53e5f79882" dependencies = [ "anyhow", "base64", @@ -13285,7 +13563,7 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix", + "rustix 0.35.13", "serde", "sha2 0.9.9", "toml", @@ -13295,9 +13573,9 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "058217e28644b012bdcdf0e445f58d496d78c2e0b6a6dd93558e701591dad705" +checksum = "4bd91339b742ff20bfed4532a27b73c86b5bcbfedd6bea2dcdf2d64471e1b5c6" dependencies = [ "anyhow", "cranelift-codegen", @@ -13305,9 +13583,9 @@ dependencies = [ "cranelift-frontend", "cranelift-native", "cranelift-wasm", - "gimli", + "gimli 0.26.2", "log", - "object", + "object 0.29.0", "target-lexicon", "thiserror", "wasmparser", @@ -13316,16 +13594,16 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7af06848df28b7661471d9a80d30a973e0f401f2e3ed5396ad7e225ed217047" +checksum = "ebb881c61f4f627b5d45c54e629724974f8a8890d455bcbe634330cc27309644" dependencies = [ "anyhow", "cranelift-entity", - "gimli", + "gimli 0.26.2", "indexmap", "log", - "object", + "object 0.29.0", "serde", "target-lexicon", "thiserror", @@ -13335,20 +13613,20 @@ dependencies = [ [[package]] name = "wasmtime-jit" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9028fb63a54185b3c192b7500ef8039c7bb8d7f62bfc9e7c258483a33a3d13bb" +checksum = "1985c628011fe26adf5e23a5301bdc79b245e0e338f14bb58b39e4e25e4d8681" dependencies = [ - "addr2line", + "addr2line 0.17.0", "anyhow", "bincode", - "cfg-if 1.0.0", + "cfg-if", "cpp_demangle", - "gimli", + "gimli 0.26.2", "log", - "object", + "object 0.29.0", "rustc-demangle", - "rustix", + "rustix 0.35.13", "serde", "target-lexicon", "thiserror", @@ -13360,33 +13638,33 @@ dependencies = [ [[package]] name = "wasmtime-jit-debug" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e82d4ef93296785de7efca92f7679dc67fe68a13b625a5ecc8d7503b377a37" +checksum = "f671b588486f5ccec8c5a3dba6b4c07eac2e66ab8c60e6f4e53717c77f709731" dependencies = [ - "object", + "object 0.29.0", "once_cell", - "rustix", + "rustix 0.35.13", ] [[package]] name = "wasmtime-runtime" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f0e9bea7d517d114fe66b930b2124ee086516ee93eeebfd97f75f366c5b0553" +checksum = "ee8f92ad4b61736339c29361da85769ebc200f184361959d1792832e592a1afd" dependencies = [ "anyhow", "cc", - "cfg-if 1.0.0", + "cfg-if", "indexmap", "libc", "log", "mach", "memfd", - "memoffset", + "memoffset 0.6.5", "paste", "rand 0.8.5", - "rustix", + "rustix 0.35.13", "thiserror", "wasmtime-asm-macros", "wasmtime-environ", @@ -13396,9 +13674,9 @@ dependencies = [ [[package]] name = "wasmtime-types" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b83e93ed41b8fdc936244cfd5e455480cf1eca1fd60c78a0040038b4ce5075" +checksum = "d23d61cb4c46e837b431196dd06abb11731541021916d03476a178b54dc07aeb" dependencies = [ "cranelift-entity", "serde", @@ -13428,9 +13706,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.22.5" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368bfe657969fb01238bb756d351dcade285e0f6fcbd36dcb23359a5169975be" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" dependencies = [ "webpki", ] @@ -13446,10 +13724,9 @@ dependencies = [ [[package]] name = "westend-runtime" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ - "beefy-primitives", "bitvec 1.0.1", "frame-benchmarking", "frame-election-provider-support", @@ -13513,6 +13790,7 @@ dependencies = [ "smallvec", "sp-api", "sp-authority-discovery", + "sp-beefy", "sp-block-builder", "sp-consensus-babe", "sp-core", @@ -13536,14 +13814,16 @@ dependencies = [ [[package]] name = "westend-runtime-constants" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "frame-support", "polkadot-primitives", "polkadot-runtime-common", "smallvec", + "sp-core", "sp-runtime", + "sp-weights", ] [[package]] @@ -13739,9 +14019,9 @@ checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" [[package]] name = "winreg" -version = "0.7.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] @@ -13754,9 +14034,9 @@ checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" [[package]] name = "wyz" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] @@ -13774,8 +14054,8 @@ dependencies = [ [[package]] name = "xcm" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "derivative", "impl-trait-for-tuples", @@ -13788,8 +14068,8 @@ dependencies = [ [[package]] name = "xcm-builder" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "frame-support", "frame-system", @@ -13808,8 +14088,8 @@ dependencies = [ [[package]] name = "xcm-executor" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "frame-benchmarking", "frame-support", @@ -13826,8 +14106,8 @@ dependencies = [ [[package]] name = "xcm-procedural" -version = "0.9.30" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.30#064536093f5ff70d867f4bbce8d4c41a406d317a" +version = "0.9.36" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.36#dc25abc712e42b9b51d87ad1168e453a42b5f0bc" dependencies = [ "Inflector", "proc-macro2", @@ -13860,9 +14140,9 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" dependencies = [ "proc-macro2", "quote", @@ -13891,9 +14171,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.1+zstd.1.5.2" +version = "2.0.4+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" +checksum = "4fa202f2ef00074143e219d15b62ffc317d17cc33909feac471c044087cad7b0" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index 72e5e76207..5a230ecaba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,3 @@ -cargo-features = ["workspace-inheritance"] - [workspace] resolver = "2" members = [ @@ -13,26 +11,28 @@ members = [ 'runtime/unique', 'runtime/tests', ] -default-members = ['node/*', 'runtime/opal'] +default-members = ['node/*', 'client/*', 'runtime/opal'] +package.version = "0.9.36" + [profile.release] panic = 'unwind' [workspace.dependencies.orml-vesting] git = "https://github.com/uniquenetwork/open-runtime-module-library" -branch = "polkadot-v0.9.30" +branch = "feature/polkadot-v0.9.36" default-features = false [workspace.dependencies.orml-xtokens] git = "https://github.com/uniquenetwork/open-runtime-module-library" -branch = "polkadot-v0.9.30" +branch = "feature/polkadot-v0.9.36" default-features = false [workspace.dependencies.orml-tokens] git = "https://github.com/uniquenetwork/open-runtime-module-library" -branch = "polkadot-v0.9.30" +branch = "feature/polkadot-v0.9.36" default-features = false [workspace.dependencies.orml-traits] git = "https://github.com/uniquenetwork/open-runtime-module-library" -branch = "polkadot-v0.9.30" +branch = "feature/polkadot-v0.9.36" default-features = false diff --git a/Makefile b/Makefile index 0647595d64..a920e0b041 100644 --- a/Makefile +++ b/Makefile @@ -7,23 +7,20 @@ _help: @echo " bench-unique" FUNGIBLE_EVM_STUBS=./pallets/fungible/src/stubs -FUNGIBLE_EVM_ABI=./tests/src/eth/fungibleAbi.json - -REFUNGIBLE_EVM_STUBS=./pallets/refungible/src/stubs -REFUNGIBLE_EVM_ABI=./tests/src/eth/refungibleAbi.json +FUNGIBLE_EVM_ABI=./tests/src/eth/abi/fungible.json NONFUNGIBLE_EVM_STUBS=./pallets/nonfungible/src/stubs -NONFUNGIBLE_EVM_ABI=./tests/src/eth/nonFungibleAbi.json +NONFUNGIBLE_EVM_ABI=./tests/src/eth/abi/nonFungible.json REFUNGIBLE_EVM_STUBS=./pallets/refungible/src/stubs -REFUNGIBLE_EVM_ABI=./tests/src/eth/reFungibleAbi.json -REFUNGIBLE_TOKEN_EVM_ABI=./tests/src/eth/reFungibleTokenAbi.json +REFUNGIBLE_EVM_ABI=./tests/src/eth/abi/reFungible.json +REFUNGIBLE_TOKEN_EVM_ABI=./tests/src/eth/abi/reFungibleToken.json CONTRACT_HELPERS_STUBS=./pallets/evm-contract-helpers/src/stubs/ -CONTRACT_HELPERS_ABI=./tests/src/eth/util/contractHelpersAbi.json +CONTRACT_HELPERS_ABI=./tests/src/eth/abi/contractHelpers.json COLLECTION_HELPER_STUBS=./pallets/unique/src/eth/stubs/ -COLLECTION_HELPER_ABI=./tests/src/eth/collectionHelpersAbi.json +COLLECTION_HELPER_ABI=./tests/src/eth/abi/collectionHelpers.json TESTS_API=./tests/src/eth/api/ @@ -118,7 +115,7 @@ bench-structure: .PHONY: bench-scheduler bench-scheduler: - make _bench PALLET=unique-scheduler PALLET_DIR=scheduler + make _bench PALLET=unique-scheduler-v2 PALLET_DIR=scheduler-v2 .PHONY: bench-rmrk-core bench-rmrk-core: diff --git a/README.md b/README.md index 47913561cd..0622ce7e55 100644 --- a/README.md +++ b/README.md @@ -46,17 +46,17 @@ curl https://sh.rustup.rs -sSf | sh 2. Remove all installed toolchains with `rustup toolchain list` and `rustup toolchain uninstall `. -3. Install toolchain nightly-2022-07-24 and make it default: +3. Install toolchain nightly-2022-10-09 and make it default: ```bash -rustup toolchain install nightly-2022-07-24 -rustup default nightly-2022-07-24 +rustup toolchain install nightly-2022-10-09 +rustup default nightly-2022-10-09 ``` 4. Add wasm target for nightly toolchain: ```bash -rustup target add wasm32-unknown-unknown --toolchain nightly-2022-07-24 +rustup target add wasm32-unknown-unknown --toolchain nightly-2022-10-09 ``` 5. Build: @@ -82,7 +82,7 @@ Note: checkout this project and all related projects (see below) in the sibling ``` git clone https://github.com/UniqueNetwork/polkadot-launch.git -git checkout feature/runtime-upgrade-testing +git checkout unique-network ``` ### Build relay @@ -90,7 +90,7 @@ git checkout feature/runtime-upgrade-testing ``` git clone https://github.com/paritytech/polkadot.git cd polkadot -git checkout release-v0.9.30 +git checkout release-v0.9.36 cargo build --release ``` diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index c33a55967c..8eb438229b 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -7,16 +7,43 @@ edition = "2021" [dependencies] pallet-common = { default-features = false, path = '../../pallets/common' } up-data-structs = { default-features = false, path = '../../primitives/data-structs' } +up-common = { default-features = false, path = '../../primitives/common' } up-rpc = { path = "../../primitives/rpc" } -app-promotion-rpc = { path = "../../primitives/app_promotion_rpc"} +app-promotion-rpc = { path = "../../primitives/app_promotion_rpc" } rmrk-rpc = { path = "../../primitives/rmrk-rpc" } +up-pov-estimate-rpc = { path = "../../primitives/pov-estimate-rpc", optional = true } codec = { package = "parity-scale-codec", version = "3.1.2" } -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["server", "macros"] } anyhow = "1.0.57" +zstd = { version = "0.11.2", default-features = false } +trie-db = { version = "0.24.0", default-features = false } -sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-blockchain = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-rpc = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +sc-rpc-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sc-service = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-externalities = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-blockchain = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-keystore = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-rpc = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-trie = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } + +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } + +sc-executor = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } + +unique-runtime = { path = '../../runtime/unique', optional = true } +quartz-runtime = { path = '../../runtime/quartz', optional = true } +opal-runtime = { path = '../../runtime/opal' } + +[features] +pov-estimate = [ + 'up-pov-estimate-rpc', + 'unique-runtime?/pov-estimate', + 'quartz-runtime?/pov-estimate', + 'opal-runtime/pov-estimate', +] diff --git a/client/rpc/src/lib.rs b/client/rpc/src/lib.rs index 21cfe32a87..de32773116 100644 --- a/client/rpc/src/lib.rs +++ b/client/rpc/src/lib.rs @@ -42,6 +42,9 @@ use up_data_structs::{ pub use app_promotion_unique_rpc::AppPromotionApiServer; pub use rmrk_unique_rpc::RmrkApiServer; +#[cfg(feature = "pov-estimate")] +pub mod pov_estimate; + #[rpc(server)] #[async_trait] pub trait UniqueApi { @@ -246,6 +249,16 @@ pub trait UniqueApi { token_id: TokenId, at: Option, ) -> Result>; + + /// Get whether an operator is approved by a given owner. + #[method(name = "unique_allowanceForAll")] + fn allowance_for_all( + &self, + collection: CollectionId, + owner: CrossAccountId, + operator: CrossAccountId, + at: Option, + ) -> Result; } mod app_promotion_unique_rpc { @@ -410,17 +423,18 @@ mod rmrk_unique_rpc { } } +#[macro_export] macro_rules! define_struct_for_server_api { - ($name:ident) => { - pub struct $name { - client: Arc, - _marker: std::marker::PhantomData

, + ($name:ident { $($arg:ident: $arg_ty:ty),+ $(,)? }) => { + pub struct $name { + $($arg: $arg_ty),+, + _marker: std::marker::PhantomData, } - impl $name { - pub fn new(client: Arc) -> Self { + impl $name { + pub fn new($($arg: $arg_ty),+) -> Self { Self { - client, + $($arg),+, _marker: Default::default(), } } @@ -428,9 +442,23 @@ macro_rules! define_struct_for_server_api { }; } -define_struct_for_server_api!(Unique); -define_struct_for_server_api!(AppPromotion); -define_struct_for_server_api!(Rmrk); +define_struct_for_server_api! { + Unique { + client: Arc + } +} + +define_struct_for_server_api! { + AppPromotion { + client: Arc + } +} + +define_struct_for_server_api! { + Rmrk { + client: Arc + } +} macro_rules! pass_method { ( @@ -569,6 +597,7 @@ where pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option, unique_api); pass_method!(total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option => |o| o.map(|number| number.to_string()) , unique_api); pass_method!(token_owners(collection: CollectionId, token: TokenId) -> Vec, unique_api); + pass_method!(allowance_for_all(collection: CollectionId, owner: CrossAccountId, operator: CrossAccountId) -> bool, unique_api); } impl diff --git a/client/rpc/src/pov_estimate.rs b/client/rpc/src/pov_estimate.rs new file mode 100644 index 0000000000..8761e4ac9b --- /dev/null +++ b/client/rpc/src/pov_estimate.rs @@ -0,0 +1,290 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +use std::sync::Arc; + +use codec::{Encode, Decode}; +use sp_externalities::Extensions; + +use up_pov_estimate_rpc::{PovEstimateApi as PovEstimateRuntimeApi}; +use up_common::types::opaque::RuntimeId; + +use sc_service::{NativeExecutionDispatch, config::ExecutionStrategy}; +use sp_state_machine::{StateMachine, TrieBackendBuilder}; +use trie_db::{Trie, TrieDBBuilder}; + +use jsonrpsee::{core::RpcResult as Result, proc_macros::rpc}; +use anyhow::anyhow; + +use sc_client_api::backend::Backend; +use sp_blockchain::HeaderBackend; +use sp_core::{ + Bytes, + offchain::{ + testing::{TestOffchainExt, TestTransactionPoolExt}, + OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, + }, + testing::TaskExecutor, + traits::TaskExecutorExt, +}; +use sp_keystore::{testing::KeyStore, KeystoreExt}; +use sp_api::{AsTrieBackend, BlockId, BlockT, ProvideRuntimeApi}; + +use sc_executor::NativeElseWasmExecutor; +use sc_rpc_api::DenyUnsafe; + +use sp_runtime::traits::Header; + +use up_pov_estimate_rpc::{PovInfo, TrieKeyValue}; + +use crate::define_struct_for_server_api; + +type HasherOf = <::Header as Header>::Hashing; +type StateOf = as Backend>::State; + +pub struct ExecutorParams { + pub wasm_method: sc_service::config::WasmExecutionMethod, + pub default_heap_pages: Option, + pub max_runtime_instances: usize, + pub runtime_cache_size: u8, +} + +#[cfg(feature = "unique-runtime")] +pub struct UniqueRuntimeExecutor; + +#[cfg(feature = "quartz-runtime")] +pub struct QuartzRuntimeExecutor; + +pub struct OpalRuntimeExecutor; + +#[cfg(feature = "unique-runtime")] +impl NativeExecutionDispatch for UniqueRuntimeExecutor { + type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + + fn dispatch(method: &str, data: &[u8]) -> Option> { + unique_runtime::api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + unique_runtime::native_version() + } +} + +#[cfg(feature = "quartz-runtime")] +impl NativeExecutionDispatch for QuartzRuntimeExecutor { + type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + + fn dispatch(method: &str, data: &[u8]) -> Option> { + quartz_runtime::api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + quartz_runtime::native_version() + } +} + +impl NativeExecutionDispatch for OpalRuntimeExecutor { + type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + + fn dispatch(method: &str, data: &[u8]) -> Option> { + opal_runtime::api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + opal_runtime::native_version() + } +} + +#[cfg(feature = "pov-estimate")] +define_struct_for_server_api! { + PovEstimate { + client: Arc, + backend: Arc>, + deny_unsafe: DenyUnsafe, + exec_params: ExecutorParams, + runtime_id: RuntimeId, + } +} + +#[rpc(server)] +#[async_trait] +pub trait PovEstimateApi { + #[method(name = "povinfo_estimateExtrinsicPoV")] + fn estimate_extrinsic_pov( + &self, + encoded_xts: Vec, + at: Option, + ) -> Result; +} + +#[allow(deprecated)] +#[cfg(feature = "pov-estimate")] +impl PovEstimateApiServer<::Hash> for PovEstimate +where + Block: BlockT, + C: 'static + ProvideRuntimeApi + HeaderBackend, + C::Api: PovEstimateRuntimeApi, +{ + fn estimate_extrinsic_pov( + &self, + encoded_xts: Vec, + at: Option<::Hash>, + ) -> Result { + self.deny_unsafe.check_if_safe()?; + + let at = at.unwrap_or_else(|| self.client.info().best_hash); + let state = self + .backend + .state_at(at) + .map_err(|_| anyhow!("unable to fetch the state at {at:?}"))?; + + match &self.runtime_id { + #[cfg(feature = "unique-runtime")] + RuntimeId::Unique => execute_extrinsic_in_sandbox::( + state, + &self.exec_params, + encoded_xts, + ), + + #[cfg(feature = "quartz-runtime")] + RuntimeId::Quartz => execute_extrinsic_in_sandbox::( + state, + &self.exec_params, + encoded_xts, + ), + + RuntimeId::Opal => execute_extrinsic_in_sandbox::( + state, + &self.exec_params, + encoded_xts, + ), + + runtime_id => Err(anyhow!("unknown runtime id {:?}", runtime_id).into()), + } + } +} + +fn full_extensions() -> Extensions { + let mut extensions = Extensions::default(); + extensions.register(TaskExecutorExt::new(TaskExecutor::new())); + let (offchain, _offchain_state) = TestOffchainExt::new(); + let (pool, _pool_state) = TestTransactionPoolExt::new(); + extensions.register(OffchainDbExt::new(offchain.clone())); + extensions.register(OffchainWorkerExt::new(offchain)); + extensions.register(KeystoreExt(std::sync::Arc::new(KeyStore::new()))); + extensions.register(TransactionPoolExt::new(pool)); + + extensions +} + +fn execute_extrinsic_in_sandbox( + state: StateOf, + exec_params: &ExecutorParams, + encoded_xts: Vec, +) -> Result +where + Block: BlockT, + D: NativeExecutionDispatch + 'static, +{ + let backend = state.as_trie_backend().clone(); + let mut changes = Default::default(); + let runtime_code_backend = sp_state_machine::backend::BackendRuntimeCode::new(backend); + + let proving_backend = TrieBackendBuilder::wrap(&backend) + .with_recorder(Default::default()) + .build(); + + let runtime_code = runtime_code_backend + .runtime_code() + .map_err(|_| anyhow!("runtime code backend creation failed"))?; + + let pre_root = *backend.root(); + + let executor = NativeElseWasmExecutor::::new( + exec_params.wasm_method, + exec_params.default_heap_pages, + exec_params.max_runtime_instances, + exec_params.runtime_cache_size, + ); + let execution = ExecutionStrategy::NativeElseWasm; + + let mut results = Vec::new(); + + for encoded_xt in encoded_xts { + let encoded_bytes = encoded_xt.encode(); + + let xt_result = StateMachine::new( + &proving_backend, + &mut changes, + &executor, + "PovEstimateApi_pov_estimate", + encoded_bytes.as_slice(), + full_extensions(), + &runtime_code, + sp_core::testing::TaskExecutor::new(), + ) + .execute(execution.into()) + .map_err(|e| anyhow!("failed to execute the extrinsic {:?}", e))?; + + let xt_result = Decode::decode(&mut &*xt_result) + .map_err(|e| anyhow!("failed to decode the extrinsic result {:?}", e))?; + + results.push(xt_result); + } + + let root = proving_backend.root().clone(); + + let proof = proving_backend + .extract_proof() + .expect("A recorder was set and thus, a storage proof can be extracted; qed"); + let proof_size = proof.encoded_size(); + + let memory_db = proof.clone().into_memory_db(); + + let tree_db = + TrieDBBuilder::>>::new(&memory_db, &root).build(); + + let key_values = tree_db + .iter() + .map_err(|e| anyhow!("failed to retrieve tree db key values: {:?}", e))? + .filter_map(|item| { + let item = item.ok()?; + + Some(TrieKeyValue { + key: item.0, + value: item.1, + }) + }) + .collect(); + + let compact_proof = proof + .clone() + .into_compact_proof::>(pre_root) + .map_err(|e| anyhow!("failed to generate compact proof {:?}", e))?; + let compact_proof_size = compact_proof.encoded_size(); + + let compressed_proof = zstd::stream::encode_all(&compact_proof.encode()[..], 0) + .map_err(|e| anyhow!("failed to generate compact proof {:?}", e))?; + let compressed_proof_size = compressed_proof.len(); + + Ok(PovInfo { + proof_size: proof_size as u64, + compact_proof_size: compact_proof_size as u64, + compressed_proof_size: compressed_proof_size as u64, + results, + key_values, + }) +} diff --git a/crates/evm-coder/CHANGELOG.md b/crates/evm-coder/CHANGELOG.md index 711280f911..69d264660a 100644 --- a/crates/evm-coder/CHANGELOG.md +++ b/crates/evm-coder/CHANGELOG.md @@ -2,22 +2,33 @@ All notable changes to this project will be documented in this file. -## [0.1.3] - 2022-08-29 + +## [v0.1.5] - 2022-11-30 + +### Added +- Derive macro to support structures and enums. + +## [v0.1.4] - 2022-11-02 + +### Added + +- Named structures support. + +## [v0.1.3] - 2022-08-29 ### Fixed - - Parsing simple values. +- Parsing simple values. - ## [v0.1.2] 2022-08-19 ### Added - - Implementation `AbiWrite` for tuples. +- Implementation `AbiWrite` for tuples. - ### Fixes +### Fixes - - Tuple generation for solidity. +- Tuple generation for solidity. ## [v0.1.1] 2022-08-16 diff --git a/crates/evm-coder/Cargo.toml b/crates/evm-coder/Cargo.toml index 5dcdc03330..8e5fe92a1e 100644 --- a/crates/evm-coder/Cargo.toml +++ b/crates/evm-coder/Cargo.toml @@ -1,28 +1,40 @@ [package] name = "evm-coder" -version = "0.1.3" +version = "0.1.5" license = "GPLv3" edition = "2021" [dependencies] +sha3-const = { version = "0.1.1", default-features = false } # evm-coder reexports those proc-macro evm-coder-procedural = { path = "./procedural" } # Evm uses primitive-types for H160, H256 and others -primitive-types = { version = "0.11.1", default-features = false } +primitive-types = { version = "0.12.1", default-features = false } # Evm doesn't have reexports for log and others -ethereum = { version = "0.12.0", default-features = false } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +ethereum = { version = "0.14.0", default-features = false } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } # Error types for execution -evm-core = { default-features = false , git = "https://github.com/uniquenetwork/evm", branch = "unique-polkadot-v0.9.30" } +evm-core = { default-features = false, git = "https://github.com/uniquenetwork/evm", branch = "unique-polkadot-v0.9.36" } # We have tuple-heavy code in solidity.rs impl-trait-for-tuples = "0.2.2" +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } + [dev-dependencies] # We want to assert some large binary blobs equality in tests hex = "0.4.3" hex-literal = "0.3.4" +similar-asserts = "1.4.2" +trybuild = "1.0" [features] default = ["std"] -std = ["ethereum/std", "primitive-types/std", "evm-core/std", "frame-support/std"] +std = [ + "ethereum/std", + "primitive-types/std", + "evm-core/std", + "frame-support/std", +] +# Stub/interface generation +stubgen = [] diff --git a/crates/evm-coder/procedural/Cargo.toml b/crates/evm-coder/procedural/Cargo.toml index 0b9956cd67..34d7a0fbd7 100644 --- a/crates/evm-coder/procedural/Cargo.toml +++ b/crates/evm-coder/procedural/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "evm-coder-procedural" -version = "0.2.0" +version = "0.2.2" license = "GPLv3" edition = "2021" diff --git a/crates/evm-coder/procedural/src/abi_derive/derive_enum.rs b/crates/evm-coder/procedural/src/abi_derive/derive_enum.rs new file mode 100644 index 0000000000..99cd8018eb --- /dev/null +++ b/crates/evm-coder/procedural/src/abi_derive/derive_enum.rs @@ -0,0 +1,199 @@ +use quote::quote; + +use super::extract_docs; + +pub fn impl_solidity_option<'a>( + docs: Vec, + name: &proc_macro2::Ident, + enum_options: impl Iterator + Clone, +) -> proc_macro2::TokenStream { + let variant_names = enum_options.clone().map(|opt| { + let opt = &opt.ident; + let s = name.to_string() + "." + opt.to_string().as_str(); + let as_string = proc_macro2::Literal::string(s.as_str()); + quote!(#name::#opt => #as_string,) + }); + let solidity_name = name.to_string(); + + let solidity_fields = enum_options.map(|v| { + let docs = extract_docs(&v.attrs).expect("TODO: handle bad docs"); + let name = v.ident.to_string(); + quote! { + SolidityEnumVariant { + docs: &[#(#docs),*], + name: #name, + } + } + }); + + quote!( + #[cfg(feature = "stubgen")] + impl ::evm_coder::solidity::SolidityEnumTy for #name { + fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector) -> String { + use evm_coder::solidity::*; + use core::fmt::Write; + let interface = SolidityEnum { + docs: &[#(#docs),*], + name: #solidity_name, + fields: &[#( + #solidity_fields, + )*], + }; + let mut out = String::new(); + let _ = interface.format(&mut out, tc); + tc.collect(out); + #solidity_name.to_string() + } + fn solidity_option(&self) -> &str { + match self { + #(#variant_names)* + } + } + } + ) +} + +pub fn impl_enum_from_u8<'a>( + name: &proc_macro2::Ident, + enum_options: impl Iterator, +) -> proc_macro2::TokenStream { + let error_str = format!("Value not convertible into enum \"{name}\""); + let error_str = proc_macro2::Literal::string(&error_str); + let enum_options = enum_options.enumerate().map(|(i, opt)| { + let opt = &opt.ident; + let n = proc_macro2::Literal::u8_suffixed(i as u8); + quote! {#n => Ok(#name::#opt),} + }); + + quote!( + impl TryFrom for #name { + type Error = &'static str; + + fn try_from(value: u8) -> ::core::result::Result { + const err: &'static str = #error_str; + match value { + #(#enum_options)* + _ => Err(err) + } + } + } + ) +} + +pub fn impl_enum_abi_type(name: &syn::Ident) -> proc_macro2::TokenStream { + quote! { + impl ::evm_coder::abi::AbiType for #name { + const SIGNATURE: ::evm_coder::custom_signature::SignatureUnit = ::SIGNATURE; + + fn is_dynamic() -> bool { + ::is_dynamic() + } + fn size() -> usize { + ::size() + } + } + } +} + +pub fn impl_enum_abi_read(name: &syn::Ident) -> proc_macro2::TokenStream { + quote!( + impl ::evm_coder::abi::AbiRead for #name { + fn abi_read(reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result { + Ok( + ::abi_read(reader)? + .try_into()? + ) + } + } + ) +} + +pub fn impl_enum_abi_write(name: &syn::Ident) -> proc_macro2::TokenStream { + quote!( + impl ::evm_coder::abi::AbiWrite for #name { + fn abi_write(&self, writer: &mut ::evm_coder::abi::AbiWriter) { + ::evm_coder::abi::AbiWrite::abi_write(&(*self as u8), writer); + } + } + ) +} + +pub fn impl_enum_solidity_type_name(name: &syn::Ident) -> proc_macro2::TokenStream { + quote!( + #[cfg(feature = "stubgen")] + impl ::evm_coder::solidity::SolidityTypeName for #name { + fn solidity_name( + writer: &mut impl ::core::fmt::Write, + tc: &::evm_coder::solidity::TypeCollector, + ) -> ::core::fmt::Result { + write!(writer, "{}", tc.collect_enum::()) + } + + fn is_simple() -> bool { + true + } + + fn solidity_default( + writer: &mut impl ::core::fmt::Write, + tc: &::evm_coder::solidity::TypeCollector, + ) -> ::core::fmt::Result { + write!(writer, "{}", <#name as ::evm_coder::solidity::SolidityEnumTy>::solidity_option(&<#name>::default())) + } + } + ) +} + +pub fn check_enum_fields(de: &syn::DataEnum) -> syn::Result<()> { + for v in de.variants.iter() { + if !v.fields.is_empty() { + return Err(syn::Error::new( + v.ident.span(), + "Enumeration parameters should not have fields", + )); + } else if v.discriminant.is_some() { + return Err(syn::Error::new( + v.ident.span(), + "Enumeration options should not have an explicit specified value", + )); + } + } + + Ok(()) +} + +pub fn check_repr_u8(name: &syn::Ident, attrs: &[syn::Attribute]) -> syn::Result<()> { + let mut has_repr = false; + for attr in attrs.iter() { + if attr.path.is_ident("repr") { + has_repr = true; + let meta = attr.parse_meta()?; + check_meta_u8(&meta)?; + } + } + + if !has_repr { + return Err(syn::Error::new(name.span(), "Enum is not \"repr(u8)\"")); + } + + Ok(()) +} + +fn check_meta_u8(meta: &syn::Meta) -> Result<(), syn::Error> { + if let syn::Meta::List(p) = meta { + for nm in p.nested.iter() { + if let syn::NestedMeta::Meta(syn::Meta::Path(p)) = nm { + if !p.is_ident("u8") { + return Err(syn::Error::new( + p.segments + .first() + .expect("repr segments are empty") + .ident + .span(), + "Enum is not \"repr(u8)\"", + )); + } + } + } + } + Ok(()) +} diff --git a/crates/evm-coder/procedural/src/abi_derive/derive_struct.rs b/crates/evm-coder/procedural/src/abi_derive/derive_struct.rs new file mode 100644 index 0000000000..4151deabcb --- /dev/null +++ b/crates/evm-coder/procedural/src/abi_derive/derive_struct.rs @@ -0,0 +1,231 @@ +use super::extract_docs; +use quote::quote; +use syn::Field; + +pub fn tuple_type<'a>( + field_types: impl Iterator + Clone, +) -> proc_macro2::TokenStream { + let field_types = field_types.map(|ty| quote!(#ty,)); + quote! {(#(#field_types)*)} +} + +pub fn tuple_ref_type<'a>( + field_types: impl Iterator + Clone, +) -> proc_macro2::TokenStream { + let field_types = field_types.map(|ty| quote!(&#ty,)); + quote! {(#(#field_types)*)} +} + +pub fn tuple_data_as_ref( + is_named_fields: bool, + field_names: impl Iterator + Clone, +) -> proc_macro2::TokenStream { + let field_names = field_names.enumerate().map(|(i, field)| { + if is_named_fields { + quote!(&self.#field,) + } else { + let field = proc_macro2::Literal::usize_unsuffixed(i); + quote!(&self.#field,) + } + }); + quote! {(#(#field_names)*)} +} + +pub fn tuple_names( + is_named_fields: bool, + field_names: impl Iterator + Clone, +) -> proc_macro2::TokenStream { + let field_names = field_names.enumerate().map(|(i, field)| { + if is_named_fields { + quote!(#field,) + } else { + let field = proc_macro2::Ident::new( + format!("field{}", i).as_str(), + proc_macro2::Span::call_site(), + ); + quote!(#field,) + } + }); + quote! {(#(#field_names)*)} +} + +pub fn struct_from_tuple( + name: &syn::Ident, + is_named_fields: bool, + field_names: impl Iterator + Clone, +) -> proc_macro2::TokenStream { + let field_names = field_names.enumerate().map(|(i, field)| { + if is_named_fields { + quote!(#field,) + } else { + let field = proc_macro2::Ident::new( + format!("field{}", i).as_str(), + proc_macro2::Span::call_site(), + ); + quote!(#field,) + } + }); + + if is_named_fields { + quote! {#name {#(#field_names)*}} + } else { + quote! {#name (#(#field_names)*)} + } +} + +pub fn map_field_to_name(field: (usize, &syn::Field)) -> syn::Ident { + match field.1.ident.as_ref() { + Some(name) => name.clone(), + None => { + let mut name = "field".to_string(); + name.push_str(field.0.to_string().as_str()); + syn::Ident::new(name.as_str(), proc_macro2::Span::call_site()) + } + } +} + +pub fn map_field_to_type(field: &syn::Field) -> &syn::Type { + &field.ty +} + +pub fn impl_can_be_placed_in_vec(ident: &syn::Ident) -> proc_macro2::TokenStream { + quote! { + impl ::evm_coder::sealed::CanBePlacedInVec for #ident {} + } +} + +pub fn impl_struct_abi_type( + name: &syn::Ident, + tuple_type: proc_macro2::TokenStream, +) -> proc_macro2::TokenStream { + quote! { + impl ::evm_coder::abi::AbiType for #name { + const SIGNATURE: ::evm_coder::custom_signature::SignatureUnit = <#tuple_type as ::evm_coder::abi::AbiType>::SIGNATURE; + fn is_dynamic() -> bool { + <#tuple_type as ::evm_coder::abi::AbiType>::is_dynamic() + } + fn size() -> usize { + <#tuple_type as ::evm_coder::abi::AbiType>::size() + } + } + } +} + +pub fn impl_struct_abi_read( + name: &syn::Ident, + tuple_type: proc_macro2::TokenStream, + tuple_names: proc_macro2::TokenStream, + struct_from_tuple: proc_macro2::TokenStream, +) -> proc_macro2::TokenStream { + quote!( + impl ::evm_coder::abi::AbiRead for #name { + fn abi_read(reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result { + let #tuple_names = <#tuple_type as ::evm_coder::abi::AbiRead>::abi_read(reader)?; + Ok(#struct_from_tuple) + } + } + ) +} + +pub fn impl_struct_abi_write( + name: &syn::Ident, + _is_named_fields: bool, + tuple_type: proc_macro2::TokenStream, + tuple_data: proc_macro2::TokenStream, +) -> proc_macro2::TokenStream { + quote!( + impl ::evm_coder::abi::AbiWrite for #name { + fn abi_write(&self, writer: &mut ::evm_coder::abi::AbiWriter) { + <#tuple_type as ::evm_coder::abi::AbiWrite>::abi_write(&#tuple_data, writer) + } + } + ) +} + +pub fn impl_struct_solidity_type<'a>( + name: &syn::Ident, + docs: Vec, + fields: impl Iterator + Clone, +) -> proc_macro2::TokenStream { + let solidity_name = name.to_string(); + let solidity_fields = fields.enumerate().map(|(i, f)| { + let name = f + .ident + .as_ref() + .map(|i| i.to_string()) + .unwrap_or_else(|| format!("field_{i}")); + let ty = &f.ty; + let docs = extract_docs(&f.attrs).expect("TODO: handle bad docs"); + quote! { + SolidityStructField::<#ty> { + docs: &[#(#docs),*], + name: #name, + ty: ::core::marker::PhantomData, + } + } + }); + quote! { + #[cfg(feature = "stubgen")] + impl ::evm_coder::solidity::SolidityStructTy for #name { + /// Generate solidity definitions for methods described in this struct + fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector) -> String { + use evm_coder::solidity::*; + use core::fmt::Write; + let interface = SolidityStruct { + docs: &[#(#docs),*], + name: #solidity_name, + fields: (#( + #solidity_fields, + )*), + }; + let mut out = String::new(); + let _ = interface.format(&mut out, tc); + tc.collect(out); + #solidity_name.to_string() + } + } + } +} + +pub fn impl_struct_solidity_type_name<'a>( + name: &syn::Ident, + field_types: impl Iterator + Clone, + params_count: usize, +) -> proc_macro2::TokenStream { + let arg_dafaults = field_types.enumerate().map(|(i, ty)| { + let mut defult_value = quote!(<#ty as ::evm_coder::solidity::SolidityTypeName + >::solidity_default(writer, tc)?;); + let last_item = params_count - 1; + if i != last_item { + defult_value.extend(quote! {write!(writer, ",")?;}) + } + defult_value + }); + + quote! { + #[cfg(feature = "stubgen")] + impl ::evm_coder::solidity::SolidityTypeName for #name { + fn solidity_name( + writer: &mut impl ::core::fmt::Write, + tc: &::evm_coder::solidity::TypeCollector, + ) -> ::core::fmt::Result { + write!(writer, "{}", tc.collect_struct::()) + } + + fn is_simple() -> bool { + false + } + + fn solidity_default( + writer: &mut impl ::core::fmt::Write, + tc: &::evm_coder::solidity::TypeCollector, + ) -> ::core::fmt::Result { + write!(writer, "{}(", tc.collect_struct::())?; + + #(#arg_dafaults)* + + write!(writer, ")") + } + } + } +} diff --git a/crates/evm-coder/procedural/src/abi_derive/mod.rs b/crates/evm-coder/procedural/src/abi_derive/mod.rs new file mode 100644 index 0000000000..74beff067c --- /dev/null +++ b/crates/evm-coder/procedural/src/abi_derive/mod.rs @@ -0,0 +1,118 @@ +mod derive_enum; +mod derive_struct; + +use quote::quote; +use derive_struct::*; +use derive_enum::*; + +pub(crate) fn impl_abi_macro(ast: &syn::DeriveInput) -> syn::Result { + let name = &ast.ident; + match &ast.data { + syn::Data::Struct(ds) => expand_struct(ds, ast), + syn::Data::Enum(de) => expand_enum(de, ast), + syn::Data::Union(_) => Err(syn::Error::new(name.span(), "Unions not supported")), + } +} + +fn expand_struct( + ds: &syn::DataStruct, + ast: &syn::DeriveInput, +) -> syn::Result { + let name = &ast.ident; + let docs = extract_docs(&ast.attrs)?; + let (is_named_fields, field_names, field_types, params_count) = match ds.fields { + syn::Fields::Named(ref fields) => Ok(( + true, + fields.named.iter().enumerate().map(map_field_to_name), + fields.named.iter().map(map_field_to_type), + fields.named.len(), + )), + syn::Fields::Unnamed(ref fields) => Ok(( + false, + fields.unnamed.iter().enumerate().map(map_field_to_name), + fields.unnamed.iter().map(map_field_to_type), + fields.unnamed.len(), + )), + syn::Fields::Unit => Err(syn::Error::new(name.span(), "Unit structs not supported")), + }?; + + if params_count == 0 { + return Err(syn::Error::new(name.span(), "Empty structs not supported")); + }; + + let tuple_type = tuple_type(field_types.clone()); + let tuple_ref_type = tuple_ref_type(field_types.clone()); + let tuple_data = tuple_data_as_ref(is_named_fields, field_names.clone()); + let tuple_names = tuple_names(is_named_fields, field_names.clone()); + let struct_from_tuple = struct_from_tuple(name, is_named_fields, field_names.clone()); + + let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name); + let abi_type = impl_struct_abi_type(name, tuple_type.clone()); + let abi_read = impl_struct_abi_read(name, tuple_type, tuple_names, struct_from_tuple); + let abi_write = impl_struct_abi_write(name, is_named_fields, tuple_ref_type, tuple_data); + let solidity_type = impl_struct_solidity_type(name, docs, ds.fields.iter()); + let solidity_type_name = + impl_struct_solidity_type_name(name, field_types.clone(), params_count); + + Ok(quote! { + #can_be_plcaed_in_vec + #abi_type + #abi_read + #abi_write + #solidity_type + #solidity_type_name + }) +} + +fn expand_enum( + de: &syn::DataEnum, + ast: &syn::DeriveInput, +) -> syn::Result { + let name = &ast.ident; + check_repr_u8(name, &ast.attrs)?; + check_enum_fields(de)?; + let docs = extract_docs(&ast.attrs)?; + let enum_options = de.variants.iter(); + + let from = impl_enum_from_u8(name, enum_options.clone()); + let solidity_option = impl_solidity_option(docs, name, enum_options.clone()); + let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name); + let abi_type = impl_enum_abi_type(name); + let abi_read = impl_enum_abi_read(name); + let abi_write = impl_enum_abi_write(name); + let solidity_type_name = impl_enum_solidity_type_name(name); + + Ok(quote! { + #from + #solidity_option + #can_be_plcaed_in_vec + #abi_type + #abi_read + #abi_write + #solidity_type_name + }) +} + +fn extract_docs(attrs: &[syn::Attribute]) -> syn::Result> { + attrs + .iter() + .filter_map(|attr| { + if let Some(ps) = attr.path.segments.first() { + if ps.ident == "doc" { + let meta = match attr.parse_meta() { + Ok(meta) => meta, + Err(e) => return Some(Err(e)), + }; + match meta { + syn::Meta::NameValue(mnv) => match &mnv.lit { + syn::Lit::Str(ls) => return Some(Ok(ls.value())), + _ => unreachable!(), + }, + _ => unreachable!(), + } + } + } + None + }) + .collect() +} diff --git a/crates/evm-coder/procedural/src/lib.rs b/crates/evm-coder/procedural/src/lib.rs index 63c916ca1c..889bee9bca 100644 --- a/crates/evm-coder/procedural/src/lib.rs +++ b/crates/evm-coder/procedural/src/lib.rs @@ -25,6 +25,7 @@ use syn::{ parse_macro_input, spanned::Spanned, }; +mod abi_derive; mod solidity_interface; mod to_log; @@ -107,7 +108,7 @@ fn parse_path_segment(path: &Path) -> syn::Result<&PathSegment> { if path.segments.len() != 1 { return Err(syn::Error::new( path.span(), - "expected path to have only segment", + "expected path to have only one segment", )); } let last_segment = &path.segments.last().unwrap(); @@ -242,3 +243,13 @@ pub fn to_log(value: TokenStream) -> TokenStream { } .into() } + +#[proc_macro_derive(AbiCoder)] +pub fn abi_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse(input).unwrap(); + let ts = match abi_derive::impl_abi_macro(&ast) { + Ok(e) => e, + Err(e) => e.to_compile_error(), + }; + ts.into() +} diff --git a/crates/evm-coder/procedural/src/solidity_interface.rs b/crates/evm-coder/procedural/src/solidity_interface.rs index 3bac1ae410..10180cf506 100644 --- a/crates/evm-coder/procedural/src/solidity_interface.rs +++ b/crates/evm-coder/procedural/src/solidity_interface.rs @@ -20,20 +20,20 @@ // about Procedural Macros in Rust book: // https://doc.rust-lang.org/reference/procedural-macros.html -use quote::{quote, ToTokens}; +use proc_macro2::TokenStream; +use quote::{quote, format_ident}; use inflector::cases; -use std::fmt::Write; use syn::{ - Expr, FnArg, GenericArgument, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Lit, Meta, - MetaNameValue, PatType, PathArguments, ReturnType, Type, + Expr, FnArg, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Lit, Meta, MetaNameValue, + PatType, ReturnType, Type, spanned::Spanned, parse::{Parse, ParseStream}, parenthesized, Token, LitInt, LitStr, }; use crate::{ - fn_selector_str, parse_ident_from_pat, parse_ident_from_path, parse_path, parse_path_segment, - parse_result_ok, pascal_ident_to_call, pascal_ident_to_snake_call, snake_ident_to_pascal, + parse_ident_from_pat, parse_ident_from_path, parse_path, parse_path_segment, parse_result_ok, + pascal_ident_to_call, pascal_ident_to_snake_call, snake_ident_to_pascal, snake_ident_to_screaming, }; @@ -328,155 +328,47 @@ impl Parse for MethodInfo { } } -enum AbiType { - // type - Plain(Ident), - // (type1,type2) - Tuple(Vec), - // type[] - Vec(Box), - // type[20] - Array(Box, usize), +trait AbiTypeHelper { + fn plain(&self) -> syn::Result<&Ident>; + fn is_value(&self) -> bool; + fn is_caller(&self) -> bool; + fn is_special(&self) -> bool; } -impl AbiType { - fn try_from(value: &Type) -> syn::Result { - let value = Self::try_maybe_special_from(value)?; - if value.is_special() { - return Err(syn::Error::new(value.span(), "unexpected special type")); - } - Ok(value) - } - fn try_maybe_special_from(value: &Type) -> syn::Result { - match value { - Type::Array(arr) => { - let wrapped = AbiType::try_from(&arr.elem)?; - match &arr.len { - Expr::Lit(l) => match &l.lit { - Lit::Int(i) => { - let num = i.base10_parse::()?; - Ok(AbiType::Array(Box::new(wrapped), num as usize)) - } - _ => Err(syn::Error::new(arr.len.span(), "should be int literal")), - }, - _ => Err(syn::Error::new(arr.len.span(), "should be literal")), - } - } - Type::Path(_) => { - let path = parse_path(value)?; - let segment = parse_path_segment(path)?; - if segment.ident == "Vec" { - let args = match &segment.arguments { - PathArguments::AngleBracketed(e) => e, - _ => { - return Err(syn::Error::new( - segment.arguments.span(), - "missing Vec generic", - )) - } - }; - let args = &args.args; - if args.len() != 1 { - return Err(syn::Error::new( - args.span(), - "expected only one generic for vec", - )); - } - let arg = args.first().expect("first arg"); - - let ty = match arg { - GenericArgument::Type(ty) => ty, - _ => { - return Err(syn::Error::new( - arg.span(), - "expected first generic to be type", - )) - } - }; - let wrapped = AbiType::try_from(ty)?; - Ok(Self::Vec(Box::new(wrapped))) - } else { - if !segment.arguments.is_empty() { - return Err(syn::Error::new( - segment.arguments.span(), - "unexpected generic arguments for non-vec type", - )); - } - Ok(Self::Plain(segment.ident.clone())) - } - } - Type::Tuple(t) => { - let mut out = Vec::with_capacity(t.elems.len()); - for el in t.elems.iter() { - out.push(AbiType::try_from(el)?) - } - Ok(Self::Tuple(out)) - } - _ => Err(syn::Error::new( - value.span(), - "unexpected type, only arrays, plain types and tuples are supported", - )), +impl AbiTypeHelper for Type { + fn plain(&self) -> syn::Result<&Ident> { + let path = parse_path(self)?; + let segment = parse_path_segment(path)?; + if !segment.arguments.is_empty() { + return Err(syn::Error::new(self.span(), "Not plain type")); } + Ok(&segment.ident) } + fn is_value(&self) -> bool { - matches!(self, Self::Plain(v) if v == "value") + if let Ok(ident) = self.plain() { + return ident == "value"; + } + false } + fn is_caller(&self) -> bool { - matches!(self, Self::Plain(v) if v == "caller") + if let Ok(ident) = self.plain() { + return ident == "caller"; + } + false } + fn is_special(&self) -> bool { self.is_caller() || self.is_value() } - fn selector_ty_buf(&self, buf: &mut String) -> std::fmt::Result { - match self { - AbiType::Plain(t) => { - write!(buf, "{}", t) - } - AbiType::Tuple(t) => { - write!(buf, "(")?; - for (i, t) in t.iter().enumerate() { - if i != 0 { - write!(buf, ",")?; - } - t.selector_ty_buf(buf)?; - } - write!(buf, ")") - } - AbiType::Vec(v) => { - v.selector_ty_buf(buf)?; - write!(buf, "[]") - } - AbiType::Array(v, len) => { - v.selector_ty_buf(buf)?; - write!(buf, "[{}]", len) - } - } - } - fn selector_ty(&self) -> String { - let mut out = String::new(); - self.selector_ty_buf(&mut out).expect("no fmt error"); - out - } -} -impl ToTokens for AbiType { - fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { - match self { - AbiType::Plain(t) => tokens.extend(quote! {#t}), - AbiType::Tuple(t) => { - tokens.extend(quote! {( - #(#t),* - )}); - } - AbiType::Vec(v) => tokens.extend(quote! {Vec<#v>}), - AbiType::Array(v, l) => tokens.extend(quote! {[#v; #l]}), - } - } } +#[derive(Debug)] struct MethodArg { name: Ident, camel_name: String, - ty: AbiType, + ty: Type, } impl MethodArg { fn try_from(value: &PatType) -> syn::Result { @@ -484,7 +376,7 @@ impl MethodArg { Ok(Self { camel_name: cases::camelcase::to_camel_case(&name.to_string()), name, - ty: AbiType::try_maybe_special_from(&value.ty)?, + ty: value.ty.as_ref().clone(), }) } fn is_value(&self) -> bool { @@ -496,10 +388,6 @@ impl MethodArg { fn is_special(&self) -> bool { self.ty.is_special() } - fn selector_ty(&self) -> String { - assert!(!self.is_special()); - self.ty.selector_ty() - } fn expand_call_def(&self) -> proc_macro2::TokenStream { assert!(!self.is_special()); @@ -514,8 +402,13 @@ impl MethodArg { fn expand_parse(&self) -> proc_macro2::TokenStream { assert!(!self.is_special()); let name = &self.name; + let ty = &self.ty; quote! { - #name: reader.abi_read()? + #name: { + let value = <#ty as ::evm_coder::abi::AbiRead>::abi_read(reader)?; + if !is_dynamic {reader.bytes_read(<#ty as ::evm_coder::abi::AbiType>::size())}; + value + } } } @@ -575,8 +468,6 @@ struct Method { camel_name: String, pascal_name: Ident, screaming_name: Ident, - selector_str: String, - selector: u32, hide: bool, args: Vec, has_normal_args: bool, @@ -667,27 +558,14 @@ impl Method { let camel_name = info .rename_selector .unwrap_or_else(|| cases::camelcase::to_camel_case(&ident.to_string())); - let mut selector_str = camel_name.clone(); - selector_str.push('('); - let mut has_normal_args = false; - for (i, arg) in args.iter().filter(|arg| !arg.is_special()).enumerate() { - if i != 0 { - selector_str.push(','); - } - write!(selector_str, "{}", arg.selector_ty()).unwrap(); - has_normal_args = true; - } + let has_normal_args = args.iter().filter(|arg| !arg.is_special()).count() != 0; let has_value_args = args.iter().any(|a| a.is_value()); - selector_str.push(')'); - let selector = fn_selector_str(&selector_str); Ok(Self { name: ident.clone(), camel_name, pascal_name: snake_ident_to_pascal(ident), screaming_name: snake_ident_to_screaming(ident), - selector_str, - selector, hide: info.hide, args, has_normal_args, @@ -718,17 +596,30 @@ impl Method { } } } else { - quote! {#pascal_name} + quote! { + #(#[doc = #docs])* + #[allow(missing_docs)] + #pascal_name + } } } fn expand_const(&self) -> proc_macro2::TokenStream { let screaming_name = &self.screaming_name; - let selector = u32::to_be_bytes(self.selector); - let selector_str = &self.selector_str; + let screaming_name_signature = format_ident!("{}_SIGNATURE", &self.screaming_name); + let custom_signature = self.expand_custom_signature(); quote! { - #[doc = #selector_str] - const #screaming_name: ::evm_coder::types::bytes4 = [#(#selector,)*]; + const #screaming_name_signature: ::evm_coder::custom_signature::SignatureUnit = #custom_signature; + const #screaming_name: ::evm_coder::types::bytes4 = { + let mut sum = ::evm_coder::sha3_const::Keccak256::new(); + let mut pos = 0; + while pos < Self::#screaming_name_signature.len { + sum = sum.update(&[Self::#screaming_name_signature.data[pos]; 1]); + pos += 1; + } + let a = sum.finalize(); + [a[0], a[1], a[2], a[3]] + }; } } @@ -743,17 +634,18 @@ impl Method { let pascal_name = &self.pascal_name; let screaming_name = &self.screaming_name; if self.has_normal_args { - let parsers = self - .args - .iter() - .filter(|a| !a.is_special()) - .map(|a| a.expand_parse()); + let args_iter = self.args.iter().filter(|a| !a.is_special()); + let arg_type = args_iter.clone().map(|a| &a.ty); + let parsers = args_iter.map(|a| a.expand_parse()); quote! { - Self::#screaming_name => return Ok(Some(Self::#pascal_name { - #( - #parsers, - )* - })) + Self::#screaming_name => { + let is_dynamic = false #(|| <#arg_type as ::evm_coder::abi::AbiType>::is_dynamic())*; + return Ok(Some(Self::#pascal_name { + #( + #parsers, + )* + })) + } } } else { quote! { Self::#screaming_name => return Ok(Some(Self::#pascal_name)) } @@ -788,6 +680,7 @@ impl Method { quote! { #call_name::#pascal_name #matcher => { + #[allow(deprecated)] let result = #receiver #name( #( #args, @@ -831,6 +724,26 @@ impl Method { } } + fn expand_custom_signature(&self) -> proc_macro2::TokenStream { + let mut args = TokenStream::new(); + + let mut has_params = false; + for arg in self.args.iter().filter(|a| !a.is_special()) { + has_params = true; + let ty = &arg.ty; + args.extend(quote! {nameof(<#ty>::SIGNATURE)}); + args.extend(quote! {fixed(",")}) + } + + // Remove trailing comma + if has_params { + args.extend(quote! {shift_left(1)}) + } + + let func_name = self.camel_name.clone(); + quote! { ::evm_coder::make_signature!(new fixed(#func_name) fixed("(") #args fixed(")")) } + } + fn expand_solidity_function(&self) -> proc_macro2::TokenStream { let camel_name = &self.camel_name; let mutability = match self.mutability { @@ -846,16 +759,17 @@ impl Method { .filter(|a| !a.is_special()) .map(MethodArg::expand_solidity_argument); let docs = &self.docs; - let selector_str = &self.selector_str; - let selector = self.selector; + let screaming_name = &self.screaming_name; let hide = self.hide; + let custom_signature = self.expand_custom_signature(); let is_payable = self.has_value_args; + quote! { SolidityFunction { docs: &[#(#docs),*], - selector_str: #selector_str, - selector: #selector, hide: #hide, + selector: u32::from_be_bytes(Self::#screaming_name), + custom_signature: #custom_signature, name: #camel_name, mutability: #mutability, is_payable: #is_payable, @@ -1019,34 +933,13 @@ impl SolidityInterface { .chain(self.info.inline_is.0.iter()) .map(|is| Is::expand_generator(is, &gen_ref)); let solidity_event_generators = self.info.events.0.iter().map(Is::expand_event_generator); - + let solidity_events_idents = self.info.events.0.iter().map(|is| is.name.clone()); let docs = &self.docs; - if let Some(expect_selector) = &self.info.expect_selector { - if !self.info.inline_is.0.is_empty() { - return syn::Error::new( - name.span(), - "expect_selector is not compatible with inline_is", - ) - .to_compile_error(); - } - let selector = self - .methods - .iter() - .map(|m| m.selector) - .fold(0, |a, b| a ^ b); - - if *expect_selector != selector { - let mut methods = String::new(); - for meth in self.methods.iter() { - write!(methods, "\n- {}", meth.selector_str).expect("write to string"); - } - return syn::Error::new(name.span(), format!("expected selector mismatch, expected {expect_selector:0>8x}, but implementation has {selector:0>8x}{methods}")).to_compile_error(); - } - } - // let methods = self.methods.iter().map(Method::solidity_def); - quote! { + #( + const _: ::core::marker::PhantomData<#solidity_events_idents> = ::core::marker::PhantomData; + )* #[derive(Debug)] #(#[doc = #docs])* pub enum #call_name #gen_ref { @@ -1071,6 +964,7 @@ impl SolidityInterface { u32::to_be_bytes(interface_id) } /// Generate solidity definitions for methods described in this interface + #[cfg(feature = "stubgen")] pub fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector, is_impl: bool) { use evm_coder::solidity::*; use core::fmt::Write; diff --git a/crates/evm-coder/procedural/src/to_log.rs b/crates/evm-coder/procedural/src/to_log.rs index 7fd8e0a76e..4b10ab8370 100644 --- a/crates/evm-coder/procedural/src/to_log.rs +++ b/crates/evm-coder/procedural/src/to_log.rs @@ -195,6 +195,8 @@ impl Events { #consts )* + /// Generate solidity definitions for methods described in this interface + #[cfg(feature = "stubgen")] pub fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector, is_impl: bool) { use evm_coder::solidity::*; use core::fmt::Write; diff --git a/crates/evm-coder/src/abi.rs b/crates/evm-coder/src/abi.rs deleted file mode 100644 index e1114333cb..0000000000 --- a/crates/evm-coder/src/abi.rs +++ /dev/null @@ -1,699 +0,0 @@ -// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. -// This file is part of Unique Network. - -// Unique Network is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Unique Network is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Unique Network. If not, see . - -//! Implementation of EVM RLP reader/writer - -#![allow(dead_code)] - -#[cfg(not(feature = "std"))] -use alloc::vec::Vec; -use evm_core::ExitError; -use primitive_types::{H160, U256}; - -use crate::{ - execution::{Error, ResultWithPostInfo, WithPostDispatchInfo}, - types::{string, self}, -}; -use crate::execution::Result; - -const ABI_ALIGNMENT: usize = 32; - -trait TypeHelper { - fn is_dynamic() -> bool; -} - -/// View into RLP data, which provides method to read typed items from it -#[derive(Clone)] -pub struct AbiReader<'i> { - buf: &'i [u8], - subresult_offset: usize, - offset: usize, -} -impl<'i> AbiReader<'i> { - /// Start reading RLP buffer, assuming there is no padding bytes - pub fn new(buf: &'i [u8]) -> Self { - Self { - buf, - subresult_offset: 0, - offset: 0, - } - } - /// Start reading RLP buffer, parsing first 4 bytes as selector - pub fn new_call(buf: &'i [u8]) -> Result<(types::bytes4, Self)> { - if buf.len() < 4 { - return Err(Error::Error(ExitError::OutOfOffset)); - } - let mut method_id = [0; 4]; - method_id.copy_from_slice(&buf[0..4]); - - Ok(( - method_id, - Self { - buf, - subresult_offset: 4, - offset: 4, - }, - )) - } - - fn read_pad( - buf: &[u8], - offset: usize, - pad_start: usize, - pad_size: usize, - block_start: usize, - block_size: usize, - ) -> Result<[u8; S]> { - if buf.len() - offset < ABI_ALIGNMENT { - return Err(Error::Error(ExitError::OutOfOffset)); - } - let mut block = [0; S]; - let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0); - if !is_pad_zeroed { - return Err(Error::Error(ExitError::InvalidRange)); - } - block.copy_from_slice(&buf[block_start..block_size]); - Ok(block) - } - - fn read_padleft(&mut self) -> Result<[u8; S]> { - let offset = self.offset; - self.offset += ABI_ALIGNMENT; - Self::read_pad( - self.buf, - offset, - offset, - offset + ABI_ALIGNMENT - S, - offset + ABI_ALIGNMENT - S, - offset + ABI_ALIGNMENT, - ) - } - - fn read_padright(&mut self) -> Result<[u8; S]> { - let offset = self.offset; - self.offset += ABI_ALIGNMENT; - Self::read_pad( - self.buf, - offset, - offset + S, - offset + ABI_ALIGNMENT, - offset, - offset + S, - ) - } - - /// Read [`H160`] at current position, then advance - pub fn address(&mut self) -> Result { - Ok(H160(self.read_padleft()?)) - } - - /// Read [`bool`] at current position, then advance - pub fn bool(&mut self) -> Result { - let data: [u8; 1] = self.read_padleft()?; - match data[0] { - 0 => Ok(false), - 1 => Ok(true), - _ => Err(Error::Error(ExitError::InvalidRange)), - } - } - - /// Read [`[u8; 4]`] at current position, then advance - pub fn bytes4(&mut self) -> Result<[u8; 4]> { - self.read_padright() - } - - /// Read [`Vec`] at current position, then advance - pub fn bytes(&mut self) -> Result> { - let mut subresult = self.subresult(None)?; - let length = subresult.uint32()? as usize; - if subresult.buf.len() < subresult.offset + length { - return Err(Error::Error(ExitError::OutOfOffset)); - } - Ok(subresult.buf[subresult.offset..subresult.offset + length].into()) - } - - /// Read [`string`] at current position, then advance - pub fn string(&mut self) -> Result { - string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange)) - } - - /// Read [`u8`] at current position, then advance - pub fn uint8(&mut self) -> Result { - Ok(self.read_padleft::<1>()?[0]) - } - - /// Read [`u32`] at current position, then advance - pub fn uint32(&mut self) -> Result { - Ok(u32::from_be_bytes(self.read_padleft()?)) - } - - /// Read [`u128`] at current position, then advance - pub fn uint128(&mut self) -> Result { - Ok(u128::from_be_bytes(self.read_padleft()?)) - } - - /// Read [`U256`] at current position, then advance - pub fn uint256(&mut self) -> Result { - let buf: [u8; 32] = self.read_padleft()?; - Ok(U256::from_big_endian(&buf)) - } - - /// Read [`u64`] at current position, then advance - pub fn uint64(&mut self) -> Result { - Ok(u64::from_be_bytes(self.read_padleft()?)) - } - - /// Read [`usize`] at current position, then advance - #[deprecated = "dangerous, as usize may have different width in wasm and native execution"] - pub fn read_usize(&mut self) -> Result { - Ok(usize::from_be_bytes(self.read_padleft()?)) - } - - /// Slice recursive buffer, advance one word for buffer offset - /// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`]. - fn subresult(&mut self, size: Option) -> Result> { - let subresult_offset = self.subresult_offset; - let offset = if let Some(size) = size { - self.offset += size; - self.subresult_offset += size; - 0 - } else { - self.uint32()? as usize - }; - - if offset + self.subresult_offset > self.buf.len() { - return Err(Error::Error(ExitError::InvalidRange)); - } - - let new_offset = offset + subresult_offset; - Ok(AbiReader { - buf: self.buf, - subresult_offset: new_offset, - offset: new_offset, - }) - } - - /// Is this parser reached end of buffer? - pub fn is_finished(&self) -> bool { - self.buf.len() == self.offset - } -} - -/// Writer for RLP encoded data -#[derive(Default)] -pub struct AbiWriter { - static_part: Vec, - dynamic_part: Vec<(usize, AbiWriter)>, - had_call: bool, -} -impl AbiWriter { - /// Initialize internal buffers for output data, assuming no padding required - pub fn new() -> Self { - Self::default() - } - /// Initialize internal buffers, inserting method selector at beginning - pub fn new_call(method_id: u32) -> Self { - let mut val = Self::new(); - val.static_part.extend(&method_id.to_be_bytes()); - val.had_call = true; - val - } - - fn write_padleft(&mut self, block: &[u8]) { - assert!(block.len() <= ABI_ALIGNMENT); - self.static_part - .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]); - self.static_part.extend(block); - } - - fn write_padright(&mut self, bytes: &[u8]) { - assert!(bytes.len() <= ABI_ALIGNMENT); - self.static_part.extend(bytes); - self.static_part - .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]); - } - - /// Write [`H160`] to end of buffer - pub fn address(&mut self, address: &H160) { - self.write_padleft(&address.0) - } - - /// Write [`bool`] to end of buffer - pub fn bool(&mut self, value: &bool) { - self.write_padleft(&[if *value { 1 } else { 0 }]) - } - - /// Write [`u8`] to end of buffer - pub fn uint8(&mut self, value: &u8) { - self.write_padleft(&[*value]) - } - - /// Write [`u32`] to end of buffer - pub fn uint32(&mut self, value: &u32) { - self.write_padleft(&u32::to_be_bytes(*value)) - } - - /// Write [`u128`] to end of buffer - pub fn uint128(&mut self, value: &u128) { - self.write_padleft(&u128::to_be_bytes(*value)) - } - - /// Write [`U256`] to end of buffer - pub fn uint256(&mut self, value: &U256) { - let mut out = [0; 32]; - value.to_big_endian(&mut out); - self.write_padleft(&out) - } - - /// Write [`usize`] to end of buffer - #[deprecated = "dangerous, as usize may have different width in wasm and native execution"] - pub fn write_usize(&mut self, value: &usize) { - self.write_padleft(&usize::to_be_bytes(*value)) - } - - /// Append recursive data, writing pending offset at end of buffer - pub fn write_subresult(&mut self, result: Self) { - self.dynamic_part.push((self.static_part.len(), result)); - // Empty block, to be filled later - self.write_padleft(&[]); - } - - fn memory(&mut self, value: &[u8]) { - let mut sub = Self::new(); - sub.uint32(&(value.len() as u32)); - for chunk in value.chunks(ABI_ALIGNMENT) { - sub.write_padright(chunk); - } - self.write_subresult(sub); - } - - /// Append recursive [`str`] at end of buffer - pub fn string(&mut self, value: &str) { - self.memory(value.as_bytes()) - } - - /// Append recursive [`[u8]`] at end of buffer - pub fn bytes(&mut self, value: &[u8]) { - self.memory(value) - } - - /// Finish writer, concatenating all internal buffers - pub fn finish(mut self) -> Vec { - for (static_offset, part) in self.dynamic_part { - let part_offset = self.static_part.len() - if self.had_call { 4 } else { 0 }; - - let encoded_dynamic_offset = usize::to_be_bytes(part_offset); - self.static_part[static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len() - ..static_offset + ABI_ALIGNMENT] - .copy_from_slice(&encoded_dynamic_offset); - self.static_part.extend(part.finish()) - } - self.static_part - } -} - -/// [`AbiReader`] implements reading of many types, but it should -/// be limited to types defined in spec -/// -/// As this trait can't be made sealed, -/// instead of having `impl AbiRead for T`, we have `impl AbiRead for AbiReader` -pub trait AbiRead { - /// Read item from current position, advanding decoder - fn abi_read(&mut self) -> Result; - - /// Size for type aligned to [`ABI_ALIGNMENT`]. - fn size() -> usize; -} - -macro_rules! impl_abi_readable { - ($ty:ty, $method:ident, $dynamic:literal) => { - impl TypeHelper for $ty { - fn is_dynamic() -> bool { - $dynamic - } - } - impl AbiRead<$ty> for AbiReader<'_> { - fn abi_read(&mut self) -> Result<$ty> { - self.$method() - } - - fn size() -> usize { - ABI_ALIGNMENT - } - } - }; -} - -impl_abi_readable!(u8, uint8, false); -impl_abi_readable!(u32, uint32, false); -impl_abi_readable!(u64, uint64, false); -impl_abi_readable!(u128, uint128, false); -impl_abi_readable!(U256, uint256, false); -impl_abi_readable!([u8; 4], bytes4, false); -impl_abi_readable!(H160, address, false); -impl_abi_readable!(Vec, bytes, true); -impl_abi_readable!(bool, bool, true); -impl_abi_readable!(string, string, true); - -mod sealed { - /// Not all types can be placed in vec, i.e `Vec` is restricted, `bytes` should be used instead - pub trait CanBePlacedInVec {} -} - -impl sealed::CanBePlacedInVec for U256 {} -impl sealed::CanBePlacedInVec for string {} -impl sealed::CanBePlacedInVec for H160 {} - -impl AbiRead> for AbiReader<'_> -where - Self: AbiRead, -{ - fn abi_read(&mut self) -> Result> { - let mut sub = self.subresult(None)?; - let size = sub.uint32()? as usize; - sub.subresult_offset = sub.offset; - let mut out = Vec::with_capacity(size); - for _ in 0..size { - out.push(>::abi_read(&mut sub)?); - } - Ok(out) - } - - fn size() -> usize { - ABI_ALIGNMENT - } -} - -macro_rules! impl_tuples { - ($($ident:ident)+) => { - impl<$($ident: TypeHelper,)+> TypeHelper for ($($ident,)+) { - fn is_dynamic() -> bool { - false - $( - || <$ident>::is_dynamic() - )* - } - } - impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {} - impl<$($ident),+> AbiRead<($($ident,)+)> for AbiReader<'_> - where - $( - Self: AbiRead<$ident>, - )+ - ($($ident,)+): TypeHelper, - { - fn abi_read(&mut self) -> Result<($($ident,)+)> { - let size = if !<($($ident,)+)>::is_dynamic() { Some(>::size()) } else { None }; - let mut subresult = self.subresult(size)?; - Ok(( - $(>::abi_read(&mut subresult)?,)+ - )) - } - - fn size() -> usize { - 0 $(+ as AbiRead<$ident>>::size())+ - } - } - #[allow(non_snake_case)] - impl<$($ident),+> AbiWrite for &($($ident,)+) - where - $($ident: AbiWrite,)+ - { - fn abi_write(&self, writer: &mut AbiWriter) { - let ($($ident,)+) = self; - $($ident.abi_write(writer);)+ - } - } - }; -} - -impl_tuples! {A} -impl_tuples! {A B} -impl_tuples! {A B C} -impl_tuples! {A B C D} -impl_tuples! {A B C D E} -impl_tuples! {A B C D E F} -impl_tuples! {A B C D E F G} -impl_tuples! {A B C D E F G H} -impl_tuples! {A B C D E F G H I} -impl_tuples! {A B C D E F G H I J} - -/// For questions about inability to provide custom implementations, -/// see [`AbiRead`] -pub trait AbiWrite { - /// Write value to end of specified encoder - fn abi_write(&self, writer: &mut AbiWriter); - /// Specialization for [`crate::solidity_interface`] implementation, - /// see comment in `impl AbiWrite for ResultWithPostInfo` - fn to_result(&self) -> ResultWithPostInfo { - let mut writer = AbiWriter::new(); - self.abi_write(&mut writer); - Ok(writer.into()) - } -} - -/// This particular AbiWrite implementation should be split to another trait, -/// which only implements `to_result`, but due to lack of specialization feature -/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`, -/// so here we abusing default trait methods for it -impl AbiWrite for ResultWithPostInfo { - fn abi_write(&self, _writer: &mut AbiWriter) { - debug_assert!(false, "shouldn't be called, see comment") - } - fn to_result(&self) -> ResultWithPostInfo { - match self { - Ok(v) => Ok(WithPostDispatchInfo { - post_info: v.post_info.clone(), - data: { - let mut out = AbiWriter::new(); - v.data.abi_write(&mut out); - out - }, - }), - Err(e) => Err(e.clone()), - } - } -} - -macro_rules! impl_abi_writeable { - ($ty:ty, $method:ident) => { - impl AbiWrite for $ty { - fn abi_write(&self, writer: &mut AbiWriter) { - writer.$method(&self) - } - } - }; -} - -impl_abi_writeable!(u8, uint8); -impl_abi_writeable!(u32, uint32); -impl_abi_writeable!(u128, uint128); -impl_abi_writeable!(U256, uint256); -impl_abi_writeable!(H160, address); -impl_abi_writeable!(bool, bool); -impl_abi_writeable!(&str, string); -impl AbiWrite for &string { - fn abi_write(&self, writer: &mut AbiWriter) { - writer.string(self) - } -} -impl AbiWrite for &Vec { - fn abi_write(&self, writer: &mut AbiWriter) { - writer.bytes(self) - } -} - -impl AbiWrite for () { - fn abi_write(&self, _writer: &mut AbiWriter) {} -} - -/// Helper macros to parse reader into variables -#[deprecated] -#[macro_export] -macro_rules! abi_decode { - ($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => { - $( - let $name = $reader.$typ()?; - )+ - } -} - -/// Helper macros to construct RLP-encoded buffer -#[deprecated] -#[macro_export] -macro_rules! abi_encode { - ($($typ:ident($value:expr)),* $(,)?) => {{ - #[allow(unused_mut)] - let mut writer = ::evm_coder::abi::AbiWriter::new(); - $( - writer.$typ($value); - )* - writer - }}; - (call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{ - #[allow(unused_mut)] - let mut writer = ::evm_coder::abi::AbiWriter::new_call($val); - $( - writer.$typ($value); - )* - writer - }} -} - -#[cfg(test)] -pub mod test { - use crate::{ - abi::AbiRead, - types::{string, uint256}, - }; - - use super::{AbiReader, AbiWriter}; - use hex_literal::hex; - - #[test] - fn dynamic_after_static() { - let mut encoder = AbiWriter::new(); - encoder.bool(&true); - encoder.string("test"); - let encoded = encoder.finish(); - - let mut encoder = AbiWriter::new(); - encoder.bool(&true); - // Offset to subresult - encoder.uint32(&(32 * 2)); - // Len of "test" - encoder.uint32(&4); - encoder.write_padright(&[b't', b'e', b's', b't']); - let alternative_encoded = encoder.finish(); - - assert_eq!(encoded, alternative_encoded); - - let mut decoder = AbiReader::new(&encoded); - assert!(decoder.bool().unwrap()); - assert_eq!(decoder.string().unwrap(), "test"); - } - - #[test] - fn mint_sample() { - let (call, mut decoder) = AbiReader::new_call(&hex!( - " - 50bb4e7f - 000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374 - 0000000000000000000000000000000000000000000000000000000000000001 - 0000000000000000000000000000000000000000000000000000000000000060 - 0000000000000000000000000000000000000000000000000000000000000008 - 5465737420555249000000000000000000000000000000000000000000000000 - " - )) - .unwrap(); - assert_eq!(call, u32::to_be_bytes(0x50bb4e7f)); - assert_eq!( - format!("{:?}", decoder.address().unwrap()), - "0xad2c0954693c2b5404b7e50967d3481bea432374" - ); - assert_eq!(decoder.uint32().unwrap(), 1); - assert_eq!(decoder.string().unwrap(), "Test URI"); - } - - #[test] - fn mint_bulk() { - let (call, mut decoder) = AbiReader::new_call(&hex!( - " - 36543006 - 00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address - 0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[] - 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[] - - 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem - 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem - 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem - - 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60 - 0000000000000000000000000000000000000000000000000000000000000040 // offset of string - 000000000000000000000000000000000000000000000000000000000000000a // size of string - 5465737420555249203000000000000000000000000000000000000000000000 // string - - 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0 - 0000000000000000000000000000000000000000000000000000000000000040 // offset of string - 000000000000000000000000000000000000000000000000000000000000000a // size of string - 5465737420555249203100000000000000000000000000000000000000000000 // string - - 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160 - 0000000000000000000000000000000000000000000000000000000000000040 // offset of string - 000000000000000000000000000000000000000000000000000000000000000a // size of string - 5465737420555249203200000000000000000000000000000000000000000000 // string - " - )) - .unwrap(); - assert_eq!(call, u32::to_be_bytes(0x36543006)); - let _ = decoder.address().unwrap(); - let data = - as AbiRead>>::abi_read(&mut decoder).unwrap(); - assert_eq!( - data, - vec![ - (1.into(), "Test URI 0".to_string()), - (11.into(), "Test URI 1".to_string()), - (12.into(), "Test URI 2".to_string()) - ] - ); - } - - #[test] - fn parse_vec_with_simple_type() { - use crate::types::address; - use primitive_types::{H160, U256}; - - let (call, mut decoder) = AbiReader::new_call(&hex!( - " - 1ACF2D55 - 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[] - 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[] - - 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address - 000000000000000000000000000000000000000000000000000000000000000A // uint256 - - 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address - 0000000000000000000000000000000000000000000000000000000000000014 // uint256 - - 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address - 000000000000000000000000000000000000000000000000000000000000001E // uint256 - " - )) - .unwrap(); - assert_eq!(call, u32::to_be_bytes(0x1ACF2D55)); - let data = - as AbiRead>>::abi_read(&mut decoder).unwrap(); - assert_eq!(data.len(), 3); - assert_eq!( - data, - vec![ - ( - H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")), - U256([10, 0, 0, 0]) - ), - ( - H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")), - U256([20, 0, 0, 0]) - ), - ( - H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")), - U256([30, 0, 0, 0]) - ), - ] - ); - } -} diff --git a/crates/evm-coder/src/abi/impls.rs b/crates/evm-coder/src/abi/impls.rs new file mode 100644 index 0000000000..4c7e967081 --- /dev/null +++ b/crates/evm-coder/src/abi/impls.rs @@ -0,0 +1,260 @@ +use crate::{ + custom_signature::SignatureUnit, + execution::{Result, ResultWithPostInfo, WithPostDispatchInfo}, + make_signature, sealed, + types::*, +}; +use super::{traits::*, ABI_ALIGNMENT, AbiReader, AbiWriter}; +use primitive_types::{U256, H160}; + +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + +macro_rules! impl_abi_type { + ($ty:ty, $name:ident, $dynamic:literal) => { + impl sealed::CanBePlacedInVec for $ty {} + + impl AbiType for $ty { + const SIGNATURE: SignatureUnit = make_signature!(new fixed(stringify!($name))); + + fn is_dynamic() -> bool { + $dynamic + } + + fn size() -> usize { + ABI_ALIGNMENT + } + } + }; +} + +macro_rules! impl_abi_readable { + ($ty:ty, $method:ident) => { + impl AbiRead for $ty { + fn abi_read(reader: &mut AbiReader) -> Result<$ty> { + reader.$method() + } + } + }; +} + +macro_rules! impl_abi_writeable { + ($ty:ty, $method:ident) => { + impl AbiWrite for $ty { + fn abi_write(&self, writer: &mut AbiWriter) { + writer.$method(&self) + } + } + }; +} + +macro_rules! impl_abi { + ($ty:ty, $method:ident, $dynamic:literal) => { + impl_abi_type!($ty, $method, $dynamic); + impl_abi_readable!($ty, $method); + impl_abi_writeable!($ty, $method); + }; +} + +impl_abi!(bool, bool, false); +impl_abi!(u8, uint8, false); +impl_abi!(u32, uint32, false); +impl_abi!(u64, uint64, false); +impl_abi!(u128, uint128, false); +impl_abi!(U256, uint256, false); +impl_abi!(H160, address, false); +impl_abi!(string, string, true); + +impl_abi_writeable!(&str, string); + +impl_abi_type!(bytes, bytes, true); + +impl AbiRead for bytes { + fn abi_read(reader: &mut AbiReader) -> Result { + Ok(bytes(reader.bytes()?)) + } +} + +impl AbiWrite for bytes { + fn abi_write(&self, writer: &mut AbiWriter) { + writer.bytes(self.0.as_slice()) + } +} + +impl_abi_type!(bytes4, bytes4, false); +impl AbiRead for bytes4 { + fn abi_read(reader: &mut AbiReader) -> Result { + reader.bytes4() + } +} + +impl AbiWrite for &T { + fn abi_write(&self, writer: &mut AbiWriter) { + T::abi_write(self, writer); + } +} + +impl AbiType for &T { + const SIGNATURE: SignatureUnit = T::SIGNATURE; + + fn is_dynamic() -> bool { + T::is_dynamic() + } + + fn size() -> usize { + T::size() + } +} + +impl AbiRead for Vec { + fn abi_read(reader: &mut AbiReader) -> Result> { + let mut sub = reader.subresult(None)?; + let size = sub.uint32()? as usize; + sub.subresult_offset = sub.offset; + let is_dynamic = ::is_dynamic(); + let mut out = Vec::with_capacity(size); + for _ in 0..size { + out.push(::abi_read(&mut sub)?); + if !is_dynamic { + sub.bytes_read(::size()); + }; + } + Ok(out) + } +} + +impl AbiType for Vec { + const SIGNATURE: SignatureUnit = make_signature!(new nameof(T::SIGNATURE) fixed("[]")); + + fn is_dynamic() -> bool { + true + } + + fn size() -> usize { + ABI_ALIGNMENT + } +} + +impl AbiWrite for Vec { + fn abi_write(&self, writer: &mut AbiWriter) { + let is_dynamic = T::is_dynamic(); + let mut sub = if is_dynamic { + AbiWriter::new_dynamic(is_dynamic) + } else { + AbiWriter::new() + }; + + // Write items count + (self.len() as u32).abi_write(&mut sub); + + for item in self { + item.abi_write(&mut sub); + } + writer.write_subresult(sub); + } +} + +impl AbiWrite for () { + fn abi_write(&self, _writer: &mut AbiWriter) {} +} + +/// This particular AbiWrite implementation should be split to another trait, +/// which only implements `to_result`, but due to lack of specialization feature +/// in stable Rust, we can't have blanket impl of this trait `for T where T: AbiWrite`, +/// so here we abusing default trait methods for it +impl AbiWrite for ResultWithPostInfo { + fn abi_write(&self, _writer: &mut AbiWriter) { + debug_assert!(false, "shouldn't be called, see comment") + } + fn to_result(&self) -> ResultWithPostInfo { + match self { + Ok(v) => Ok(WithPostDispatchInfo { + post_info: v.post_info.clone(), + data: { + let mut out = AbiWriter::new(); + v.data.abi_write(&mut out); + out + }, + }), + Err(e) => Err(e.clone()), + } + } +} + +macro_rules! impl_tuples { + ($($ident:ident)+) => { + impl<$($ident: AbiType,)+> AbiType for ($($ident,)+) + where + $( + $ident: AbiType, + )+ + { + const SIGNATURE: SignatureUnit = make_signature!( + new fixed("(") + $(nameof(<$ident>::SIGNATURE) fixed(","))+ + shift_left(1) + fixed(")") + ); + + fn is_dynamic() -> bool { + false + $( + || <$ident>::is_dynamic() + )* + } + + fn size() -> usize { + 0 $(+ <$ident>::size())+ + } + } + + impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {} + + impl<$($ident),+> AbiRead for ($($ident,)+) + where + Self: AbiType, + $($ident: AbiRead + AbiType,)+ + { + fn abi_read(reader: &mut AbiReader) -> Result<($($ident,)+)> { + let is_dynamic = ::is_dynamic(); + let size = if !is_dynamic { Some(::size()) } else { None }; + let mut subresult = reader.subresult(size)?; + Ok(( + $({ + let value = <$ident>::abi_read(&mut subresult)?; + if !is_dynamic {subresult.bytes_read(<$ident as AbiType>::size())}; + value + },)+ + )) + } + } + + #[allow(non_snake_case)] + impl<$($ident),+> AbiWrite for ($($ident,)+) + where + $($ident: AbiWrite + AbiType,)+ + { + fn abi_write(&self, writer: &mut AbiWriter) { + let ($($ident,)+) = self; + if ::is_dynamic() { + let mut sub = AbiWriter::new(); + $($ident.abi_write(&mut sub);)+ + writer.write_subresult(sub); + } else { + $($ident.abi_write(writer);)+ + } + } + } + }; +} + +impl_tuples! {A} +impl_tuples! {A B} +impl_tuples! {A B C} +impl_tuples! {A B C D} +impl_tuples! {A B C D E} +impl_tuples! {A B C D E F} +impl_tuples! {A B C D E F G} +impl_tuples! {A B C D E F G H} +impl_tuples! {A B C D E F G H I} +impl_tuples! {A B C D E F G H I J} diff --git a/crates/evm-coder/src/abi/mod.rs b/crates/evm-coder/src/abi/mod.rs new file mode 100644 index 0000000000..201974d932 --- /dev/null +++ b/crates/evm-coder/src/abi/mod.rs @@ -0,0 +1,348 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +//! Implementation of EVM RLP reader/writer + +#![allow(dead_code)] + +mod traits; +pub use traits::*; +mod impls; + +#[cfg(test)] +mod test; + +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; +use evm_core::ExitError; +use primitive_types::{H160, U256}; + +use crate::{ + execution::{Result, Error}, + types::*, +}; + +const ABI_ALIGNMENT: usize = 32; + +/// View into RLP data, which provides method to read typed items from it +#[derive(Clone)] +pub struct AbiReader<'i> { + buf: &'i [u8], + subresult_offset: usize, + offset: usize, +} +impl<'i> AbiReader<'i> { + /// Start reading RLP buffer, assuming there is no padding bytes + pub fn new(buf: &'i [u8]) -> Self { + Self { + buf, + subresult_offset: 0, + offset: 0, + } + } + /// Start reading RLP buffer, parsing first 4 bytes as selector + pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> { + if buf.len() < 4 { + return Err(Error::Error(ExitError::OutOfOffset)); + } + let mut method_id = [0; 4]; + method_id.copy_from_slice(&buf[0..4]); + + Ok(( + method_id, + Self { + buf, + subresult_offset: 4, + offset: 4, + }, + )) + } + + fn read_pad( + buf: &[u8], + offset: usize, + pad_start: usize, + pad_end: usize, + block_start: usize, + block_end: usize, + ) -> Result<[u8; S]> { + if buf.len() - offset < ABI_ALIGNMENT { + return Err(Error::Error(ExitError::OutOfOffset)); + } + let mut block = [0; S]; + let is_pad_zeroed = buf[pad_start..pad_end].iter().all(|&v| v == 0); + if !is_pad_zeroed { + return Err(Error::Error(ExitError::InvalidRange)); + } + block.copy_from_slice(&buf[block_start..block_end]); + Ok(block) + } + + fn read_padleft(&mut self) -> Result<[u8; S]> { + let offset = self.offset; + self.offset += ABI_ALIGNMENT; + Self::read_pad( + self.buf, + offset, + offset, + offset + ABI_ALIGNMENT - S, + offset + ABI_ALIGNMENT - S, + offset + ABI_ALIGNMENT, + ) + } + + fn read_padright(&mut self) -> Result<[u8; S]> { + let offset = self.offset; + self.offset += ABI_ALIGNMENT; + Self::read_pad( + self.buf, + offset, + offset + S, + offset + ABI_ALIGNMENT, + offset, + offset + S, + ) + } + + /// Read [`H160`] at current position, then advance + pub fn address(&mut self) -> Result { + Ok(H160(self.read_padleft()?)) + } + + /// Read [`bool`] at current position, then advance + pub fn bool(&mut self) -> Result { + let data: [u8; 1] = self.read_padleft()?; + match data[0] { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(Error::Error(ExitError::InvalidRange)), + } + } + + /// Read [`[u8; 4]`] at current position, then advance + pub fn bytes4(&mut self) -> Result<[u8; 4]> { + self.read_padright() + } + + /// Read [`Vec`] at current position, then advance + pub fn bytes(&mut self) -> Result> { + let mut subresult = self.subresult(None)?; + let length = subresult.uint32()? as usize; + if subresult.buf.len() < subresult.offset + length { + return Err(Error::Error(ExitError::OutOfOffset)); + } + Ok(subresult.buf[subresult.offset..subresult.offset + length].into()) + } + + /// Read [`string`] at current position, then advance + pub fn string(&mut self) -> Result { + string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange)) + } + + /// Read [`u8`] at current position, then advance + pub fn uint8(&mut self) -> Result { + Ok(self.read_padleft::<1>()?[0]) + } + + /// Read [`u32`] at current position, then advance + pub fn uint32(&mut self) -> Result { + Ok(u32::from_be_bytes(self.read_padleft()?)) + } + + /// Read [`u128`] at current position, then advance + pub fn uint128(&mut self) -> Result { + Ok(u128::from_be_bytes(self.read_padleft()?)) + } + + /// Read [`U256`] at current position, then advance + pub fn uint256(&mut self) -> Result { + let buf: [u8; 32] = self.read_padleft()?; + Ok(U256::from_big_endian(&buf)) + } + + /// Read [`u64`] at current position, then advance + pub fn uint64(&mut self) -> Result { + Ok(u64::from_be_bytes(self.read_padleft()?)) + } + + /// Read [`usize`] at current position, then advance + #[deprecated = "dangerous, as usize may have different width in wasm and native execution"] + pub fn read_usize(&mut self) -> Result { + Ok(usize::from_be_bytes(self.read_padleft()?)) + } + + /// Slice recursive buffer, advance one word for buffer offset + /// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`]. + pub fn subresult(&mut self, size: Option) -> Result> { + let subresult_offset = self.subresult_offset; + let offset = if let Some(size) = size { + self.offset += size; + 0 + } else { + self.uint32()? as usize + }; + + if offset + self.subresult_offset > self.buf.len() { + return Err(Error::Error(ExitError::InvalidRange)); + } + + let new_offset = offset + subresult_offset; + Ok(AbiReader { + buf: self.buf, + subresult_offset: new_offset, + offset: new_offset, + }) + } + + /// Notify about readed data portion. + pub fn bytes_read(&mut self, size: usize) { + self.subresult_offset += size; + } + + /// Is this parser reached end of buffer? + pub fn is_finished(&self) -> bool { + self.buf.len() == self.offset + } +} + +/// Writer for RLP encoded data +#[derive(Default)] +pub struct AbiWriter { + static_part: Vec, + dynamic_part: Vec<(usize, AbiWriter)>, + had_call: bool, + is_dynamic: bool, +} +impl AbiWriter { + /// Initialize internal buffers for output data, assuming no padding required + pub fn new() -> Self { + Self::default() + } + + /// Initialize internal buffers with data size + pub fn new_dynamic(is_dynamic: bool) -> Self { + Self { + is_dynamic, + ..Default::default() + } + } + /// Initialize internal buffers, inserting method selector at beginning + pub fn new_call(method_id: u32) -> Self { + let mut val = Self::new(); + val.static_part.extend(&method_id.to_be_bytes()); + val.had_call = true; + val + } + + fn write_padleft(&mut self, block: &[u8]) { + assert!(block.len() <= ABI_ALIGNMENT); + self.static_part + .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]); + self.static_part.extend(block); + } + + fn write_padright(&mut self, block: &[u8]) { + assert!(block.len() <= ABI_ALIGNMENT); + self.static_part.extend(block); + self.static_part + .extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]); + } + + /// Write [`H160`] to end of buffer + pub fn address(&mut self, address: &H160) { + self.write_padleft(&address.0) + } + + /// Write [`bool`] to end of buffer + pub fn bool(&mut self, value: &bool) { + self.write_padleft(&[if *value { 1 } else { 0 }]) + } + + /// Write [`u8`] to end of buffer + pub fn uint8(&mut self, value: &u8) { + self.write_padleft(&[*value]) + } + + /// Write [`u32`] to end of buffer + pub fn uint32(&mut self, value: &u32) { + self.write_padleft(&u32::to_be_bytes(*value)) + } + + /// Write [`u64`] to end of buffer + pub fn uint64(&mut self, value: &u64) { + self.write_padleft(&u64::to_be_bytes(*value)) + } + + /// Write [`u128`] to end of buffer + pub fn uint128(&mut self, value: &u128) { + self.write_padleft(&u128::to_be_bytes(*value)) + } + + /// Write [`U256`] to end of buffer + pub fn uint256(&mut self, value: &U256) { + let mut out = [0; 32]; + value.to_big_endian(&mut out); + self.write_padleft(&out) + } + + /// Write [`usize`] to end of buffer + #[deprecated = "dangerous, as usize may have different width in wasm and native execution"] + pub fn write_usize(&mut self, value: &usize) { + self.write_padleft(&usize::to_be_bytes(*value)) + } + + /// Append recursive data, writing pending offset at end of buffer + pub fn write_subresult(&mut self, result: Self) { + self.dynamic_part.push((self.static_part.len(), result)); + // Empty block, to be filled later + self.write_padleft(&[]); + } + + fn memory(&mut self, value: &[u8]) { + let mut sub = Self::new(); + sub.uint32(&(value.len() as u32)); + for chunk in value.chunks(ABI_ALIGNMENT) { + sub.write_padright(chunk); + } + self.write_subresult(sub); + } + + /// Append recursive [`str`] at end of buffer + pub fn string(&mut self, value: &str) { + self.memory(value.as_bytes()) + } + + /// Append recursive [`[u8]`] at end of buffer + pub fn bytes(&mut self, value: &[u8]) { + self.memory(value) + } + + /// Finish writer, concatenating all internal buffers + pub fn finish(mut self) -> Vec { + for (static_offset, part) in self.dynamic_part { + let part_offset = self.static_part.len() + - if self.had_call { 4 } else { 0 } + - if self.is_dynamic { ABI_ALIGNMENT } else { 0 }; + + let encoded_dynamic_offset = usize::to_be_bytes(part_offset); + let start = static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len(); + let stop = static_offset + ABI_ALIGNMENT; + self.static_part[start..stop].copy_from_slice(&encoded_dynamic_offset); + self.static_part.extend(part.finish()) + } + self.static_part + } +} diff --git a/crates/evm-coder/src/abi/test.rs b/crates/evm-coder/src/abi/test.rs new file mode 100644 index 0000000000..e1d04161d8 --- /dev/null +++ b/crates/evm-coder/src/abi/test.rs @@ -0,0 +1,540 @@ +use crate::{ + abi::{AbiRead, AbiWrite}, + types::*, +}; + +use super::{AbiReader, AbiWriter}; +use hex_literal::hex; +use primitive_types::{H160, U256}; + +fn test_impl(function_identifier: u32, decoded_data: T, encoded_data: &[u8]) +where + T: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug, +{ + let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap(); + assert_eq!(call, u32::to_be_bytes(function_identifier)); + let data = ::abi_read(&mut decoder).unwrap(); + assert_eq!(data, decoded_data); + + let mut writer = AbiWriter::new_call(function_identifier); + decoded_data.abi_write(&mut writer); + let ed = writer.finish(); + similar_asserts::assert_eq!(encoded_data, ed.as_slice()); +} + +macro_rules! test_impl_uint { + ($type:ident) => { + test_impl::<$type>( + 0xdeadbeef, + 255 as $type, + &hex!( + " + deadbeef + 00000000000000000000000000000000000000000000000000000000000000ff + " + ), + ); + }; +} + +#[test] +fn encode_decode_uint8() { + test_impl_uint!(uint8); +} + +#[test] +fn encode_decode_uint32() { + test_impl_uint!(uint32); +} + +#[test] +fn encode_decode_uint128() { + test_impl_uint!(uint128); +} + +#[test] +fn encode_decode_uint256() { + test_impl::( + 0xdeadbeef, + U256([255, 0, 0, 0]), + &hex!( + " + deadbeef + 00000000000000000000000000000000000000000000000000000000000000ff + " + ), + ); +} + +#[test] +fn encode_decode_string() { + test_impl::( + 0xdeadbeef, + "some string".to_string(), + &hex!( + " + deadbeef + 0000000000000000000000000000000000000000000000000000000000000020 + 000000000000000000000000000000000000000000000000000000000000000b + 736f6d6520737472696e67000000000000000000000000000000000000000000 + " + ), + ); +} + +#[test] +fn encode_decode_tuple_string() { + test_impl::<(String,)>( + 0xdeadbeef, + ("some string".to_string(),), + &hex!( + " + deadbeef + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000020 + 000000000000000000000000000000000000000000000000000000000000000b + 736f6d6520737472696e67000000000000000000000000000000000000000000 + " + ), + ); +} + +#[test] +fn encode_decode_vec_tuple_address_uint256() { + test_impl::>( + 0x1ACF2D55, + vec![ + ( + H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")), + U256([10, 0, 0, 0]), + ), + ( + H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")), + U256([20, 0, 0, 0]), + ), + ( + H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")), + U256([30, 0, 0, 0]), + ), + ], + &hex!( + " + 1ACF2D55 + 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[] + 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[] + + 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address + 000000000000000000000000000000000000000000000000000000000000000A // uint256 + + 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address + 0000000000000000000000000000000000000000000000000000000000000014 // uint256 + + 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address + 000000000000000000000000000000000000000000000000000000000000001E // uint256 + " + ) + ); +} + +#[test] +fn encode_decode_vec_tuple_uint256_string() { + test_impl::>( + 0xdeadbeef, + vec![ + (1.into(), "Test URI 0".to_string()), + (11.into(), "Test URI 1".to_string()), + (12.into(), "Test URI 2".to_string()), + ], + &hex!( + " + deadbeef + 0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[] + 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[] + + 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem + 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem + 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem + + 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60 + 0000000000000000000000000000000000000000000000000000000000000040 // offset of string + 000000000000000000000000000000000000000000000000000000000000000a // size of string + 5465737420555249203000000000000000000000000000000000000000000000 // string + + 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0 + 0000000000000000000000000000000000000000000000000000000000000040 // offset of string + 000000000000000000000000000000000000000000000000000000000000000a // size of string + 5465737420555249203100000000000000000000000000000000000000000000 // string + + 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160 + 0000000000000000000000000000000000000000000000000000000000000040 // offset of string + 000000000000000000000000000000000000000000000000000000000000000a // size of string + 5465737420555249203200000000000000000000000000000000000000000000 // string + " + ) + ); +} + +#[test] +fn dynamic_after_static() { + let mut encoder = AbiWriter::new(); + encoder.bool(&true); + encoder.string("test"); + let encoded = encoder.finish(); + + let mut encoder = AbiWriter::new(); + encoder.bool(&true); + // Offset to subresult + encoder.uint32(&(32 * 2)); + // Len of "test" + encoder.uint32(&4); + encoder.write_padright(&[b't', b'e', b's', b't']); + let alternative_encoded = encoder.finish(); + + assert_eq!(encoded, alternative_encoded); + + let mut decoder = AbiReader::new(&encoded); + assert!(decoder.bool().unwrap()); + assert_eq!(decoder.string().unwrap(), "test"); +} + +#[test] +fn mint_sample() { + let (call, mut decoder) = AbiReader::new_call(&hex!( + " + 50bb4e7f + 000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374 + 0000000000000000000000000000000000000000000000000000000000000001 + 0000000000000000000000000000000000000000000000000000000000000060 + 0000000000000000000000000000000000000000000000000000000000000008 + 5465737420555249000000000000000000000000000000000000000000000000 + " + )) + .unwrap(); + assert_eq!(call, u32::to_be_bytes(0x50bb4e7f)); + assert_eq!( + format!("{:?}", decoder.address().unwrap()), + "0xad2c0954693c2b5404b7e50967d3481bea432374" + ); + assert_eq!(decoder.uint32().unwrap(), 1); + assert_eq!(decoder.string().unwrap(), "Test URI"); +} + +#[test] +fn parse_vec_with_dynamic_type() { + let decoded_data = ( + 0x36543006, + vec![ + (1.into(), "Test URI 0".to_string()), + (11.into(), "Test URI 1".to_string()), + (12.into(), "Test URI 2".to_string()), + ], + ); + + let encoded_data = &hex!( + " + 36543006 + 00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address + 0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[] + 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[] + + 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem + 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem + 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem + + 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60 + 0000000000000000000000000000000000000000000000000000000000000040 // offset of string + 000000000000000000000000000000000000000000000000000000000000000a // size of string + 5465737420555249203000000000000000000000000000000000000000000000 // string + + 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0 + 0000000000000000000000000000000000000000000000000000000000000040 // offset of string + 000000000000000000000000000000000000000000000000000000000000000a // size of string + 5465737420555249203100000000000000000000000000000000000000000000 // string + + 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160 + 0000000000000000000000000000000000000000000000000000000000000040 // offset of string + 000000000000000000000000000000000000000000000000000000000000000a // size of string + 5465737420555249203200000000000000000000000000000000000000000000 // string + " + ); + + let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap(); + assert_eq!(call, u32::to_be_bytes(decoded_data.0)); + let address = decoder.address().unwrap(); + let data = >::abi_read(&mut decoder).unwrap(); + assert_eq!(data, decoded_data.1); + + let mut writer = AbiWriter::new_call(decoded_data.0); + address.abi_write(&mut writer); + decoded_data.1.abi_write(&mut writer); + let ed = writer.finish(); + similar_asserts::assert_eq!(encoded_data, ed.as_slice()); +} + +#[test] +fn encode_decode_vec_tuple_string_bytes() { + test_impl::>( + 0xdeadbeef, + vec![ + ( + "Test URI 0".to_string(), + bytes(vec![ + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + ]), + ), + ( + "Test URI 1".to_string(), + bytes(vec![ + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + ]), + ), + ("Test URI 2".to_string(), bytes(vec![0x33, 0x33])), + ], + &hex!( + " + deadbeef + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000003 + + 0000000000000000000000000000000000000000000000000000000000000060 + 0000000000000000000000000000000000000000000000000000000000000140 + 0000000000000000000000000000000000000000000000000000000000000220 + + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000080 + 000000000000000000000000000000000000000000000000000000000000000a + 5465737420555249203000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000030 + 1111111111111111111111111111111111111111111111111111111111111111 + 1111111111111111111111111111111100000000000000000000000000000000 + + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000080 + 000000000000000000000000000000000000000000000000000000000000000a + 5465737420555249203100000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000002f + 2222222222222222222222222222222222222222222222222222222222222222 + 2222222222222222222222222222220000000000000000000000000000000000 + + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000080 + 000000000000000000000000000000000000000000000000000000000000000a + 5465737420555249203200000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000002 + 3333000000000000000000000000000000000000000000000000000000000000 + " + ), + ); +} + +#[test] +// #[ignore = "reason"] +fn encode_decode_tuple0_tuple1_uint8_tuple1_string_bytes_tuple1_uint8_bytes() { + let int = 0xff; + let by = bytes(vec![0x11, 0x22, 0x33]); + let string = "some string".to_string(); + + test_impl::<((u8,), (String, bytes), (u8, bytes))>( + 0xdeadbeef, + ((int,), (string.clone(), by.clone()), (int, by)), + &hex!( + " + deadbeef + 0000000000000000000000000000000000000000000000000000000000000020 + 00000000000000000000000000000000000000000000000000000000000000ff + 0000000000000000000000000000000000000000000000000000000000000060 + 0000000000000000000000000000000000000000000000000000000000000120 + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000080 + 000000000000000000000000000000000000000000000000000000000000000b + 736f6d6520737472696e67000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000003 + 1122330000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000000000000000ff + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000003 + 1122330000000000000000000000000000000000000000000000000000000000 + " + ), + ); +} + +#[test] +fn encode_decode_tuple0_tuple1_uint8_tuple1_uint8_uint8_tuple1_uint8_uint8() { + test_impl::<((u8,), (u8, u8), (u8, u8))>( + 0xdeadbeef, + ((43,), (44, 45), (46, 47)), + &hex!( + " + deadbeef + 000000000000000000000000000000000000000000000000000000000000002b + 000000000000000000000000000000000000000000000000000000000000002c + 000000000000000000000000000000000000000000000000000000000000002d + 000000000000000000000000000000000000000000000000000000000000002e + 000000000000000000000000000000000000000000000000000000000000002f + " + ), + ); +} + +#[test] +fn encode_decode_tuple0_tuple1_uint8_tuple1_uint8() { + test_impl::<((u8,), (u8,))>( + 0xdeadbeef, + ((43,), (44,)), + &hex!( + " + deadbeef + 000000000000000000000000000000000000000000000000000000000000002b + 000000000000000000000000000000000000000000000000000000000000002c + " + ), + ); +} + +#[test] +fn encode_decode_tuple0_tuple1_uint8_uint8() { + test_impl::<((u8, u8),)>( + 0xdeadbeef, + ((43, 44),), + &hex!( + " + deadbeef + 000000000000000000000000000000000000000000000000000000000000002b + 000000000000000000000000000000000000000000000000000000000000002c + " + ), + ); +} + +#[test] +fn encode_decode_tuple_uint8_uint8() { + test_impl::<(u8, u8)>( + 0xdeadbeef, + (43, 44), + &hex!( + " + deadbeef + 000000000000000000000000000000000000000000000000000000000000002b + 000000000000000000000000000000000000000000000000000000000000002c + " + ), + ); +} + +#[test] +fn encode_decode_tuple0_tuple1_uint8_uint8_tuple1_uint8_uint8_and_uint8() { + test_impl::<((u8, u8), (u8, u8), u8)>( + 0xdeadbeef, + ((10, 11), (12, 13), 14), + &hex!( + " + deadbeef + 000000000000000000000000000000000000000000000000000000000000000a + 000000000000000000000000000000000000000000000000000000000000000b + 000000000000000000000000000000000000000000000000000000000000000c + 000000000000000000000000000000000000000000000000000000000000000d + 000000000000000000000000000000000000000000000000000000000000000e + " + ), + ); +} + +#[test] +fn encode_decode_tuple0_tuple1_string() { + test_impl::<((String,),)>( + 0xdeadbeef, + (("some string".to_string(),),), + &hex!( + " + deadbeef + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000020 + 000000000000000000000000000000000000000000000000000000000000000b + 736f6d6520737472696e67000000000000000000000000000000000000000000 + " + ), + ); +} + +#[test] +fn encode_decode_tuple0_tuple1_uint8_string() { + test_impl::<((u8, String),)>( + 0xdeadbeef, + ((0xff, "some string".to_string()),), + &hex!( + " + deadbeef + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000020 + 00000000000000000000000000000000000000000000000000000000000000ff + 0000000000000000000000000000000000000000000000000000000000000040 + 000000000000000000000000000000000000000000000000000000000000000b + 736f6d6520737472696e67000000000000000000000000000000000000000000 + " + ), + ); +} + +#[test] +fn encode_decode_tuple0_tuple1_string_bytes() { + test_impl::<((String, bytes),)>( + 0xdeadbeef, + (("some string".to_string(), bytes(vec![1, 2, 3])),), + &hex!( + " + deadbeef + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000020 + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000080 + 000000000000000000000000000000000000000000000000000000000000000b + 736f6d6520737472696e67000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000003 + 0102030000000000000000000000000000000000000000000000000000000000 + " + ), + ); +} + +#[test] +fn encode_decode_tuple0_tuple1_uint8_tuple1_string() { + test_impl::<((u8,), (String,))>( + 0xdeadbeef, + ((0xff,), ("some string".to_string(),)), + &hex!( + " + deadbeef + 0000000000000000000000000000000000000000000000000000000000000020 + 00000000000000000000000000000000000000000000000000000000000000ff + 0000000000000000000000000000000000000000000000000000000000000040 + 0000000000000000000000000000000000000000000000000000000000000020 + 000000000000000000000000000000000000000000000000000000000000000b + 736f6d6520737472696e67000000000000000000000000000000000000000000 + " + ), + ); +} + +#[test] +fn parse_multiple_params() { + let encoded_data = hex!( + " + deadbeef + 000000000000000000000000000000000000000000000000000000000000000a + 000000000000000000000000000000000000000000000000000000000000000b + " + ); + let (_, mut decoder) = AbiReader::new_call(&encoded_data).unwrap(); + let p1 = ::abi_read(&mut decoder).unwrap(); + let p2 = ::abi_read(&mut decoder).unwrap(); + assert_eq!(p1, 0x0a); + assert_eq!(p2, 0x0b); +} diff --git a/crates/evm-coder/src/abi/traits.rs b/crates/evm-coder/src/abi/traits.rs new file mode 100644 index 0000000000..265941892e --- /dev/null +++ b/crates/evm-coder/src/abi/traits.rs @@ -0,0 +1,45 @@ +use super::{AbiReader, AbiWriter}; +use crate::{ + custom_signature::*, + execution::{Result, ResultWithPostInfo}, +}; +use core::str::from_utf8; + +/// Helper for type. +pub trait AbiType { + /// Signature for Etherium ABI. + const SIGNATURE: SignatureUnit; + + /// Signature as str. + fn as_str() -> &'static str { + from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8") + } + + /// Is type dynamic sized. + fn is_dynamic() -> bool; + + /// Size for type aligned to [`ABI_ALIGNMENT`]. + fn size() -> usize; +} + +/// [`AbiReader`] implements reading of many types. +pub trait AbiRead { + /// Read item from current position, advanding decoder + fn abi_read(reader: &mut AbiReader) -> Result + where + Self: Sized; +} + +/// For questions about inability to provide custom implementations, +/// see [`AbiRead`] +pub trait AbiWrite { + /// Write value to end of specified encoder + fn abi_write(&self, writer: &mut AbiWriter); + /// Specialization for [`crate::solidity_interface`] implementation, + /// see comment in `impl AbiWrite for ResultWithPostInfo` + fn to_result(&self) -> ResultWithPostInfo { + let mut writer = AbiWriter::new(); + self.abi_write(&mut writer); + Ok(writer.into()) + } +} diff --git a/crates/evm-coder/src/custom_signature.rs b/crates/evm-coder/src/custom_signature.rs new file mode 100644 index 0000000000..ebec3dbb7d --- /dev/null +++ b/crates/evm-coder/src/custom_signature.rs @@ -0,0 +1,326 @@ +//! # A module for custom signature support. +//! +//! ## Overview +//! This module allows you to create arbitrary signatures for types and functions in compile time. +//! +//! ### Type signatures +//! To create the desired type signature, you need to create your own trait with the `SIGNATURE` constant. +//! Then in the implementation, for the required type, use the macro [`make_signature`] +//! #### Example +//! ``` +//! use std::str::from_utf8; +//! use evm_coder::{custom_signature::SignatureUnit, make_signature}; +//! +//! // Create trait for our signature +//! trait SoliditySignature { +//! const SIGNATURE: SignatureUnit; +//! +//! fn name() -> &'static str { +//! from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8") +//! } +//! } +//! +//! // Make signatures for some types +//! impl SoliditySignature for u8 { +//! const SIGNATURE: SignatureUnit = make_signature!(new fixed("uint8")); +//! } +//! impl SoliditySignature for u32 { +//! const SIGNATURE: SignatureUnit = make_signature!(new fixed("uint32")); +//! } +//! impl SoliditySignature for Vec { +//! const SIGNATURE: SignatureUnit = make_signature!(new nameof(T::SIGNATURE) fixed("[]")); +//! } +//! impl SoliditySignature for (A, B) { +//! const SIGNATURE: SignatureUnit = make_signature!(new fixed("(") nameof(A::SIGNATURE) fixed(",") nameof(B::SIGNATURE) fixed(")")); +//! } +//! impl SoliditySignature for (A,) { +//! const SIGNATURE: SignatureUnit = make_signature!(new fixed("(") nameof(A::SIGNATURE) fixed(",") shift_left(1) fixed(")")); +//! } +//! +//! assert_eq!(u8::name(), "uint8"); +//! assert_eq!(>::name(), "uint8[]"); +//! assert_eq!(<(u32, u8)>::name(), "(uint32,uint8)"); +//! ``` +//! +//! ### Function signatures +//! To create a function signature, the macro [`make_signature`] is also used, which accepts +//! settings for the function format [`SignaturePreferences`] and function parameters [`SignatureUnit`] +//! #### Example +//! ``` +//! use core::str::from_utf8; +//! use evm_coder::{custom_signature::SignatureUnit, make_signature}; +//! // Trait for our signature +//! trait SoliditySignature { +//! const SIGNATURE: SignatureUnit; +//! +//! fn name() -> &'static str { +//! from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8") +//! } +//! } +//! +//! // Make signatures for some types +//! impl SoliditySignature for u8 { +//! const SIGNATURE: SignatureUnit = make_signature!(new fixed("uint8")); +//! } +//! impl SoliditySignature for Vec { +//! const SIGNATURE: SignatureUnit = make_signature!(new nameof(T::SIGNATURE) fixed("[]")); +//! } +//! ``` + +/// The maximum length of the signature. +pub const SIGNATURE_SIZE_LIMIT: usize = 256; + +/// Storage for the signature or its elements. +#[derive(Debug)] +pub struct SignatureUnit { + /// Signature data. + pub data: [u8; SIGNATURE_SIZE_LIMIT], + /// The actual size of the data. + pub len: usize, +} + +impl SignatureUnit { + /// Create a signature from `&str'. + pub const fn new(name: &'static str) -> SignatureUnit { + let mut signature = [0_u8; SIGNATURE_SIZE_LIMIT]; + let name = name.as_bytes(); + let name_len = name.len(); + let mut dst_offset = 0; + crate::make_signature!(@copy(name, signature, name_len, dst_offset)); + SignatureUnit { + data: signature, + len: name_len, + } + } + /// String conversion + pub fn as_str(&self) -> Option<&str> { + core::str::from_utf8(&self.data[0..self.len]).ok() + } +} + +/// ### Macro to create signatures of types and functions. +/// +/// Format for creating a type of signature: +/// ```ignore +/// make_signature!(new fixed("uint8")); // Simple type +/// make_signature!(new fixed("(") nameof(u8) fixed(",") nameof(u8) fixed(")")); // Composite type +/// ``` +#[macro_export] +macro_rules! make_signature { + (new $($tt:tt)*) => { + ($crate::custom_signature::SignatureUnit { + data: { + let mut out = [0u8; $crate::custom_signature::SIGNATURE_SIZE_LIMIT]; + let mut dst_offset = 0; + $crate::make_signature!(@data(out, dst_offset); $($tt)*); + out + }, + len: {0 + $crate::make_signature!(@size; $($tt)*)}, + }) + }; + + (@size;) => { + 0 + }; + (@size; fixed($expr:expr) $($tt:tt)*) => { + $expr.len() + $crate::make_signature!(@size; $($tt)*) + }; + (@size; nameof($expr:expr) $($tt:tt)*) => { + $expr.len + $crate::make_signature!(@size; $($tt)*) + }; + (@size; numof($expr:expr) $($tt:tt)*) => { + { + let mut out = 0; + let mut v = $expr; + if v == 0 { + out = 1; + } else { + while v > 0 { + out += 1; + v /= 10; + } + } + out + } + $crate::make_signature!(@size; $($tt)*) + }; + (@size; shift_left($expr:expr) $($tt:tt)*) => { + $crate::make_signature!(@size; $($tt)*) - $expr + }; + + (@data($dst:ident, $dst_offset:ident);) => {}; + (@data($dst:ident, $dst_offset:ident); fixed($expr:expr) $($tt:tt)*) => { + { + let data = $expr.as_bytes(); + let data_len = data.len(); + $crate::make_signature!(@copy(data, $dst, data_len, $dst_offset)); + } + $crate::make_signature!(@data($dst, $dst_offset); $($tt)*) + }; + (@data($dst:ident, $dst_offset:ident); nameof($expr:expr) $($tt:tt)*) => { + { + $crate::make_signature!(@copy(&$expr.data, $dst, $expr.len, $dst_offset)); + } + $crate::make_signature!(@data($dst, $dst_offset); $($tt)*) + }; + (@data($dst:ident, $dst_offset:ident); numof($expr:expr) $($tt:tt)*) => { + { + let mut v = $expr; + let mut need_to_swap = 0; + if v == 0 { + $dst[$dst_offset] = b'0'; + $dst_offset += 1; + } else { + while v > 0 { + let n = (v % 10) as u8; + $dst[$dst_offset] = b'0' + n; + v /= 10; + need_to_swap += 1; + $dst_offset += 1; + } + } + let mut i = 0; + #[allow(clippy::manual_swap)] + while i < need_to_swap / 2 { + let a = $dst_offset - i - 1; + let b = $dst_offset - need_to_swap + i; + let v = $dst[a]; + $dst[a] = $dst[b]; + $dst[b] = v; + i += 1; + } + } + $crate::make_signature!(@data($dst, $dst_offset); $($tt)*) + }; + (@data($dst:ident, $dst_offset:ident); shift_left($expr:expr) $($tt:tt)*) => { + $dst_offset -= $expr; + $crate::make_signature!(@data($dst, $dst_offset); $($tt)*) + }; + + (@copy($src:expr, $dst:expr, $src_len:expr, $dst_offset:ident)) => { + { + let mut src_offset = 0; + let src_len: usize = $src_len; + while src_offset < src_len { + $dst[$dst_offset] = $src[src_offset]; + $dst_offset += 1; + src_offset += 1; + } + } + } +} + +#[cfg(test)] +mod test { + use core::str::from_utf8; + + use super::{SIGNATURE_SIZE_LIMIT, SignatureUnit}; + + trait Name { + const NAME: SignatureUnit; + + fn name() -> &'static str { + from_utf8(&Self::NAME.data[..Self::NAME.len]).expect("bad utf-8") + } + } + + impl Name for u8 { + const NAME: SignatureUnit = make_signature!(new fixed("uint8")); + } + impl Name for u32 { + const NAME: SignatureUnit = make_signature!(new fixed("uint32")); + } + impl Name for Vec { + const NAME: SignatureUnit = make_signature!(new nameof(T::NAME) fixed("[]")); + } + impl Name for (A, B) { + const NAME: SignatureUnit = + make_signature!(new fixed("(") nameof(A::NAME) fixed(",") nameof(B::NAME) fixed(")")); + } + impl Name for (A,) { + const NAME: SignatureUnit = + make_signature!(new fixed("(") nameof(A::NAME) fixed(",") shift_left(1) fixed(")")); + } + impl Name for [A; SIZE] { + const NAME: SignatureUnit = + make_signature!(new nameof(A::NAME) fixed("[") numof(SIZE) fixed("]")); + } + + struct MaxSize(); + impl Name for MaxSize { + const NAME: SignatureUnit = SignatureUnit { + data: [b'!'; SIGNATURE_SIZE_LIMIT], + len: SIGNATURE_SIZE_LIMIT, + }; + } + + #[test] + fn simple() { + assert_eq!(u8::name(), "uint8"); + assert_eq!(u32::name(), "uint32"); + } + + #[test] + fn vector_of_simple() { + assert_eq!(>::name(), "uint8[]"); + assert_eq!(>::name(), "uint32[]"); + } + + #[test] + fn vector_of_vector() { + assert_eq!(>>::name(), "uint8[][]"); + } + + #[test] + fn tuple_of_simple() { + assert_eq!(<(u32, u8)>::name(), "(uint32,uint8)"); + } + + #[test] + fn tuple_of_tuple() { + assert_eq!( + <((u32, u8), (u8, u32))>::name(), + "((uint32,uint8),(uint8,uint32))" + ); + } + + #[test] + fn vector_of_tuple() { + assert_eq!(>::name(), "(uint32,uint8)[]"); + } + + #[test] + fn tuple_of_vector() { + assert_eq!(<(Vec, u8)>::name(), "(uint32[],uint8)"); + } + + #[test] + fn complex() { + assert_eq!( + <(Vec, (u32, Vec))>::name(), + "(uint32[],(uint32,uint8[]))" + ); + } + + #[test] + fn max_size() { + assert_eq!(::name(), "!".repeat(SIGNATURE_SIZE_LIMIT)); + } + + #[test] + fn shift() { + assert_eq!(<(u32,)>::name(), "(uint32)"); + } + + #[test] + fn num() { + assert_eq!(<[u8; 0]>::name(), "uint8[0]"); + assert_eq!(<[u8; 1234]>::name(), "uint8[1234]"); + assert_eq!(<[u8; 12345]>::name(), "uint8[12345]"); + } + + #[test] + fn over_max_size() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/build_failed/custom_signature_over_max_size.rs"); + } +} diff --git a/crates/evm-coder/src/lib.rs b/crates/evm-coder/src/lib.rs index fa247f2240..e3df8c924f 100644 --- a/crates/evm-coder/src/lib.rs +++ b/crates/evm-coder/src/lib.rs @@ -16,6 +16,7 @@ #![doc = include_str!("../README.md")] #![deny(missing_docs)] +#![macro_use] #![cfg_attr(not(feature = "std"), no_std)] #[cfg(not(feature = "std"))] extern crate alloc; @@ -26,6 +27,8 @@ pub mod abi; pub use events::{ToLog, ToTopic}; use execution::DispatchInfo; pub mod execution; +#[macro_use] +pub mod custom_signature; /// Derives call enum implementing [`crate::Callable`], [`crate::Weighted`] /// and [`crate::Call`] from impl block. @@ -90,6 +93,8 @@ pub use evm_coder_procedural::solidity_interface; pub use evm_coder_procedural::solidity; /// See [`solidity_interface`] pub use evm_coder_procedural::weight; +pub use evm_coder_procedural::AbiCoder; +pub use sha3_const; /// Derives [`ToLog`] for enum /// @@ -104,8 +109,18 @@ pub use evm_coder_procedural::ToLog; #[doc(hidden)] pub mod events; #[doc(hidden)] +#[cfg(feature = "stubgen")] pub mod solidity; +/// Sealed traits. +pub mod sealed { + /// Not every type should be directly placed in vec. + /// Vec encoding is not memory efficient, as every item will be padded + /// to 32 bytes. + /// Instead you should use specialized types (`bytes` in case of `Vec`) + pub trait CanBePlacedInVec {} +} + /// Solidity type definitions (aliases from solidity name to rust type) /// To be used in [`solidity_interface`] definitions, to make sure there is no /// type conflict between Rust code and generated definitions @@ -117,23 +132,22 @@ pub mod types { use primitive_types::{U256, H160, H256}; pub type address = H160; - pub type uint8 = u8; pub type uint16 = u16; pub type uint32 = u32; pub type uint64 = u64; pub type uint128 = u128; pub type uint256 = U256; - pub type bytes4 = [u8; 4]; - pub type topic = H256; #[cfg(not(feature = "std"))] pub type string = ::alloc::string::String; #[cfg(feature = "std")] pub type string = ::std::string::String; - pub type bytes = Vec; + + #[derive(Default, Debug, PartialEq, Eq, Clone)] + pub struct bytes(pub Vec); /// Solidity doesn't have `void` type, however we have special implementation /// for empty tuple return type @@ -157,6 +171,31 @@ pub mod types { /// and there is no `receiver()` function defined. pub value: U256, } + + impl From> for bytes { + fn from(src: Vec) -> Self { + Self(src) + } + } + + #[allow(clippy::from_over_into)] + impl Into> for bytes { + fn into(self) -> Vec { + self.0 + } + } + + impl bytes { + #[must_use] + pub fn len(&self) -> usize { + self.0.len() + } + + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + } } /// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro @@ -213,7 +252,7 @@ impl Call for ERC165Call { return Ok(None); } Ok(Some(Self::SupportsInterface { - interface_id: input.abi_read()?, + interface_id: types::bytes4::abi_read(input)?, })) } } @@ -226,6 +265,7 @@ impl Call for ERC165Call { #[macro_export] macro_rules! generate_stubgen { ($name:ident, $decl:ty, $is_impl:literal) => { + #[cfg(feature = "stubgen")] #[test] #[ignore] fn $name() { diff --git a/crates/evm-coder/src/solidity/impls.rs b/crates/evm-coder/src/solidity/impls.rs new file mode 100644 index 0000000000..1206d4331d --- /dev/null +++ b/crates/evm-coder/src/solidity/impls.rs @@ -0,0 +1,123 @@ +use super::{TypeCollector, SolidityTypeName, SolidityTupleTy}; +use crate::{sealed, types::*}; +use core::fmt; +use primitive_types::{U256, H160}; + +macro_rules! solidity_type_name { + ($($ty:ty => $name:literal $simple:literal = $default:literal),* $(,)?) => { + $( + impl SolidityTypeName for $ty { + fn solidity_name(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result { + write!(writer, $name) + } + fn is_simple() -> bool { + $simple + } + fn solidity_default(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result { + write!(writer, $default) + } + } + )* + }; +} + +solidity_type_name! { + u8 => "uint8" true = "0", + u32 => "uint32" true = "0", + u64 => "uint64" true = "0", + u128 => "uint128" true = "0", + U256 => "uint256" true = "0", + bytes4 => "bytes4" true = "bytes4(0)", + H160 => "address" true = "0x0000000000000000000000000000000000000000", + string => "string" false = "\"\"", + bytes => "bytes" false = "hex\"\"", + bool => "bool" true = "false", +} + +impl SolidityTypeName for void { + fn solidity_name(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result { + Ok(()) + } + fn is_simple() -> bool { + true + } + fn solidity_default(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result { + Ok(()) + } + fn is_void() -> bool { + true + } +} + +impl SolidityTypeName for Vec { + fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { + T::solidity_name(writer, tc)?; + write!(writer, "[]") + } + fn is_simple() -> bool { + false + } + fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { + write!(writer, "new ")?; + T::solidity_name(writer, tc)?; + write!(writer, "[](0)") + } +} + +macro_rules! count { + () => (0usize); + ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*)); +} + +macro_rules! impl_tuples { + ($($ident:ident)+) => { + impl<$($ident: SolidityTypeName + 'static),+> SolidityTupleTy for ($($ident,)+) { + fn fields(tc: &TypeCollector) -> Vec { + let mut collected = Vec::with_capacity(Self::len()); + $({ + let mut out = string::new(); + $ident::solidity_name(&mut out, tc).expect("no fmt error"); + collected.push(out); + })*; + collected + } + + fn len() -> usize { + count!($($ident)*) + } + } + impl<$($ident: SolidityTypeName + 'static),+> SolidityTypeName for ($($ident,)+) { + fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { + write!(writer, "{}", tc.collect_tuple::()) + } + fn is_simple() -> bool { + false + } + #[allow(unused_assignments)] + fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { + write!(writer, "{}(", tc.collect_tuple::())?; + let mut first = true; + $( + if !first { + write!(writer, ",")?; + } else { + first = false; + } + <$ident>::solidity_default(writer, tc)?; + )* + write!(writer, ")") + } + } + }; +} + +impl_tuples! {A} +impl_tuples! {A B} +impl_tuples! {A B C} +impl_tuples! {A B C D} +impl_tuples! {A B C D E} +impl_tuples! {A B C D E F} +impl_tuples! {A B C D E F G} +impl_tuples! {A B C D E F G H} +impl_tuples! {A B C D E F G H I} +impl_tuples! {A B C D E F G H I J} diff --git a/crates/evm-coder/src/solidity.rs b/crates/evm-coder/src/solidity/mod.rs similarity index 70% rename from crates/evm-coder/src/solidity.rs rename to crates/evm-coder/src/solidity/mod.rs index 0ceaab6f40..10a0fa0e86 100644 --- a/crates/evm-coder/src/solidity.rs +++ b/crates/evm-coder/src/solidity/mod.rs @@ -21,6 +21,10 @@ //! Purpose of this module is to receive solidity contract definition in module-specified //! format, and then output string, representing interface of this contract in solidity language +mod traits; +pub use traits::*; +mod impls; + #[cfg(not(feature = "std"))] use alloc::{string::String, vec::Vec, collections::BTreeMap, format}; #[cfg(feature = "std")] @@ -32,7 +36,7 @@ use core::{ cmp::Reverse, }; use impl_trait_for_tuples::impl_for_tuples; -use crate::types::*; +use crate::{types::*, custom_signature::SignatureUnit}; #[derive(Default)] pub struct TypeCollector { @@ -40,6 +44,7 @@ pub struct TypeCollector { /// id ordering is required to perform topo-sort on the resulting data structs: RefCell>, anonymous: RefCell, usize>>, + // generic: RefCell>, id: Cell, } impl TypeCollector { @@ -55,8 +60,9 @@ impl TypeCollector { self.id.set(v + 1); v } - pub fn collect_tuple(&self) -> String { - let names = T::names(self); + /// Collect typle, deduplicating it by type, and returning generated name + pub fn collect_tuple(&self) -> String { + let names = T::fields(self); if let Some(id) = self.anonymous.borrow().get(&names).cloned() { return format!("Tuple{}", id); } @@ -72,167 +78,18 @@ impl TypeCollector { self.anonymous.borrow_mut().insert(names, id); format!("Tuple{}", id) } + pub fn collect_struct(&self) -> String { + T::generate_solidity_interface(self) + } + pub fn collect_enum(&self) -> String { + T::generate_solidity_interface(self) + } pub fn finish(self) -> Vec { let mut data = self.structs.into_inner().into_iter().collect::>(); data.sort_by_key(|(_, id)| Reverse(*id)); data.into_iter().map(|(code, _)| code).collect() } } - -pub trait SolidityTypeName: 'static { - fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result; - /// "simple" types are stored inline, no `memory` modifier should be used in solidity - fn is_simple() -> bool; - fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result; - /// Specialization - fn is_void() -> bool { - false - } -} -macro_rules! solidity_type_name { - ($($ty:ty => $name:literal $simple:literal = $default:literal),* $(,)?) => { - $( - impl SolidityTypeName for $ty { - fn solidity_name(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result { - write!(writer, $name) - } - fn is_simple() -> bool { - $simple - } - fn solidity_default(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result { - write!(writer, $default) - } - } - )* - }; -} - -solidity_type_name! { - uint8 => "uint8" true = "0", - uint32 => "uint32" true = "0", - uint64 => "uint64" true = "0", - uint128 => "uint128" true = "0", - uint256 => "uint256" true = "0", - bytes4 => "bytes4" true = "bytes4(0)", - address => "address" true = "0x0000000000000000000000000000000000000000", - string => "string" false = "\"\"", - bytes => "bytes" false = "hex\"\"", - bool => "bool" true = "false", -} -impl SolidityTypeName for void { - fn solidity_name(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result { - Ok(()) - } - fn is_simple() -> bool { - true - } - fn solidity_default(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result { - Ok(()) - } - fn is_void() -> bool { - true - } -} - -mod sealed { - /// Not every type should be directly placed in vec. - /// Vec encoding is not memory efficient, as every item will be padded - /// to 32 bytes. - /// Instead you should use specialized types (`bytes` in case of `Vec`) - pub trait CanBePlacedInVec {} -} - -impl sealed::CanBePlacedInVec for uint256 {} -impl sealed::CanBePlacedInVec for string {} -impl sealed::CanBePlacedInVec for address {} - -impl SolidityTypeName for Vec { - fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { - T::solidity_name(writer, tc)?; - write!(writer, "[]") - } - fn is_simple() -> bool { - false - } - fn solidity_default(writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result { - write!(writer, "[]") - } -} - -pub trait SolidityTupleType { - fn names(tc: &TypeCollector) -> Vec; - fn len() -> usize; -} - -macro_rules! count { - () => (0usize); - ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*)); -} - -macro_rules! impl_tuples { - ($($ident:ident)+) => { - impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {} - impl<$($ident: SolidityTypeName + 'static),+> SolidityTupleType for ($($ident,)+) { - fn names(tc: &TypeCollector) -> Vec { - let mut collected = Vec::with_capacity(Self::len()); - $({ - let mut out = string::new(); - $ident::solidity_name(&mut out, tc).expect("no fmt error"); - collected.push(out); - })*; - collected - } - - fn len() -> usize { - count!($($ident)*) - } - } - impl<$($ident: SolidityTypeName + 'static),+> SolidityTypeName for ($($ident,)+) { - fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { - write!(writer, "{}", tc.collect_tuple::()) - } - fn is_simple() -> bool { - false - } - #[allow(unused_assignments)] - fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { - write!(writer, "{}(", tc.collect_tuple::())?; - let mut first = true; - $( - if !first { - write!(writer, ",")?; - } else { - first = false; - } - <$ident>::solidity_default(writer, tc)?; - )* - write!(writer, ")") - } - } - }; -} - -impl_tuples! {A} -impl_tuples! {A B} -impl_tuples! {A B C} -impl_tuples! {A B C D} -impl_tuples! {A B C D E} -impl_tuples! {A B C D E F} -impl_tuples! {A B C D E F G} -impl_tuples! {A B C D E F G H} -impl_tuples! {A B C D E F G H I} -impl_tuples! {A B C D E F G H I J} - -pub trait SolidityArguments { - fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result; - fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result; - fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result; - fn is_empty(&self) -> bool { - self.len() == 0 - } - fn len(&self) -> usize; -} - #[derive(Default)] pub struct UnnamedArgument(PhantomData<*const T>); @@ -400,15 +257,6 @@ impl SolidityArguments for Tuple { } } -pub trait SolidityFunctions { - fn solidity_name( - &self, - is_impl: bool, - writer: &mut impl fmt::Write, - tc: &TypeCollector, - ) -> fmt::Result; -} - pub enum SolidityMutability { Pure, View, @@ -416,9 +264,9 @@ pub enum SolidityMutability { } pub struct SolidityFunction { pub docs: &'static [&'static str], - pub selector_str: &'static str, pub selector: u32, pub hide: bool, + pub custom_signature: SignatureUnit, pub name: &'static str, pub args: A, pub result: R, @@ -432,7 +280,7 @@ impl SolidityFunctions for SolidityF writer: &mut impl fmt::Write, tc: &TypeCollector, ) -> fmt::Result { - let hide_comment = self.hide.then(|| "// ").unwrap_or(""); + let hide_comment = self.hide.then_some("// ").unwrap_or(""); for doc in self.docs { writeln!(writer, "\t{hide_comment}///{}", doc)?; } @@ -444,7 +292,7 @@ impl SolidityFunctions for SolidityF writeln!( writer, "\t{hide_comment}/// or in textual repr: {}", - self.selector_str + self.custom_signature.as_str().expect("bad utf-8") )?; write!(writer, "\t{hide_comment}function {}(", self.name)?; self.args.solidity_name(writer, tc)?; @@ -575,3 +423,93 @@ impl SolidityFunctions for SolidityEvent { writeln!(writer, ");") } } + +#[impl_for_tuples(0, 48)] +impl SolidityItems for Tuple { + for_tuples!( where #( Tuple: SolidityItems ),* ); + + fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { + for_tuples!( #( + Tuple.solidity_name(writer, tc)?; + )* ); + Ok(()) + } +} + +pub struct SolidityStructField { + pub docs: &'static [&'static str], + pub name: &'static str, + pub ty: PhantomData<*const T>, +} + +impl SolidityItems for SolidityStructField +where + T: SolidityTypeName, +{ + fn solidity_name(&self, out: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { + for doc in self.docs { + writeln!(out, "///{}", doc)?; + } + write!(out, "\t")?; + T::solidity_name(out, tc)?; + writeln!(out, " {};", self.name)?; + Ok(()) + } +} +pub struct SolidityStruct { + pub docs: &'static [&'static str], + // pub generics: + pub name: &'static str, + pub fields: F, +} +impl SolidityStruct +where + F: SolidityItems, +{ + pub fn format(&self, out: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { + for doc in self.docs { + writeln!(out, "///{}", doc)?; + } + writeln!(out, "struct {} {{", self.name)?; + self.fields.solidity_name(out, tc)?; + writeln!(out, "}}")?; + Ok(()) + } +} + +pub struct SolidityEnumVariant { + pub docs: &'static [&'static str], + pub name: &'static str, +} +impl SolidityItems for SolidityEnumVariant { + fn solidity_name(&self, out: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result { + for doc in self.docs { + writeln!(out, "///{}", doc)?; + } + write!(out, "\t{}", self.name)?; + Ok(()) + } +} +pub struct SolidityEnum { + pub docs: &'static [&'static str], + pub name: &'static str, + pub fields: &'static [SolidityEnumVariant], +} +impl SolidityEnum { + pub fn format(&self, out: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result { + for doc in self.docs { + writeln!(out, "///{}", doc)?; + } + write!(out, "enum {} {{", self.name)?; + for (i, field) in self.fields.iter().enumerate() { + if i != 0 { + write!(out, ",")?; + } + writeln!(out)?; + field.solidity_name(out, tc)?; + } + writeln!(out)?; + writeln!(out, "}}")?; + Ok(()) + } +} diff --git a/crates/evm-coder/src/solidity/traits.rs b/crates/evm-coder/src/solidity/traits.rs new file mode 100644 index 0000000000..3a2cd348f4 --- /dev/null +++ b/crates/evm-coder/src/solidity/traits.rs @@ -0,0 +1,50 @@ +use super::TypeCollector; +use core::fmt; + +pub trait SolidityTypeName: 'static { + fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result; + /// "simple" types are stored inline, no `memory` modifier should be used in solidity + fn is_simple() -> bool; + fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result; + /// Specialization + fn is_void() -> bool { + false + } +} + +pub trait SolidityTupleTy: 'static { + fn fields(tc: &TypeCollector) -> Vec; + fn len() -> usize; +} +pub trait SolidityStructTy: 'static { + fn generate_solidity_interface(tc: &TypeCollector) -> String; +} +pub trait SolidityEnumTy: 'static { + fn generate_solidity_interface(tc: &TypeCollector) -> String; + fn solidity_option(&self) -> &str; +} + +pub trait SolidityArguments { + fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result; + fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result; + fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result; + fn is_empty(&self) -> bool { + self.len() == 0 + } + fn len(&self) -> usize; +} + +pub trait SolidityFunctions { + fn solidity_name( + &self, + is_impl: bool, + writer: &mut impl fmt::Write, + tc: &TypeCollector, + ) -> fmt::Result; +} + +pub trait SolidityItems { + fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result; + // For PhantomData fields + // fn is_void() +} diff --git a/crates/evm-coder/tests/abi_derive_generation.rs b/crates/evm-coder/tests/abi_derive_generation.rs new file mode 100644 index 0000000000..a2bd0b985a --- /dev/null +++ b/crates/evm-coder/tests/abi_derive_generation.rs @@ -0,0 +1,765 @@ +mod test_struct { + use evm_coder_procedural::AbiCoder; + use evm_coder::types::bytes; + + #[test] + fn empty_struct() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/build_failed/abi_derive_struct_generation.rs"); + } + + #[derive(AbiCoder, PartialEq, Debug)] + struct TypeStruct1SimpleParam { + _a: u8, + } + + #[derive(AbiCoder, PartialEq, Debug)] + struct TypeStruct1DynamicParam { + _a: String, + } + + #[derive(AbiCoder, PartialEq, Debug)] + struct TypeStruct2SimpleParam { + _a: u8, + _b: u32, + } + + #[derive(AbiCoder, PartialEq, Debug)] + struct TypeStruct2DynamicParam { + _a: String, + _b: bytes, + } + + #[derive(AbiCoder, PartialEq, Debug)] + struct TypeStruct2MixedParam { + _a: u8, + _b: bytes, + } + + #[derive(AbiCoder, PartialEq, Debug)] + struct TypeStruct1DerivedSimpleParam { + _a: TypeStruct1SimpleParam, + } + + #[derive(AbiCoder, PartialEq, Debug)] + struct TypeStruct2DerivedSimpleParam { + _a: TypeStruct1SimpleParam, + _b: TypeStruct2SimpleParam, + } + + #[derive(AbiCoder, PartialEq, Debug)] + struct TypeStruct1DerivedDynamicParam { + _a: TypeStruct1DynamicParam, + } + + #[derive(AbiCoder, PartialEq, Debug)] + struct TypeStruct2DerivedDynamicParam { + _a: TypeStruct1DynamicParam, + _b: TypeStruct2DynamicParam, + } + + /// Some docs + /// At multi + /// line + #[derive(AbiCoder, PartialEq, Debug)] + struct TypeStruct3DerivedMixedParam { + /// Docs for A + /// multi + /// line + _a: TypeStruct1SimpleParam, + /// Docs for B + _b: TypeStruct2DynamicParam, + /// Docs for C + _c: TypeStruct2MixedParam, + } + + #[test] + fn impl_abi_type_signature() { + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "(uint8)" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "(string)" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "(uint8,uint32)" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "(string,bytes)" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "(uint8,bytes)" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "((uint8))" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "((uint8),(uint8,uint32))" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "((string))" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "((string),(string,bytes))" + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + "((uint8),(string,bytes),(uint8,bytes))" + ); + } + + #[test] + fn impl_abi_type_is_dynamic() { + assert_eq!( + ::is_dynamic(), + false + ); + assert_eq!( + ::is_dynamic(), + true + ); + assert_eq!( + ::is_dynamic(), + false + ); + assert_eq!( + ::is_dynamic(), + true + ); + assert_eq!( + ::is_dynamic(), + true + ); + assert_eq!( + ::is_dynamic(), + false + ); + assert_eq!( + ::is_dynamic(), + false + ); + assert_eq!( + ::is_dynamic(), + true + ); + assert_eq!( + ::is_dynamic(), + true + ); + assert_eq!( + ::is_dynamic(), + true + ); + } + + #[test] + fn impl_abi_type_size() { + const ABI_ALIGNMENT: usize = 32; + assert_eq!( + ::size(), + ABI_ALIGNMENT + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT * 2 + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT * 2 + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT * 2 + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT * 3 + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT * 3 + ); + assert_eq!( + ::size(), + ABI_ALIGNMENT * 5 + ); + } + + #[derive(AbiCoder, PartialEq, Debug)] + struct TupleStruct1SimpleParam(u8); + + #[derive(AbiCoder, PartialEq, Debug)] + struct TupleStruct1DynamicParam(String); + + #[derive(AbiCoder, PartialEq, Debug)] + struct TupleStruct2SimpleParam(u8, u32); + + #[derive(AbiCoder, PartialEq, Debug)] + struct TupleStruct2DynamicParam(String, bytes); + + #[derive(AbiCoder, PartialEq, Debug)] + struct TupleStruct2MixedParam(u8, bytes); + + #[derive(AbiCoder, PartialEq, Debug)] + struct TupleStruct1DerivedSimpleParam(TupleStruct1SimpleParam); + + #[derive(AbiCoder, PartialEq, Debug)] + struct TupleStruct2DerivedSimpleParam(TupleStruct1SimpleParam, TupleStruct2SimpleParam); + + #[derive(AbiCoder, PartialEq, Debug)] + struct TupleStruct1DerivedDynamicParam(TupleStruct1DynamicParam); + + #[derive(AbiCoder, PartialEq, Debug)] + struct TupleStruct2DerivedDynamicParam(TupleStruct1DynamicParam, TupleStruct2DynamicParam); + + /// Some docs + /// At multi + /// line + #[derive(AbiCoder, PartialEq, Debug)] + struct TupleStruct3DerivedMixedParam( + /// Docs for A + /// multi + /// line + TupleStruct1SimpleParam, + TupleStruct2DynamicParam, + /// Docs for C + TupleStruct2MixedParam, + ); + + #[test] + fn impl_abi_type_signature_same_for_structs() { + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + ::SIGNATURE + .as_str() + .unwrap() + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + ::SIGNATURE + .as_str() + .unwrap() + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + ::SIGNATURE + .as_str() + .unwrap() + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + ::SIGNATURE + .as_str() + .unwrap() + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + ::SIGNATURE + .as_str() + .unwrap(), + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + ::SIGNATURE + .as_str() + .unwrap(), + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + ::SIGNATURE + .as_str() + .unwrap(), + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + ::SIGNATURE + .as_str() + .unwrap(), + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + ::SIGNATURE + .as_str() + .unwrap(), + ); + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + ::SIGNATURE + .as_str() + .unwrap(), + ); + } + + #[test] + fn impl_abi_type_is_dynamic_same_for_structs() { + assert_eq!( + ::is_dynamic(), + ::is_dynamic() + ); + assert_eq!( + ::is_dynamic(), + ::is_dynamic() + ); + assert_eq!( + ::is_dynamic(), + ::is_dynamic() + ); + assert_eq!( + ::is_dynamic(), + ::is_dynamic() + ); + assert_eq!( + ::is_dynamic(), + ::is_dynamic() + ); + assert_eq!( + ::is_dynamic(), + ::is_dynamic() + ); + assert_eq!( + ::is_dynamic(), + ::is_dynamic() + ); + assert_eq!( + ::is_dynamic(), + ::is_dynamic() + ); + assert_eq!( + ::is_dynamic(), + ::is_dynamic() + ); + assert_eq!( + ::is_dynamic(), + ::is_dynamic() + ); + } + + #[test] + fn impl_abi_type_size_same_for_structs() { + assert_eq!( + ::size(), + ::size() + ); + assert_eq!( + ::size(), + ::size() + ); + assert_eq!( + ::size(), + ::size() + ); + assert_eq!( + ::size(), + ::size() + ); + assert_eq!( + ::size(), + ::size() + ); + assert_eq!( + ::size(), + ::size() + ); + assert_eq!( + ::size(), + ::size() + ); + assert_eq!( + ::size(), + ::size() + ); + assert_eq!( + ::size(), + ::size() + ); + assert_eq!( + ::size(), + ::size() + ); + } + + const FUNCTION_IDENTIFIER: u32 = 0xdeadbeef; + + fn test_impl( + tuple_data: Tuple, + tuple_struct_data: TupleStruct, + type_struct_data: TypeStruct, + ) where + TypeStruct: evm_coder::abi::AbiWrite + + evm_coder::abi::AbiRead + + std::cmp::PartialEq + + std::fmt::Debug, + TupleStruct: evm_coder::abi::AbiWrite + + evm_coder::abi::AbiRead + + std::cmp::PartialEq + + std::fmt::Debug, + Tuple: evm_coder::abi::AbiWrite + + evm_coder::abi::AbiRead + + std::cmp::PartialEq + + std::fmt::Debug, + { + let encoded_type_struct = test_abi_write_impl(&type_struct_data); + let encoded_tuple_struct = test_abi_write_impl(&tuple_struct_data); + let encoded_tuple = test_abi_write_impl(&tuple_data); + + similar_asserts::assert_eq!(encoded_tuple, encoded_type_struct); + similar_asserts::assert_eq!(encoded_tuple, encoded_tuple_struct); + + { + let (_, mut decoder) = evm_coder::abi::AbiReader::new_call(&encoded_tuple).unwrap(); + let restored_struct_data = ::abi_read(&mut decoder).unwrap(); + assert_eq!(restored_struct_data, type_struct_data); + } + { + let (_, mut decoder) = evm_coder::abi::AbiReader::new_call(&encoded_tuple).unwrap(); + let restored_struct_data = ::abi_read(&mut decoder).unwrap(); + assert_eq!(restored_struct_data, tuple_struct_data); + } + + { + let (_, mut decoder) = + evm_coder::abi::AbiReader::new_call(&encoded_type_struct).unwrap(); + let restored_tuple_data = ::abi_read(&mut decoder).unwrap(); + assert_eq!(restored_tuple_data, tuple_data); + } + { + let (_, mut decoder) = + evm_coder::abi::AbiReader::new_call(&encoded_tuple_struct).unwrap(); + let restored_tuple_data = ::abi_read(&mut decoder).unwrap(); + assert_eq!(restored_tuple_data, tuple_data); + } + } + + fn test_abi_write_impl(data: &A) -> Vec + where + A: evm_coder::abi::AbiWrite + + evm_coder::abi::AbiRead + + std::cmp::PartialEq + + std::fmt::Debug, + { + let mut writer = evm_coder::abi::AbiWriter::new_call(FUNCTION_IDENTIFIER); + data.abi_write(&mut writer); + let encoded_tuple = writer.finish(); + encoded_tuple + } + + #[test] + fn codec_struct_1_simple() { + let _a = 0xff; + test_impl::<(u8,), TupleStruct1SimpleParam, TypeStruct1SimpleParam>( + (_a,), + TupleStruct1SimpleParam(_a), + TypeStruct1SimpleParam { _a }, + ); + } + + #[test] + fn codec_struct_1_dynamic() { + let _a: String = "some string".into(); + test_impl::<(String,), TupleStruct1DynamicParam, TypeStruct1DynamicParam>( + (_a.clone(),), + TupleStruct1DynamicParam(_a.clone()), + TypeStruct1DynamicParam { _a }, + ); + } + + #[test] + fn codec_struct_1_derived_simple() { + let _a: u8 = 0xff; + test_impl::<((u8,),), TupleStruct1DerivedSimpleParam, TypeStruct1DerivedSimpleParam>( + ((_a,),), + TupleStruct1DerivedSimpleParam(TupleStruct1SimpleParam(_a)), + TypeStruct1DerivedSimpleParam { + _a: TypeStruct1SimpleParam { _a }, + }, + ); + } + + #[test] + fn codec_struct_1_derived_dynamic() { + let _a: String = "some string".into(); + test_impl::<((String,),), TupleStruct1DerivedDynamicParam, TypeStruct1DerivedDynamicParam>( + ((_a.clone(),),), + TupleStruct1DerivedDynamicParam(TupleStruct1DynamicParam(_a.clone())), + TypeStruct1DerivedDynamicParam { + _a: TypeStruct1DynamicParam { _a }, + }, + ); + } + + #[test] + fn codec_struct_2_simple() { + let _a = 0xff; + let _b = 0xbeefbaba; + test_impl::<(u8, u32), TupleStruct2SimpleParam, TypeStruct2SimpleParam>( + (_a, _b), + TupleStruct2SimpleParam(_a, _b), + TypeStruct2SimpleParam { _a, _b }, + ); + } + + #[test] + fn codec_struct_2_dynamic() { + let _a: String = "some string".into(); + let _b: bytes = bytes(vec![0x11, 0x22, 0x33]); + test_impl::<(String, bytes), TupleStruct2DynamicParam, TypeStruct2DynamicParam>( + (_a.clone(), _b.clone()), + TupleStruct2DynamicParam(_a.clone(), _b.clone()), + TypeStruct2DynamicParam { _a, _b }, + ); + } + + #[test] + fn codec_struct_2_mixed() { + let _a: u8 = 0xff; + let _b: bytes = bytes(vec![0x11, 0x22, 0x33]); + test_impl::<(u8, bytes), TupleStruct2MixedParam, TypeStruct2MixedParam>( + (_a.clone(), _b.clone()), + TupleStruct2MixedParam(_a.clone(), _b.clone()), + TypeStruct2MixedParam { _a, _b }, + ); + } + + #[test] + fn codec_struct_2_derived_simple() { + let _a = 0xff; + let _b = 0xbeefbaba; + test_impl::< + ((u8,), (u8, u32)), + TupleStruct2DerivedSimpleParam, + TypeStruct2DerivedSimpleParam, + >( + ((_a,), (_a, _b)), + TupleStruct2DerivedSimpleParam( + TupleStruct1SimpleParam(_a), + TupleStruct2SimpleParam(_a, _b), + ), + TypeStruct2DerivedSimpleParam { + _a: TypeStruct1SimpleParam { _a }, + _b: TypeStruct2SimpleParam { _a, _b }, + }, + ); + } + + #[test] + fn codec_struct_2_derived_dynamic() { + let _a = "some string".to_string(); + let _b = bytes(vec![0x11, 0x22, 0x33]); + test_impl::< + ((String,), (String, bytes)), + TupleStruct2DerivedDynamicParam, + TypeStruct2DerivedDynamicParam, + >( + ((_a.clone(),), (_a.clone(), _b.clone())), + TupleStruct2DerivedDynamicParam( + TupleStruct1DynamicParam(_a.clone()), + TupleStruct2DynamicParam(_a.clone(), _b.clone()), + ), + TypeStruct2DerivedDynamicParam { + _a: TypeStruct1DynamicParam { _a: _a.clone() }, + _b: TypeStruct2DynamicParam { _a, _b }, + }, + ); + } + + #[test] + fn codec_struct_3_derived_mixed() { + let int = 0xff; + let by = bytes(vec![0x11, 0x22, 0x33]); + let string = "some string".to_string(); + test_impl::< + ((u8,), (String, bytes), (u8, bytes)), + TupleStruct3DerivedMixedParam, + TypeStruct3DerivedMixedParam, + >( + ((int,), (string.clone(), by.clone()), (int, by.clone())), + TupleStruct3DerivedMixedParam( + TupleStruct1SimpleParam(int), + TupleStruct2DynamicParam(string.clone(), by.clone()), + TupleStruct2MixedParam(int, by.clone()), + ), + TypeStruct3DerivedMixedParam { + _a: TypeStruct1SimpleParam { _a: int }, + _b: TypeStruct2DynamicParam { + _a: string.clone(), + _b: by.clone(), + }, + _c: TypeStruct2MixedParam { _a: int, _b: by }, + }, + ); + } + + #[derive(AbiCoder, PartialEq, Debug)] + struct TypeStruct2SimpleStruct1Simple { + _a: TypeStruct2SimpleParam, + _b: TypeStruct2SimpleParam, + _c: u8, + } + #[derive(AbiCoder, PartialEq, Debug)] + struct TupleStruct2SimpleStruct1Simple(TupleStruct2SimpleParam, TupleStruct2SimpleParam, u8); + + #[test] + fn codec_struct_2_struct_simple_1_simple() { + let _a = 0xff; + let _b = 0xbeefbaba; + test_impl::< + ((u8, u32), (u8, u32), u8), + TupleStruct2SimpleStruct1Simple, + TypeStruct2SimpleStruct1Simple, + >( + ((_a, _b), (_a, _b), _a), + TupleStruct2SimpleStruct1Simple( + TupleStruct2SimpleParam(_a, _b), + TupleStruct2SimpleParam(_a, _b), + _a, + ), + TypeStruct2SimpleStruct1Simple { + _a: TypeStruct2SimpleParam { _a, _b }, + _b: TypeStruct2SimpleParam { _a, _b }, + _c: _a, + }, + ); + } +} + +mod test_enum { + use evm_coder::AbiCoder; + + /// Some docs + /// At multi + /// line + #[derive(AbiCoder, Debug, PartialEq, Default, Clone, Copy)] + #[repr(u8)] + enum Color { + /// Docs for Red + /// multi + /// line + Red, + Green, + /// Docs for Blue + #[default] + Blue, + } + + #[test] + fn empty() {} + + #[test] + fn bad_enums() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/build_failed/abi_derive_enum_generation.rs"); + } + + #[test] + fn impl_abi_type_signature_same_for_structs() { + assert_eq!( + ::SIGNATURE + .as_str() + .unwrap(), + ::SIGNATURE.as_str().unwrap() + ); + } + + #[test] + fn impl_abi_type_is_dynamic_same_for_structs() { + assert_eq!( + ::is_dynamic(), + ::is_dynamic() + ); + } + + #[test] + fn impl_abi_type_size_same_for_structs() { + assert_eq!( + ::size(), + ::size() + ); + } + + #[test] + fn test_coder() { + const FUNCTION_IDENTIFIER: u32 = 0xdeadbeef; + + let encoded_enum = { + let mut writer = evm_coder::abi::AbiWriter::new_call(FUNCTION_IDENTIFIER); + ::abi_write(&Color::Green, &mut writer); + writer.finish() + }; + + let encoded_u8 = { + let mut writer = evm_coder::abi::AbiWriter::new_call(FUNCTION_IDENTIFIER); + ::abi_write(&(Color::Green as u8), &mut writer); + writer.finish() + }; + + similar_asserts::assert_eq!(encoded_enum, encoded_u8); + + { + let (_, mut decoder) = evm_coder::abi::AbiReader::new_call(&encoded_enum).unwrap(); + let restored_enum_data = + ::abi_read(&mut decoder).unwrap(); + assert_eq!(restored_enum_data, Color::Green); + } + } +} diff --git a/crates/evm-coder/tests/build_failed/abi_derive_enum_generation.rs b/crates/evm-coder/tests/build_failed/abi_derive_enum_generation.rs new file mode 100644 index 0000000000..bcc8ed7855 --- /dev/null +++ b/crates/evm-coder/tests/build_failed/abi_derive_enum_generation.rs @@ -0,0 +1,36 @@ +use evm_coder_procedural::AbiCoder; + +#[derive(AbiCoder)] +enum NonRepr { + A, + B, + C, +} + +#[derive(AbiCoder)] +#[repr(u32)] +enum NonReprU8 { + A, + B, + C, +} + +#[derive(AbiCoder)] +#[repr(u8)] +enum RustEnum { + A(u128), + B, + C, +} + +#[derive(AbiCoder)] +#[repr(u8)] +enum WithExplicit { + A = 128, + B, + C, +} + +fn main() { + assert!(false); +} diff --git a/crates/evm-coder/tests/build_failed/abi_derive_enum_generation.stderr b/crates/evm-coder/tests/build_failed/abi_derive_enum_generation.stderr new file mode 100644 index 0000000000..3116136c5b --- /dev/null +++ b/crates/evm-coder/tests/build_failed/abi_derive_enum_generation.stderr @@ -0,0 +1,23 @@ +error: Enum is not "repr(u8)" + --> tests/build_failed/abi_derive_enum_generation.rs:4:6 + | +4 | enum NonRepr { + | ^^^^^^^ + +error: Enum is not "repr(u8)" + --> tests/build_failed/abi_derive_enum_generation.rs:11:8 + | +11 | #[repr(u32)] + | ^^^ + +error: Enumeration parameters should not have fields + --> tests/build_failed/abi_derive_enum_generation.rs:21:2 + | +21 | A(u128), + | ^ + +error: Enumeration options should not have an explicit specified value + --> tests/build_failed/abi_derive_enum_generation.rs:29:2 + | +29 | A = 128, + | ^ diff --git a/crates/evm-coder/tests/build_failed/abi_derive_struct_generation.rs b/crates/evm-coder/tests/build_failed/abi_derive_struct_generation.rs new file mode 100644 index 0000000000..0cd54290b0 --- /dev/null +++ b/crates/evm-coder/tests/build_failed/abi_derive_struct_generation.rs @@ -0,0 +1,11 @@ +use evm_coder_procedural::AbiCoder; + +#[derive(AbiCoder, PartialEq, Debug)] +struct EmptyStruct {} + +#[derive(AbiCoder, PartialEq, Debug)] +struct EmptyTupleStruct(); + +fn main() { + assert!(false); +} diff --git a/crates/evm-coder/tests/build_failed/abi_derive_struct_generation.stderr b/crates/evm-coder/tests/build_failed/abi_derive_struct_generation.stderr new file mode 100644 index 0000000000..716a06f1b9 --- /dev/null +++ b/crates/evm-coder/tests/build_failed/abi_derive_struct_generation.stderr @@ -0,0 +1,11 @@ +error: Empty structs not supported + --> tests/build_failed/abi_derive_struct_generation.rs:4:8 + | +4 | struct EmptyStruct {} + | ^^^^^^^^^^^ + +error: Empty structs not supported + --> tests/build_failed/abi_derive_struct_generation.rs:7:8 + | +7 | struct EmptyTupleStruct(); + | ^^^^^^^^^^^^^^^^ diff --git a/crates/evm-coder/tests/build_failed/custom_signature_over_max_size.rs b/crates/evm-coder/tests/build_failed/custom_signature_over_max_size.rs new file mode 100644 index 0000000000..f37f5a1f4e --- /dev/null +++ b/crates/evm-coder/tests/build_failed/custom_signature_over_max_size.rs @@ -0,0 +1,34 @@ +#![allow(dead_code)] +use std::str::from_utf8; + +use evm_coder::{ + make_signature, + custom_signature::{SignatureUnit, SIGNATURE_SIZE_LIMIT}, +}; + +trait Name { + const SIGNATURE: SignatureUnit; + + fn name() -> &'static str { + from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8") + } +} + +impl Name for Vec { + const SIGNATURE: SignatureUnit = + evm_coder::make_signature!(new nameof(T::SIGNATURE) fixed("[]")); +} + +struct MaxSize(); +impl Name for MaxSize { + const SIGNATURE: SignatureUnit = SignatureUnit { + data: [b'!'; SIGNATURE_SIZE_LIMIT], + len: SIGNATURE_SIZE_LIMIT, + }; +} + +const NAME: SignatureUnit = >::SIGNATURE; + +fn main() { + assert!(false); +} diff --git a/crates/evm-coder/tests/build_failed/custom_signature_over_max_size.stderr b/crates/evm-coder/tests/build_failed/custom_signature_over_max_size.stderr new file mode 100644 index 0000000000..e6ea2ee4e1 --- /dev/null +++ b/crates/evm-coder/tests/build_failed/custom_signature_over_max_size.stderr @@ -0,0 +1,21 @@ +warning: unused import: `make_signature` + --> tests/build_failed/custom_signature_over_max_size.rs:5:2 + | +5 | make_signature, + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default + +error[E0080]: evaluation of ` as Name>::SIGNATURE` failed + --> tests/build_failed/custom_signature_over_max_size.rs:19:3 + | +19 | evm_coder::make_signature!(new nameof(T::SIGNATURE) fixed("[]")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 256 but the index is 256 + | + = note: this error originates in the macro `$crate::make_signature` which comes from the expansion of the macro `evm_coder::make_signature` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> tests/build_failed/custom_signature_over_max_size.rs:30:29 + | +30 | const NAME: SignatureUnit = >::SIGNATURE; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors diff --git a/crates/evm-coder/tests/random.rs b/crates/evm-coder/tests/random.rs index 47acff7280..d5787d8944 100644 --- a/crates/evm-coder/tests/random.rs +++ b/crates/evm-coder/tests/random.rs @@ -16,7 +16,9 @@ #![allow(dead_code)] // This test only checks that macros is not panicking -use evm_coder::{ToLog, execution::Result, solidity_interface, types::*, solidity, weight}; +use evm_coder::{ + abi::AbiType, ToLog, execution::Result, solidity_interface, types::*, solidity, weight, +}; pub struct Impls; diff --git a/crates/evm-coder/tests/solidity_generation.rs b/crates/evm-coder/tests/solidity_generation.rs index 7ddc8ea500..a286b2de3d 100644 --- a/crates/evm-coder/tests/solidity_generation.rs +++ b/crates/evm-coder/tests/solidity_generation.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -use evm_coder::{execution::Result, generate_stubgen, solidity_interface, types::*}; +use evm_coder::{abi::AbiType, execution::Result, generate_stubgen, solidity_interface, types::*}; pub struct ERC20; diff --git a/examples/package.json b/examples/package.json index 6a68e5f5ba..12ba25480d 100644 --- a/examples/package.json +++ b/examples/package.json @@ -7,7 +7,7 @@ "test": "test" }, "devDependencies": { - "got": "^10.7.0" + "got": "^11.8.5" }, "scripts": { "test": "" diff --git a/kb/how-not-to-break-rpc.md b/kb/how-not-to-break-rpc.md new file mode 100644 index 0000000000..1464aa8a0c --- /dev/null +++ b/kb/how-not-to-break-rpc.md @@ -0,0 +1,169 @@ +# How not to break RPC + +Let's discuss how to avoid the breaking of RPC with an example of how the `colection_by_id` RPC method was broken. + +The `collection_by_id` was broken due to the change of the result type `RpcCollection`. +The new version of the `RpcCollection` was incompatible with the old one due to addition of the `flags` field: + +```rust +// The new version of the `RpcCollection` +pub struct RpcCollection { + /// Collection owner account. + pub owner: AccountId, + /// Collection mode. + pub mode: CollectionMode, + /// Collection name. + pub name: Vec, + /// Collection description. + pub description: Vec, + /// Token prefix. + pub token_prefix: Vec, + /// The state of sponsorship of the collection. + pub sponsorship: SponsorshipState, + /// Collection limits. + pub limits: CollectionLimits, + /// Collection permissions. + pub permissions: CollectionPermissions, + /// Token property permissions. + pub token_property_permissions: Vec, + /// Collection properties. + pub properties: Vec, + /// Is collection read only. + pub read_only: bool, + + /// Extra collection flags + pub flags: RpcCollectionFlags, // <-- THIS IS A NEW FIELD! +} +``` + +### Where exactly was RPC broken? + +To answer this question, we need to describe the process of handling an RPC call. + +1. A user calls an RPC method. +2. The node sees what method with what arguments should be executed. +3. Since the code of each RPC method is located inside the runtime, the node does the following: + - The node encodes the RPC arguments into the [SCALE format](https://docs.substrate.io/reference/scale-codec/), and then it will call the corresponding method of the runtime API with the encoded arguments. + - The runtime executes the RPC logic and then returns the SCALE-encoded result. + - The node receives the result from the runtime and then decodes it. **It is the place where RPC could break!** + +Point #3 describes a process implemented inside the [`pass_method`](https://github.com/UniqueNetwork/unique-chain/blob/1c7179877b5fb1eacf86c5ecf607317d11999675/client/rpc/src/lib.rs#L435-L472) macro. + +Using the `pass_method` macro the node maps each RPC method onto the corresponding runtime API method. + +See how [the node's RPC is implemented](https://github.com/UniqueNetwork/unique-chain/blob/1c7179877b5fb1eacf86c5ecf607317d11999675/client/rpc/src/lib.rs#L493-L569) and how [the runtime API is declared](https://github.com/UniqueNetwork/unique-chain/blob/1c7179877b5fb1eacf86c5ecf607317d11999675/primitives/rpc/src/lib.rs#L32-L129). + +### How can the node use the old runtime API? + +As you can see from the previous section -- RPC breaks if the runtime API data format is incompatible with the node's RPC data format. + +When the node is working with an old runtime and exposes the new version of RPC that contains some methods with a changed signature, the node should call only the old versions of these methods to avoid RPC failure. + +The node should do the following to get an old runtime API method to run correctly: +* The node should convert all the RPC arguments into the old runtime API format. +* It should convert the result from the runtime to the new data format (it is the only action needed in the case of `collection_by_id`). + +The `pass_method` macro can call the old runtime API methods. +For instance, the correct implementation of the `collection_by_id` RPC method looks like this: +```rust +pass_method!( + /* line 1 */ collection_by_id(collection: CollectionId) -> Option>, unique_api; + /* line 2 */ changed_in 3, collection_by_id_before_version_3(collection) => |value| value.map(|coll| coll.into()) +); +``` + +The first line describes the newest RPC signature. + +The second line tells us what should be called in the case if we're dealing with an old runtime API. +* `collection_by_id_before_version_3` -- the name of the corresponding runtime API method with an old signature. +* `(collection)` -- what arguments should the node pass to the old method. In the case of `collection_by_id`, we pass the arguments as is since there were no changes to the arguments' types. +* `=> |value| value.map(|coll| coll.into())` -- describes how to transform the return value from the old runtime API data format into the new RPC data format. + +### Runtime API backward compatibility support + +Methods like `collection_by_id_before_version_3` doesn't appear automatically. + +When changing the runtime API methods' signatures, we need to: +* Specify the number of the new version of the runtime API. +* Specify the old versions of the changed methods. + +See the documentation of the `decl_runtime_apis` macro: [runtime api trait versioning](https://docs.rs/sp-api/latest/sp_api/macro.decl_runtime_apis.html#runtime-api-trait-versioning). + +### How to easily implement the converting from the old structure into the new ones + +To describe structures that can have some fields changing over different versions, we use the `#[struct_versioning::versioned]` attribute. + +Let's take a look at the `RpcCollection` declaration. + +```rust +/// Collection parameters, used in RPC calls (see [`Collection`] for the storage version). +#[struct_versioning::versioned(version = 2, upper)] +#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct RpcCollection { + /// Collection owner account. + pub owner: AccountId, + + /// Collection mode. + pub mode: CollectionMode, + + /// Collection name. + pub name: Vec, + + /// Collection description. + pub description: Vec, + + /// Token prefix. + pub token_prefix: Vec, + + /// The state of sponsorship of the collection. + pub sponsorship: SponsorshipState, + + /// Collection limits. + pub limits: CollectionLimits, + + /// Collection permissions. + pub permissions: CollectionPermissions, + + /// Token property permissions. + pub token_property_permissions: Vec, + + /// Collection properties. + pub properties: Vec, + + /// Is collection read only. + pub read_only: bool, + + /// Extra collection flags + #[version(2.., upper(RpcCollectionFlags {foreign: false, erc721metadata: false}))] + pub flags: RpcCollectionFlags, +} +``` + +The `#[struct_versioning::versioned]` will create 2 types for us: the `RpcCollectionVersion1` (the old version) and the `RpcCollection` (the new version). + +This attribute automatically implements the `impl From for RpcCollection`. + +The attribute understands how to map the old fields to new ones with the help of the `#[version(...)]` field attribute, which should be placed right before the field in question. + +There were no field `flags` in the `RpcCollectionVersion1` structure. The `#[version(2.., upper())]` tells the attribute to assign the `flags` field to `` in the new version of the `RpcCollection` structure. + +Given that we have the `From` trait implemented for the new version of the `RpcCollection`, we can use `.into()` to convert the old version to the new one as we did in the `pass_method` macro above. + +Here is the description of the `struct_versioning` attribute: +``` +Generate versioned variants of a struct + + `#[versioned(version = 1[, first_version = 1][, upper][, versions])]` + - *version* - current version of a struct + - *first_version* - allows to skip generation of structs, which predates first supported version + - *upper* - generate From impls, which converts old version of structs to new + - *versions* - generate enum, which contains all possible versions of struct + + Each field may have version attribute + `#[version([1]..[2][, upper(old)])]` + - *1* - version, on which this field is appeared + - *2* - version, in which this field was removed + (i.e if set to 2, this field was exist on version 1, and no longer exist on version 2) + - *upper* - code, which should be executed to transform old value to new/create new value +``` diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index 0b75fe0be3..7e4b1919e1 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -3,7 +3,7 @@ [build-dependencies.substrate-build-script-utils] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" ################################################################################ # Substrate Dependecies @@ -16,158 +16,159 @@ version = '3.1.2' [dependencies.frame-benchmarking] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-benchmarking-cli] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.try-runtime-cli] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-transaction-payment-rpc] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.substrate-prometheus-endpoint] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-basic-authorship] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-chain-spec] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-cli] -features = ['wasmtime'] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-client-api] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-consensus] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-consensus-aura] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-executor] -features = ['wasmtime'] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-finality-grandpa] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-keystore] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-rpc] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-rpc-api] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-service] -features = ['wasmtime'] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-telemetry] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-transaction-pool] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-tracing] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-sysinfo] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-block-builder] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-api] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-blockchain] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-consensus] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-consensus-aura] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-core] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" + +[dependencies.sp-io] +git = "https://github.com/paritytech/substrate" +branch = "polkadot-v0.9.36" [dependencies.sp-finality-grandpa] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-inherents] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-keystore] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-offchain] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-runtime] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-session] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-timestamp] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-transaction-pool] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-trie] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.substrate-frame-rpc-system] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sc-network] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.serde] features = ['derive'] @@ -178,76 +179,76 @@ version = '1.0.68' [dependencies.sc-consensus-manual-seal] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" ################################################################################ # Cumulus dependencies [dependencies.cumulus-client-consensus-aura] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.cumulus-client-consensus-common] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.cumulus-client-collator] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.cumulus-client-cli] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.cumulus-client-network] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.cumulus-primitives-core] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.cumulus-primitives-parachain-inherent] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.cumulus-client-service] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.cumulus-relay-chain-interface] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.cumulus-relay-chain-inprocess-interface] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" -[dependencies.cumulus-relay-chain-rpc-interface] +[dependencies.cumulus-relay-chain-minimal-node] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" ################################################################################ # Polkadot dependencies [dependencies.polkadot-primitives] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" [dependencies.polkadot-service] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" [dependencies.polkadot-cli] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" [dependencies.polkadot-test-service] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" [dependencies.polkadot-parachain] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" ################################################################################ @@ -277,7 +278,7 @@ path = "../../primitives/rpc" [dependencies.pallet-transaction-payment-rpc-runtime-api] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" ################################################################################ # Package @@ -291,7 +292,7 @@ homepage = 'https://unique.network' license = 'GPLv3' name = 'unique-node' repository = 'https://github.com/UniqueNetwork/unique-chain' -version = "0.9.30" +version.workspace = true [[bin]] name = 'unique-collator' @@ -303,23 +304,25 @@ targets = ['x86_64-unknown-linux-gnu'] [dependencies] futures = '0.3.17' log = '0.4.16' -flexi_logger = "0.22.5" +flexi_logger = "0.24.2" parking_lot = '0.12.1' -clap = "3.1.2" -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +clap = "4.0.9" +jsonrpsee = { version = "0.16.2", features = ["server", "macros"] } tokio = { version = "1.19.2", features = ["time"] } -fc-rpc-core = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fc-consensus = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fc-mapping-sync = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fc-rpc = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fc-db = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fp-rpc = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +fc-rpc-core = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fc-consensus = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fc-mapping-sync = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fc-rpc = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fc-db = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-rpc = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } unique-rpc = { default-features = false, path = "../rpc" } +uc-rpc = { default-features = false, path = "../../client/rpc" } app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false } rmrk-rpc = { path = "../../primitives/rmrk-rpc" } +up-pov-estimate-rpc = { path = "../../primitives/pov-estimate-rpc", default-features = false } [features] default = ["opal-runtime"] @@ -328,14 +331,20 @@ runtime-benchmarks = [ 'quartz-runtime?/runtime-benchmarks', 'opal-runtime/runtime-benchmarks', 'polkadot-service/runtime-benchmarks', + 'polkadot-cli/runtime-benchmarks', 'sc-service/runtime-benchmarks', ] try-runtime = [ 'unique-runtime?/try-runtime', 'quartz-runtime?/try-runtime', 'opal-runtime?/try-runtime', + 'try-runtime-cli/try-runtime', ] -sapphire-runtime = [ - 'opal-runtime', - 'opal-runtime/become-sapphire', +sapphire-runtime = ['opal-runtime', 'opal-runtime/become-sapphire'] +pov-estimate = [ + 'unique-runtime?/pov-estimate', + 'quartz-runtime?/pov-estimate', + 'opal-runtime/pov-estimate', + 'uc-rpc/pov-estimate', + 'unique-rpc/pov-estimate', ] diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 20077a5607..fbe569fa68 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -54,17 +54,6 @@ pub type DefaultChainSpec = QuartzChainSpec; #[cfg(all(not(feature = "unique-runtime"), not(feature = "quartz-runtime")))] pub type DefaultChainSpec = OpalChainSpec; -pub enum RuntimeId { - #[cfg(feature = "unique-runtime")] - Unique, - - #[cfg(feature = "quartz-runtime")] - Quartz, - - Opal, - Unknown(String), -} - #[cfg(not(feature = "unique-runtime"))] /// PARA_ID for Opal/Sapphire/Quartz const PARA_ID: u32 = 2095; diff --git a/node/cli/src/cli.rs b/node/cli/src/cli.rs index 678029d8a0..2db2d730f7 100644 --- a/node/cli/src/cli.rs +++ b/node/cli/src/cli.rs @@ -56,7 +56,12 @@ pub enum Subcommand { Benchmark(frame_benchmarking_cli::BenchmarkCmd), /// Try runtime + #[cfg(feature = "try-runtime")] TryRuntime(try_runtime_cli::TryRuntimeCmd), + + /// Try runtime. Note: `try-runtime` feature must be enabled. + #[cfg(not(feature = "try-runtime"))] + TryRuntime, } #[derive(Debug, Parser)] diff --git a/node/cli/src/command.rs b/node/cli/src/command.rs index 211e6b6b75..fa894c6442 100644 --- a/node/cli/src/command.rs +++ b/node/cli/src/command.rs @@ -33,12 +33,12 @@ // limitations under the License. use crate::{ - chain_spec::{ - self, RuntimeId, RuntimeIdentification, ServiceId, ServiceIdentification, default_runtime, - }, + chain_spec::{self, RuntimeIdentification, ServiceId, ServiceIdentification}, cli::{Cli, RelayChainCli, Subcommand}, service::{new_partial, start_node, start_dev_node}, }; +#[cfg(feature = "runtime-benchmarks")] +use crate::chain_spec::default_runtime; #[cfg(feature = "unique-runtime")] use crate::service::UniqueRuntimeExecutor; @@ -46,12 +46,14 @@ use crate::service::UniqueRuntimeExecutor; #[cfg(feature = "quartz-runtime")] use crate::service::QuartzRuntimeExecutor; -use crate::service::{OpalRuntimeExecutor, DefaultRuntimeExecutor}; +use crate::service::OpalRuntimeExecutor; + +#[cfg(feature = "runtime-benchmarks")] +use crate::service::DefaultRuntimeExecutor; use codec::Encode; use cumulus_primitives_core::ParaId; use cumulus_client_cli::generate_genesis_block; -use std::{future::Future, pin::Pin}; use log::info; use sc_cli::{ ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, @@ -64,13 +66,13 @@ use sp_core::hexdisplay::HexDisplay; use sp_runtime::traits::{AccountIdConversion, Block as BlockT}; use std::{net::SocketAddr, time::Duration}; -use up_common::types::opaque::Block; +use up_common::types::opaque::{Block, RuntimeId}; macro_rules! no_runtime_err { - ($chain_name:expr) => { + ($runtime_id:expr) => { format!( - "No runtime valid runtime was found for chain {}", - $chain_name + "No runtime valid runtime was found for chain {:#?}", + $runtime_id ) }; } @@ -92,7 +94,7 @@ fn load_spec(id: &str) -> std::result::Result, St RuntimeId::Quartz => Box::new(chain_spec::QuartzChainSpec::from_json_file(path)?), RuntimeId::Opal => chain_spec, - RuntimeId::Unknown(chain) => return Err(no_runtime_err!(chain)), + runtime_id => return Err(no_runtime_err!(runtime_id)), } } }) @@ -145,7 +147,7 @@ impl SubstrateCli for Cli { RuntimeId::Quartz => &quartz_runtime::VERSION, RuntimeId::Opal => &opal_runtime::VERSION, - RuntimeId::Unknown(chain) => panic!("{}", no_runtime_err!(chain)), + runtime_id => panic!("{}", no_runtime_err!(runtime_id)), } } } @@ -233,7 +235,7 @@ macro_rules! construct_async_run { runner, $components, $cli, $cmd, $config, $( $code )* ), - RuntimeId::Unknown(chain) => Err(no_runtime_err!(chain).into()) + runtime_id => Err(no_runtime_err!(runtime_id).into()) } }} } @@ -272,7 +274,7 @@ macro_rules! construct_sync_run { runner, $components, $cli, $cmd, $config, $( $code )* ), - RuntimeId::Unknown(chain) => Err(no_runtime_err!(chain).into()) + runtime_id => Err(no_runtime_err!(runtime_id).into()) } }} } @@ -300,7 +302,7 @@ macro_rules! start_node_using_chain_runtime { OpalRuntimeExecutor, >($config $(, $($args),+)?) $($code)*, - RuntimeId::Unknown(chain) => Err(no_runtime_err!(chain).into()), + runtime_id => Err(no_runtime_err!(runtime_id).into()), } }; } @@ -407,40 +409,51 @@ pub fn run() -> Result<()> { } } } + #[cfg(feature = "try-runtime")] Some(Subcommand::TryRuntime(cmd)) => { - if cfg!(feature = "try-runtime") { - let runner = cli.create_runner(cmd)?; - - // grab the task manager. - let registry = &runner - .config() - .prometheus_config - .as_ref() - .map(|cfg| &cfg.registry); - let task_manager = - sc_service::TaskManager::new(runner.config().tokio_handle.clone(), *registry) - .map_err(|e| format!("Error: {:?}", e))?; - - runner.async_run(|config| -> Result<(Pin>>, _)> { - Ok(( - match config.chain_spec.runtime_id() { - #[cfg(feature = "unique-runtime")] - RuntimeId::Unique => Box::pin(cmd.run::(config)), - - #[cfg(feature = "quartz-runtime")] - RuntimeId::Quartz => Box::pin(cmd.run::(config)), - - RuntimeId::Opal => { - Box::pin(cmd.run::(config)) - } - RuntimeId::Unknown(chain) => return Err(no_runtime_err!(chain).into()), - }, - task_manager, - )) - }) - } else { - Err("Try-runtime must be enabled by `--features try-runtime`.".into()) - } + use std::{future::Future, pin::Pin}; + use sc_executor::{sp_wasm_interface::ExtendedHostFunctions, NativeExecutionDispatch}; + + let runner = cli.create_runner(cmd)?; + + // grab the task manager. + let registry = &runner + .config() + .prometheus_config + .as_ref() + .map(|cfg| &cfg.registry); + let task_manager = + sc_service::TaskManager::new(runner.config().tokio_handle.clone(), *registry) + .map_err(|e| format!("Error: {:?}", e))?; + + runner.async_run(|config| -> Result<(Pin>>, _)> { + Ok(( + match config.chain_spec.runtime_id() { + #[cfg(feature = "unique-runtime")] + RuntimeId::Unique => Box::pin(cmd.run::::ExtendHostFunctions, + >>()), + + #[cfg(feature = "quartz-runtime")] + RuntimeId::Quartz => Box::pin(cmd.run::::ExtendHostFunctions, + >>()), + + RuntimeId::Opal => Box::pin(cmd.run::::ExtendHostFunctions, + >>()), + runtime_id => return Err(no_runtime_err!(runtime_id).into()), + }, + task_manager, + )) + }) + } + #[cfg(not(feature = "try-runtime"))] + Some(Subcommand::TryRuntime) => { + Err("Try-runtime must be enabled by `--features try-runtime`.".into()) } None => { let runner = cli.create_runner(&cli.run.normalize())?; @@ -469,9 +482,8 @@ pub fn run() -> Result<()> { let autoseal_interval = Duration::from_millis(cli.idle_autoseal_interval); let mut config = config; - if config.state_pruning == None { - config.state_pruning = Some(sc_service::PruningMode::ArchiveAll); - } + + config.state_pruning = Some(sc_service::PruningMode::ArchiveAll); return start_node_using_chain_runtime! { start_dev_node(config, autoseal_interval).map_err(Into::into) diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 6972adcd1d..7088d17c46 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -34,7 +34,9 @@ use serde::{Serialize, Deserialize}; // Cumulus Imports use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion}; -use cumulus_client_consensus_common::ParachainConsensus; +use cumulus_client_consensus_common::{ + ParachainConsensus, ParachainBlockImport as TParachainBlockImport, +}; use cumulus_client_service::{ prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams, }; @@ -43,10 +45,10 @@ use cumulus_client_network::BlockAnnounceValidator; use cumulus_primitives_core::ParaId; use cumulus_relay_chain_inprocess_interface::build_inprocess_relay_chain; use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, RelayChainResult}; -use cumulus_relay_chain_rpc_interface::{RelayChainRpcInterface, create_client_and_start_worker}; +use cumulus_relay_chain_minimal_node::build_minimal_relay_chain_node; // Substrate Imports -use sc_client_api::ExecutorProvider; +use sp_api::BlockT; use sc_executor::NativeElseWasmExecutor; use sc_executor::NativeExecutionDispatch; use sc_network::{NetworkService, NetworkBlock}; @@ -56,6 +58,7 @@ use sp_keystore::SyncCryptoStorePtr; use sp_runtime::traits::BlakeTwo256; use substrate_prometheus_endpoint::Registry; use sc_client_api::BlockchainEvents; +use sc_consensus::ImportQueue; use polkadot_service::CollatorPair; @@ -63,9 +66,10 @@ use polkadot_service::CollatorPair; use fc_rpc_core::types::FilterPool; use fc_mapping_sync::{MappingSyncWorker, SyncStrategy}; -use up_common::types::opaque::{ - AuraId, RuntimeInstance, AccountId, Balance, Index, Hash, Block, BlockNumber, -}; +use up_common::types::opaque::*; + +#[cfg(feature = "pov-estimate")] +use crate::chain_spec::RuntimeIdentification; // RMRK use up_data_structs::{ @@ -84,18 +88,31 @@ pub struct QuartzRuntimeExecutor; /// Opal native executor instance. pub struct OpalRuntimeExecutor; -#[cfg(feature = "unique-runtime")] +#[cfg(all(feature = "unique-runtime", feature = "runtime-benchmarks"))] pub type DefaultRuntimeExecutor = UniqueRuntimeExecutor; -#[cfg(all(not(feature = "unique-runtime"), feature = "quartz-runtime"))] +#[cfg(all( + not(feature = "unique-runtime"), + feature = "quartz-runtime", + feature = "runtime-benchmarks" +))] pub type DefaultRuntimeExecutor = QuartzRuntimeExecutor; -#[cfg(all(not(feature = "unique-runtime"), not(feature = "quartz-runtime")))] +#[cfg(all( + not(feature = "unique-runtime"), + not(feature = "quartz-runtime"), + feature = "runtime-benchmarks" +))] pub type DefaultRuntimeExecutor = OpalRuntimeExecutor; #[cfg(feature = "unique-runtime")] impl NativeExecutionDispatch for UniqueRuntimeExecutor { + /// Only enable the benchmarking host functions when we actually want to benchmark. + #[cfg(feature = "runtime-benchmarks")] type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + /// Otherwise we only use the default Substrate host functions. + #[cfg(not(feature = "runtime-benchmarks"))] + type ExtendHostFunctions = (); fn dispatch(method: &str, data: &[u8]) -> Option> { unique_runtime::api::dispatch(method, data) @@ -108,7 +125,12 @@ impl NativeExecutionDispatch for UniqueRuntimeExecutor { #[cfg(feature = "quartz-runtime")] impl NativeExecutionDispatch for QuartzRuntimeExecutor { + /// Only enable the benchmarking host functions when we actually want to benchmark. + #[cfg(feature = "runtime-benchmarks")] type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + /// Otherwise we only use the default Substrate host functions. + #[cfg(not(feature = "runtime-benchmarks"))] + type ExtendHostFunctions = (); fn dispatch(method: &str, data: &[u8]) -> Option> { quartz_runtime::api::dispatch(method, data) @@ -120,7 +142,12 @@ impl NativeExecutionDispatch for QuartzRuntimeExecutor { } impl NativeExecutionDispatch for OpalRuntimeExecutor { + /// Only enable the benchmarking host functions when we actually want to benchmark. + #[cfg(feature = "runtime-benchmarks")] type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + /// Otherwise we only use the default Substrate host functions. + #[cfg(not(feature = "runtime-benchmarks"))] + type ExtendHostFunctions = (); fn dispatch(method: &str, data: &[u8]) -> Option> { opal_runtime::api::dispatch(method, data) @@ -152,7 +179,10 @@ impl Stream for AutosealInterval { } } -pub fn open_frontier_backend(config: &Configuration) -> Result>, String> { +pub fn open_frontier_backend>( + client: Arc, + config: &Configuration, +) -> Result>, String> { let config_dir = config .base_path .as_ref() @@ -163,6 +193,7 @@ pub fn open_frontier_backend(config: &Configuration) -> Result::new( + client, &fc_db::DatabaseSettings { source: fc_db::DatabaseSource::RocksDb { path: database_dir, @@ -176,6 +207,8 @@ type FullClient = sc_service::TFullClient>; type FullBackend = sc_service::TFullBackend; type FullSelectChain = sc_consensus::LongestChain; +type ParachainBlockImport = + TParachainBlockImport>, FullBackend>; /// Starts a `ServiceBuilder` for a full service. /// @@ -212,6 +245,7 @@ where ExecutorDispatch: NativeExecutionDispatch + 'static, BIQ: FnOnce( Arc>, + Arc, &Configuration, Option, &TaskManager, @@ -278,10 +312,11 @@ where let filter_pool: Option = Some(Arc::new(Mutex::new(BTreeMap::new()))); - let frontier_backend = open_frontier_backend(config)?; + let frontier_backend = open_frontier_backend(client.clone(), config)?; let import_queue = build_import_queue( client.clone(), + backend.clone(), config, telemetry.as_ref().map(|telemetry| telemetry.handle()), &task_manager, @@ -319,22 +354,21 @@ async fn build_relay_chain_interface( Arc<(dyn RelayChainInterface + 'static)>, Option, )> { - match collator_options.relay_chain_rpc_url { - Some(relay_chain_url) => { - let rpc_client = create_client_and_start_worker(relay_chain_url, task_manager).await?; - - Ok(( - Arc::new(RelayChainRpcInterface::new(rpc_client)) as Arc<_>, - None, - )) - } - None => build_inprocess_relay_chain( + if collator_options.relay_chain_rpc_urls.is_empty() { + build_inprocess_relay_chain( polkadot_config, parachain_config, telemetry_worker_handle, task_manager, hwbench, - ), + ) + } else { + build_minimal_relay_chain_node( + polkadot_config, + task_manager, + collator_options.relay_chain_rpc_urls, + ) + .await } } @@ -379,13 +413,15 @@ where RmrkBaseInfo, RmrkPartType, RmrkTheme, - > + substrate_frame_rpc_system::AccountNonceApi + > + up_pov_estimate_rpc::PovEstimateApi + + substrate_frame_rpc_system::AccountNonceApi + sp_api::Metadata + sp_offchain::OffchainWorkerApi + cumulus_primitives_core::CollectCollationInfo, ExecutorDispatch: NativeExecutionDispatch + 'static, BIQ: FnOnce( Arc>, + Arc, &Configuration, Option, &TaskManager, @@ -395,6 +431,7 @@ where >, BIC: FnOnce( Arc>, + Arc, Option<&Registry>, Option, &TaskManager, @@ -436,7 +473,7 @@ where let validator = parachain_config.role.is_authority(); let prometheus_registry = parachain_config.prometheus_registry().cloned(); let transaction_pool = params.transaction_pool.clone(); - let import_queue = cumulus_client_service::SharedImportQueue::new(params.import_queue); + let import_queue_service = params.import_queue.service(); let (network, system_rpc_tx, tx_handler_controller, start_network) = sc_service::build_network(sc_service::BuildNetworkParams { @@ -444,7 +481,7 @@ where client: client.clone(), transaction_pool: transaction_pool.clone(), spawn_handle: task_manager.spawn_handle(), - import_queue: import_queue.clone(), + import_queue: params.import_queue, block_announce_validator_builder: Some(Box::new(|_| { Box::new(block_announce_validator) })), @@ -482,9 +519,29 @@ where .for_each(|()| futures::future::ready(())), ); + #[cfg(feature = "pov-estimate")] + let rpc_backend = backend.clone(); + + #[cfg(feature = "pov-estimate")] + let runtime_id = parachain_config.chain_spec.runtime_id(); + let rpc_builder = Box::new(move |deny_unsafe, subscription_task_executor| { let full_deps = unique_rpc::FullDeps { - backend: rpc_frontier_backend.clone(), + #[cfg(feature = "pov-estimate")] + runtime_id: runtime_id.clone(), + + #[cfg(feature = "pov-estimate")] + exec_params: uc_rpc::pov_estimate::ExecutorParams { + wasm_method: parachain_config.wasm_method, + default_heap_pages: parachain_config.default_heap_pages, + max_runtime_instances: parachain_config.max_runtime_instances, + runtime_cache_size: parachain_config.runtime_cache_size, + }, + + #[cfg(feature = "pov-estimate")] + backend: rpc_backend.clone(), + + eth_backend: rpc_frontier_backend.clone(), deny_unsafe, client: rpc_client.clone(), pool: rpc_pool.clone(), @@ -549,6 +606,7 @@ where if validator { let parachain_consensus = build_consensus( client.clone(), + backend.clone(), prometheus_registry.as_ref(), telemetry.as_ref().map(|t| t.handle()), &task_manager, @@ -569,7 +627,7 @@ where task_manager: &mut task_manager, spawner, parachain_consensus, - import_queue, + import_queue: import_queue_service, collator_key: collator_key.expect("Command line arguments do not allow this. qed"), relay_chain_interface, relay_chain_slot_duration, @@ -582,10 +640,9 @@ where announce_block, task_manager: &mut task_manager, para_id: id, - import_queue, + import_queue: import_queue_service, relay_chain_interface, relay_chain_slot_duration, - collator_options, }; start_full_node(params)?; @@ -599,6 +656,7 @@ where /// Build the import queue for the the parachain runtime. pub fn parachain_build_import_queue( client: Arc>, + backend: Arc, config: &Configuration, telemetry: Option, task_manager: &TaskManager, @@ -619,6 +677,8 @@ where { let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; + let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); + cumulus_client_consensus_aura::import_queue::< sp_consensus_aura::sr25519::AuthorityPair, _, @@ -627,7 +687,7 @@ where _, _, >(cumulus_client_consensus_aura::ImportQueueParams { - block_import: client.clone(), + block_import, client: client.clone(), create_inherent_data_providers: move |_, _| async move { let time = sp_timestamp::InherentDataProvider::from_system_time(); @@ -682,7 +742,8 @@ where RmrkBaseInfo, RmrkPartType, RmrkTheme, - > + substrate_frame_rpc_system::AccountNonceApi + > + up_pov_estimate_rpc::PovEstimateApi + + substrate_frame_rpc_system::AccountNonceApi + sp_api::Metadata + sp_offchain::OffchainWorkerApi + cumulus_primitives_core::CollectCollationInfo @@ -696,6 +757,7 @@ where id, parachain_build_import_queue, |client, + backend, prometheus_registry, telemetry, task_manager, @@ -714,6 +776,8 @@ where telemetry.clone(), ); + let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); + Ok(AuraConsensus::build::< sp_consensus_aura::sr25519::AuthorityPair, _, @@ -751,7 +815,7 @@ where Ok((slot, time, parachain_inherent)) } }, - block_import: client.clone(), + block_import, para_client: client, backoff_authoring_blocks: Option::<()>::None, sync_oracle, @@ -771,6 +835,7 @@ where fn dev_build_import_queue( client: Arc>, + _: Arc, config: &Configuration, _: Option, task_manager: &TaskManager, @@ -827,7 +892,8 @@ where RmrkBaseInfo, RmrkPartType, RmrkTheme, - > + substrate_frame_rpc_system::AccountNonceApi + > + up_pov_estimate_rpc::PovEstimateApi + + substrate_frame_rpc_system::AccountNonceApi + sp_api::Metadata + sp_offchain::OffchainWorkerApi + cumulus_primitives_core::CollectCollationInfo @@ -998,9 +1064,29 @@ where let rpc_pool = transaction_pool.clone(); let rpc_network = network.clone(); let rpc_frontier_backend = frontier_backend.clone(); + + #[cfg(feature = "pov-estimate")] + let rpc_backend = backend.clone(); + + #[cfg(feature = "pov-estimate")] + let runtime_id = config.chain_spec.runtime_id(); + let rpc_builder = Box::new(move |deny_unsafe, subscription_executor| { let full_deps = unique_rpc::FullDeps { - backend: rpc_frontier_backend.clone(), + #[cfg(feature = "pov-estimate")] + runtime_id: runtime_id.clone(), + + #[cfg(feature = "pov-estimate")] + exec_params: uc_rpc::pov_estimate::ExecutorParams { + wasm_method: config.wasm_method, + default_heap_pages: config.default_heap_pages, + max_runtime_instances: config.max_runtime_instances, + runtime_cache_size: config.runtime_cache_size, + }, + + #[cfg(feature = "pov-estimate")] + backend: rpc_backend.clone(), + eth_backend: rpc_frontier_backend.clone(), deny_unsafe, client: rpc_client.clone(), pool: rpc_pool.clone(), diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 1bfa18bf3e..73f89f05cd 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -11,50 +11,51 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = { version = "0.3.17", features = ["compat"] } -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +jsonrpsee = { version = "0.16.2", features = ["server", "macros"] } # pallet-contracts-rpc = { git = 'https://github.com/paritytech/substrate', branch = 'master' } -pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sc-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sc-consensus-epochs = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sc-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sc-finality-grandpa-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sc-network = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sc-service = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-storage = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-session = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sc-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sc-consensus-epochs = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sc-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sc-finality-grandpa-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sc-network = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sc-service = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-storage = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-session = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } tokio = { version = "1.19.2", features = ["macros", "sync"] } -pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fp-storage = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fc-db = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-storage = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fc-db = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } pallet-common = { default-features = false, path = "../../pallets/common" } up-common = { path = "../../primitives/common" } pallet-unique = { path = "../../pallets/unique" } uc-rpc = { path = "../../client/rpc" } up-rpc = { path = "../../primitives/rpc" } -app-promotion-rpc = { path = "../../primitives/app_promotion_rpc"} +app-promotion-rpc = { path = "../../primitives/app_promotion_rpc" } rmrk-rpc = { path = "../../primitives/rmrk-rpc" } +up-pov-estimate-rpc = { path = "../../primitives/pov-estimate-rpc" } up-data-structs = { default-features = false, path = "../../primitives/data-structs" } [dependencies.serde] @@ -65,3 +66,4 @@ version = '1.0.130' default = [] std = [] unique-runtime = [] +pov-estimate = ['uc-rpc/pov-estimate'] diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index b6d022506d..fdc98eea67 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -40,7 +40,7 @@ use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sc_service::TransactionPool; use std::{collections::BTreeMap, sync::Arc}; -use up_common::types::opaque::{Hash, AccountId, RuntimeInstance, Index, Block, BlockNumber, Balance}; +use up_common::types::opaque::*; // RMRK use up_data_structs::{ @@ -48,6 +48,9 @@ use up_data_structs::{ RmrkPartType, RmrkTheme, }; +#[cfg(feature = "pov-estimate")] +type FullBackend = sc_service::TFullBackend; + /// Extra dependencies for GRANDPA pub struct GrandpaDeps { /// Voting round info. @@ -82,8 +85,18 @@ pub struct FullDeps { pub deny_unsafe: DenyUnsafe, /// EthFilterApi pool. pub filter_pool: Option, - /// Backend. - pub backend: Arc>, + + #[cfg(feature = "pov-estimate")] + pub runtime_id: RuntimeId, + /// Executor params for PoV estimating + #[cfg(feature = "pov-estimate")] + pub exec_params: uc_rpc::pov_estimate::ExecutorParams, + /// Substrate Backend. + #[cfg(feature = "pov-estimate")] + pub backend: Arc, + + /// Ethereum Backend. + pub eth_backend: Arc>, /// Maximum number of logs in a query. pub max_past_logs: u32, /// Maximum fee history cache size. @@ -162,6 +175,7 @@ where RmrkPartType, RmrkTheme, >, + C::Api: up_pov_estimate_rpc::PovEstimateApi, B: sc_client_api::Backend + Send + Sync + 'static, B::State: sc_client_api::backend::StateBackend>, P: TransactionPool + 'static, @@ -182,6 +196,9 @@ where #[cfg(not(feature = "unique-runtime"))] use uc_rpc::{RmrkApiServer, Rmrk}; + #[cfg(feature = "pov-estimate")] + use uc_rpc::pov_estimate::{PovEstimateApiServer, PovEstimate}; + // use pallet_contracts_rpc::{Contracts, ContractsApi}; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; use substrate_frame_rpc_system::{System, SystemApiServer}; @@ -200,7 +217,17 @@ where network, deny_unsafe, filter_pool, + + #[cfg(feature = "pov-estimate")] + runtime_id, + + #[cfg(feature = "pov-estimate")] + exec_params, + + #[cfg(feature = "pov-estimate")] backend, + + eth_backend, max_past_logs, } = deps; @@ -216,6 +243,7 @@ where let overrides = overrides_handle::<_, _, R>(client.clone()); + let execute_gas_limit_multiplier = 10; io.merge( Eth::new( client.clone(), @@ -225,11 +253,12 @@ where network.clone(), signers, overrides.clone(), - backend.clone(), + eth_backend.clone(), is_authority, block_data_cache.clone(), fee_history_cache, fee_history_limit, + execute_gas_limit_multiplier, ) .into_rpc(), )?; @@ -242,11 +271,23 @@ where #[cfg(not(feature = "unique-runtime"))] io.merge(Rmrk::new(client.clone()).into_rpc())?; + #[cfg(feature = "pov-estimate")] + io.merge( + PovEstimate::new( + client.clone(), + backend, + deny_unsafe, + exec_params, + runtime_id, + ) + .into_rpc(), + )?; + if let Some(filter_pool) = filter_pool { io.merge( EthFilter::new( client.clone(), - backend, + eth_backend, filter_pool, 500_usize, // max stored filters max_past_logs, diff --git a/pallets/app-promotion/CHANGELOG.md b/pallets/app-promotion/CHANGELOG.md index ad06f63f95..2f6c3f66cb 100644 --- a/pallets/app-promotion/CHANGELOG.md +++ b/pallets/app-promotion/CHANGELOG.md @@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file. +## [0.1.3] - 2022-12-25 + +### Fixed + +- Benchmarks for `payoutStakers` and `unstake` extrinsics. + +## [0.1.2] - 2022-12-20 + +### Fixed + +- The behaviour of the `payoutStakers` extrinsic + in which only one stake is calculated for the last processed staker. + ## [0.1.1] - 2022-12-13 ### Added diff --git a/pallets/app-promotion/Cargo.toml b/pallets/app-promotion/Cargo.toml index 7ad5b1d3d4..577e861021 100644 --- a/pallets/app-promotion/Cargo.toml +++ b/pallets/app-promotion/Cargo.toml @@ -9,13 +9,13 @@ homepage = 'https://unique.network' license = 'GPLv3' name = 'pallet-app-promotion' repository = 'https://github.com/UniqueNetwork/unique-chain' -version = '0.1.1' +version = '0.1.3' [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] [features] -default = ['std'] +default = ['std',] runtime-benchmarks = [ 'frame-benchmarking', 'frame-support/runtime-benchmarks', @@ -47,18 +47,20 @@ scale-info = { version = "2.0.1", default-features = false, features = [ ################################################################################ # Substrate Dependencies -codec = { default-features = false, features = ['derive'], package = 'parity-scale-codec', version = '3.1.2' } -frame-benchmarking = {default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-balances ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-timestamp ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-randomness-collective-flip ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-evm ={ default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -sp-std ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-io ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +codec = { default-features = false, features = [ + 'derive', +], package = 'parity-scale-codec', version = '3.1.2' } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-balances = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-timestamp = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-randomness-collective-flip = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } serde = { default-features = false, features = ['derive'], version = '1.0.130' } ################################################################################ diff --git a/pallets/app-promotion/src/benchmarking.rs b/pallets/app-promotion/src/benchmarking.rs index b9e9c7f0d8..4cbe29d7ee 100644 --- a/pallets/app-promotion/src/benchmarking.rs +++ b/pallets/app-promotion/src/benchmarking.rs @@ -77,27 +77,36 @@ benchmarks! { } : _(RawOrigin::Root, T::CrossAccountId::from_sub(pallet_admin)) payout_stakers{ - let b in 1..101; + let b in 1..100; let pallet_admin = account::("admin", 1, SEED); let share = Perbill::from_rational(1u32, 20); PromototionPallet::::set_admin_address(RawOrigin::Root.into(), T::CrossAccountId::from_sub(pallet_admin.clone()))?; ::Currency::make_free_balance_be(&pallet_admin, Perbill::from_rational(1u32, 2) * BalanceOf::::max_value()); + ::Currency::make_free_balance_be(&::TreasuryAccountId::get(), Perbill::from_rational(1u32, 2) * BalanceOf::::max_value()); - let staker: T::AccountId = account("caller", 0, SEED); - ::Currency::make_free_balance_be(&staker, Perbill::from_rational(1u32, 2) * BalanceOf::::max_value()); let stakers: Vec = (0..b).map(|index| account("staker", index, SEED)).collect(); stakers.iter().for_each(|staker| { ::Currency::make_free_balance_be(&staker, Perbill::from_rational(1u32, 2) * BalanceOf::::max_value()); }); - (0..10).try_for_each(|_| { + (1..11).try_for_each(|i| { + >::set_block_number(i.into()); + T::RelayBlockNumberProvider::set_block_number((2*i).into()); + assert_eq!(>::block_number(), i.into()); + assert_eq!(T::RelayBlockNumberProvider::current_block_number(), (2*i).into()); stakers.iter() - .map(|staker| { - PromototionPallet::::stake(RawOrigin::Signed(staker.clone()).into(), Into::>::into(100u128) * T::Nominal::get()) - }).collect::, _>>()?; - >::finalize(); + .map(|staker| { + PromototionPallet::::stake(RawOrigin::Signed(staker.clone()).into(), Into::>::into(100u128) * T::Nominal::get()) + }).collect::, _>>()?; + Result::<(), sp_runtime::DispatchError>::Ok(()) })?; + + let stakes = Staked::::iter_prefix((&stakers[0],)).into_iter().collect::>(); + assert_eq!(stakes.len(), 10); + + >::set_block_number(15_000.into()); + T::RelayBlockNumberProvider::set_block_number(30_000.into()); } : _(RawOrigin::Signed(pallet_admin.clone()), Some(b as u8)) stake { @@ -110,9 +119,12 @@ benchmarks! { let caller = account::("caller", 0, SEED); let share = Perbill::from_rational(1u32, 20); let _ = ::Currency::make_free_balance_be(&caller, Perbill::from_rational(1u32, 2) * BalanceOf::::max_value()); - (0..10).map(|_| { + (1..11).map(|i| { // used to change block number - >::finalize(); + >::set_block_number(i.into()); + T::RelayBlockNumberProvider::set_block_number((2*i).into()); + assert_eq!(>::block_number(), i.into()); + assert_eq!(T::RelayBlockNumberProvider::current_block_number(), (2*i).into()); PromototionPallet::::stake(RawOrigin::Signed(caller.clone()).into(), share * ::Currency::total_balance(&caller)) }).collect::, _>>()?; diff --git a/pallets/app-promotion/src/lib.rs b/pallets/app-promotion/src/lib.rs index f47c8b5787..0bb0df882b 100644 --- a/pallets/app-promotion/src/lib.rs +++ b/pallets/app-promotion/src/lib.rs @@ -103,7 +103,7 @@ pub mod pallet { #[pallet::config] pub trait Config: - frame_system::Config + pallet_evm::account::Config + pallet_configuration::Config + frame_system::Config + pallet_evm::Config + pallet_configuration::Config { /// Type to interact with the native token type Currency: ExtendedLockableCurrency @@ -276,11 +276,13 @@ pub mod pallet { if !block_pending.is_empty() { block_pending.into_iter().for_each(|(staker, amount)| { - >::unreserve(&staker, amount); + <::Currency as ReservableCurrency>::unreserve( + &staker, amount, + ); }); } - T::WeightInfo::on_initialize(counter) + ::WeightInfo::on_initialize(counter) } } @@ -299,7 +301,8 @@ pub mod pallet { /// # Arguments /// /// * `admin`: account of the new admin. - #[pallet::weight(T::WeightInfo::set_admin_address())] + #[pallet::call_index(0)] + #[pallet::weight(::WeightInfo::set_admin_address())] pub fn set_admin_address(origin: OriginFor, admin: T::CrossAccountId) -> DispatchResult { ensure_root(origin)?; @@ -317,7 +320,8 @@ pub mod pallet { /// # Arguments /// /// * `amount`: in native tokens. - #[pallet::weight(T::WeightInfo::stake())] + #[pallet::call_index(1)] + #[pallet::weight(::WeightInfo::stake())] pub fn stake(staker: OriginFor, amount: BalanceOf) -> DispatchResult { let staker_id = ensure_signed(staker)?; @@ -391,7 +395,8 @@ pub mod pallet { /// Moves the sum of all stakes to the `reserved` state. /// After the end of `PendingInterval` this sum becomes completely /// free for further use. - #[pallet::weight(T::WeightInfo::unstake())] + #[pallet::call_index(2)] + #[pallet::weight(::WeightInfo::unstake())] pub fn unstake(staker: OriginFor) -> DispatchResultWithPostInfo { let staker_id = ensure_signed(staker)?; let config = >::get(); @@ -425,7 +430,10 @@ pub mod pallet { Self::unlock_balance(&staker_id, total_staked)?; - >::reserve(&staker_id, total_staked)?; + <::Currency as ReservableCurrency>::reserve( + &staker_id, + total_staked, + )?; TotalStaked::::set( TotalStaked::::get() @@ -449,7 +457,8 @@ pub mod pallet { /// # Arguments /// /// * `collection_id`: ID of the collection that will be sponsored by `pallet_id` - #[pallet::weight(T::WeightInfo::sponsor_collection())] + #[pallet::call_index(3)] + #[pallet::weight(::WeightInfo::sponsor_collection())] pub fn sponsor_collection( admin: OriginFor, collection_id: CollectionId, @@ -474,7 +483,8 @@ pub mod pallet { /// # Arguments /// /// * `collection_id`: ID of the collection that is sponsored by `pallet_id` - #[pallet::weight(T::WeightInfo::stop_sponsoring_collection())] + #[pallet::call_index(4)] + #[pallet::weight(::WeightInfo::stop_sponsoring_collection())] pub fn stop_sponsoring_collection( admin: OriginFor, collection_id: CollectionId, @@ -503,7 +513,8 @@ pub mod pallet { /// # Arguments /// /// * `contract_id`: the contract address that will be sponsored by `pallet_id` - #[pallet::weight(T::WeightInfo::sponsor_contract())] + #[pallet::call_index(5)] + #[pallet::weight(::WeightInfo::sponsor_contract())] pub fn sponsor_contract(admin: OriginFor, contract_id: H160) -> DispatchResult { let admin_id = ensure_signed(admin)?; @@ -529,7 +540,8 @@ pub mod pallet { /// # Arguments /// /// * `contract_id`: the contract address that is sponsored by `pallet_id` - #[pallet::weight(T::WeightInfo::stop_sponsoring_contract())] + #[pallet::call_index(6)] + #[pallet::weight(::WeightInfo::stop_sponsoring_contract())] pub fn stop_sponsoring_contract(admin: OriginFor, contract_id: H160) -> DispatchResult { let admin_id = ensure_signed(admin)?; @@ -559,7 +571,8 @@ pub mod pallet { /// # Arguments /// /// * `stakers_number`: the number of stakers for which recalculation will be performed - #[pallet::weight(T::WeightInfo::payout_stakers(stakers_number.unwrap_or(DEFAULT_NUMBER_PAYOUTS) as u32))] + #[pallet::call_index(7)] + #[pallet::weight(::WeightInfo::payout_stakers(stakers_number.unwrap_or(DEFAULT_NUMBER_PAYOUTS) as u32))] pub fn payout_stakers(admin: OriginFor, stakers_number: Option) -> DispatchResult { let admin_id = ensure_signed(admin)?; @@ -593,16 +606,26 @@ pub mod pallet { PreviousCalculatedRecord::::set(None); { + // Address handled in the last payout loop iteration (below) let last_id = RefCell::new(None); + // Block number (as a part of the key) for which calculation was performed in the last payout loop iteration + let mut last_staked_calculated_block = Default::default(); + // Reward balance for the address in the iteration let income_acc = RefCell::new(BalanceOf::::default()); + // Staked balance for the address in the iteration (before stake is recalculated) let amount_acc = RefCell::new(BalanceOf::::default()); - // this closure is used to perform some of the actions if we break the loop because we reached the number of stakers for recalculation, - // but there were unrecalculated records in the storage. + // This closure is used to finalize handling single staker address in each of the two conditions: (1) when we break out of the payout + // loop because we reached the number of stakes for rewarding, (2) When all stakes by the single address are handled and the payout + // loop switches to handling the next staker address: + // 1. Transfer full reward amount to the payee + // 2. Lock the reward in staking lock + // 3. Update TotalStaked amount + // 4. Issue StakingRecalculation event let flush_stake = || -> DispatchResult { if let Some(last_id) = &*last_id.borrow() { if !income_acc.borrow().is_zero() { - >::transfer( + <::Currency as Currency>::transfer( &T::TreasuryAccountId::get(), last_id, *income_acc.borrow(), @@ -630,16 +653,40 @@ pub mod pallet { Ok(()) }; + // Reward payment loop. Should loop for no more than config.max_stakers_per_calculation + // iterations in one extrinsic call + // + // stakers_number - keeps the remaining number of iterations (staker addresses to handle) + // next_recalc_block_for_stake - is taken from the state and stores the starting relay block from which reward should be paid out + // income_acc - stores the reward amount to pay to the staker address (accumulates over all address stake records) while let Some(( (current_id, staked_block), (amount, next_recalc_block_for_stake), )) = storage_iterator.next() { + // last_id is not equal current_id when we switch to handling a new staker address + // or just start handling the very first address. In the latter case last_id will be None and + // flush_stake will do nothing if last_id.borrow().as_ref() != Some(¤t_id) { - flush_stake()?; - *last_id.borrow_mut() = Some(current_id.clone()); - stakers_number -= 1; + if stakers_number > 0 { + flush_stake()?; + *last_id.borrow_mut() = Some(current_id.clone()); + stakers_number -= 1; + } + // Break out if we reached the address limit + else { + if let Some(staker) = &*last_id.borrow() { + // Save the last calculated record to pick up in the next extrinsic call + PreviousCalculatedRecord::::set(Some(( + staker.clone(), + last_staked_calculated_block, + ))); + } + break; + }; }; + + // Increase accumulated reward for current address and update current staking record, i.e. (address, staked_block) -> amount if current_recalc_block >= next_recalc_block_for_stake { *amount_acc.borrow_mut() += amount; Self::recalculate_and_insert_stake( @@ -653,13 +700,7 @@ pub mod pallet { &mut *income_acc.borrow_mut(), ); } - - if stakers_number == 0 { - if storage_iterator.next().is_some() { - PreviousCalculatedRecord::::set(Some((current_id, staked_block))); - } - break; - } + last_staked_calculated_block = staked_block; } flush_stake()?; } @@ -716,9 +757,12 @@ impl Pallet { /// - `amount`: amount of locked funds. fn set_lock_unchecked(staker: &T::AccountId, amount: BalanceOf) { if amount.is_zero() { - >::remove_lock(LOCK_IDENTIFIER, &staker); + <::Currency as LockableCurrency>::remove_lock( + LOCK_IDENTIFIER, + &staker, + ); } else { - >::set_lock( + <::Currency as LockableCurrency>::set_lock( LOCK_IDENTIFIER, staker, amount, @@ -733,7 +777,7 @@ impl Pallet { pub fn get_locked_balance( staker: impl EncodeLike, ) -> Option>> { - >::locks(staker) + <::Currency as ExtendedLockableCurrency>::locks(staker) .into_iter() .find(|l| l.id == LOCK_IDENTIFIER) } @@ -826,6 +870,8 @@ impl Pallet { income - base } + /// Get relay block number rounded down to multiples of config.recalculation_interval. + /// We need it to reward stakers in integer parts of recalculation_interval fn get_current_recalc_block( current_relay_block: T::BlockNumber, config: &PalletConfiguration, diff --git a/pallets/app-promotion/src/weights.rs b/pallets/app-promotion/src/weights.rs index 78ea346ce7..f1e4220c16 100644 --- a/pallets/app-promotion/src/weights.rs +++ b/pallets/app-promotion/src/weights.rs @@ -3,7 +3,7 @@ //! Autogenerated weights for pallet_app_promotion //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-09-07, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-12-25, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 // Executed Command: @@ -51,77 +51,84 @@ impl WeightInfo for SubstrateWeight { // Storage: AppPromotion PendingUnstake (r:1 w:0) // Storage: System Account (r:1 w:1) fn on_initialize(b: u32, ) -> Weight { - Weight::from_ref_time(2_651_000) - // Standard Error: 103_000 - .saturating_add(Weight::from_ref_time(6_024_000).saturating_mul(b as u64)) + Weight::from_ref_time(3_079_948 as u64) + // Standard Error: 30_376 + .saturating_add(Weight::from_ref_time(6_343_630 as u64).saturating_mul(b as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(b as u64))) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(b as u64))) } // Storage: AppPromotion Admin (r:0 w:1) fn set_admin_address() -> Weight { - Weight::from_ref_time(7_117_000) + Weight::from_ref_time(6_653_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: AppPromotion Admin (r:1 w:0) + // Storage: Configuration AppPromomotionConfigurationOverride (r:1 w:0) // Storage: ParachainSystem ValidationData (r:1 w:0) - // Storage: AppPromotion NextCalculatedRecord (r:1 w:1) - // Storage: AppPromotion Staked (r:2 w:0) + // Storage: AppPromotion PreviousCalculatedRecord (r:1 w:1) + // Storage: AppPromotion Staked (r:11 w:10) + // Storage: System Account (r:2 w:2) + // Storage: Balances Locks (r:1 w:1) + // Storage: AppPromotion TotalStaked (r:1 w:1) fn payout_stakers(b: u32, ) -> Weight { - Weight::from_ref_time(9_958_000) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(4_406_000).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(b as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(74_048_000 as u64) + // Standard Error: 33_223 + .saturating_add(Weight::from_ref_time(57_702_092 as u64).saturating_mul(b as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().reads((12 as u64).saturating_mul(b as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes((12 as u64).saturating_mul(b as u64))) } // Storage: AppPromotion StakesPerAccount (r:1 w:1) + // Storage: Configuration AppPromomotionConfigurationOverride (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: ParachainSystem ValidationData (r:1 w:0) // Storage: AppPromotion Staked (r:1 w:1) // Storage: AppPromotion TotalStaked (r:1 w:1) fn stake() -> Weight { - Weight::from_ref_time(20_574_000) - .saturating_add(T::DbWeight::get().reads(6 as u64)) + Weight::from_ref_time(20_314_000 as u64) + .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } + // Storage: Configuration AppPromomotionConfigurationOverride (r:1 w:0) // Storage: AppPromotion PendingUnstake (r:1 w:1) - // Storage: AppPromotion Staked (r:2 w:1) + // Storage: AppPromotion Staked (r:11 w:10) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: AppPromotion TotalStaked (r:1 w:1) // Storage: AppPromotion StakesPerAccount (r:0 w:1) fn unstake() -> Weight { - Weight::from_ref_time(31_703_000) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + Weight::from_ref_time(64_582_000 as u64) + .saturating_add(T::DbWeight::get().reads(16 as u64)) + .saturating_add(T::DbWeight::get().writes(15 as u64)) } // Storage: AppPromotion Admin (r:1 w:0) // Storage: Common CollectionById (r:1 w:1) fn sponsor_collection() -> Weight { - Weight::from_ref_time(12_932_000) + Weight::from_ref_time(16_364_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: AppPromotion Admin (r:1 w:0) // Storage: Common CollectionById (r:1 w:1) fn stop_sponsoring_collection() -> Weight { - Weight::from_ref_time(12_453_000) + Weight::from_ref_time(15_710_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: AppPromotion Admin (r:1 w:0) // Storage: EvmContractHelpers Sponsoring (r:0 w:1) fn sponsor_contract() -> Weight { - Weight::from_ref_time(11_952_000) + Weight::from_ref_time(12_669_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: AppPromotion Admin (r:1 w:0) // Storage: EvmContractHelpers Sponsoring (r:1 w:1) fn stop_sponsoring_contract() -> Weight { - Weight::from_ref_time(12_538_000) + Weight::from_ref_time(14_406_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -132,77 +139,84 @@ impl WeightInfo for () { // Storage: AppPromotion PendingUnstake (r:1 w:0) // Storage: System Account (r:1 w:1) fn on_initialize(b: u32, ) -> Weight { - Weight::from_ref_time(2_651_000) - // Standard Error: 103_000 - .saturating_add(Weight::from_ref_time(6_024_000).saturating_mul(b as u64)) + Weight::from_ref_time(3_079_948 as u64) + // Standard Error: 30_376 + .saturating_add(Weight::from_ref_time(6_343_630 as u64).saturating_mul(b as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(b as u64))) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(b as u64))) } // Storage: AppPromotion Admin (r:0 w:1) fn set_admin_address() -> Weight { - Weight::from_ref_time(7_117_000) + Weight::from_ref_time(6_653_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: AppPromotion Admin (r:1 w:0) + // Storage: Configuration AppPromomotionConfigurationOverride (r:1 w:0) // Storage: ParachainSystem ValidationData (r:1 w:0) - // Storage: AppPromotion NextCalculatedRecord (r:1 w:1) - // Storage: AppPromotion Staked (r:2 w:0) + // Storage: AppPromotion PreviousCalculatedRecord (r:1 w:1) + // Storage: AppPromotion Staked (r:11 w:10) + // Storage: System Account (r:2 w:2) + // Storage: Balances Locks (r:1 w:1) + // Storage: AppPromotion TotalStaked (r:1 w:1) fn payout_stakers(b: u32, ) -> Weight { - Weight::from_ref_time(9_958_000) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(4_406_000).saturating_mul(b as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(b as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(74_048_000 as u64) + // Standard Error: 33_223 + .saturating_add(Weight::from_ref_time(57_702_092 as u64).saturating_mul(b as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().reads((12 as u64).saturating_mul(b as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes((12 as u64).saturating_mul(b as u64))) } // Storage: AppPromotion StakesPerAccount (r:1 w:1) + // Storage: Configuration AppPromomotionConfigurationOverride (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: ParachainSystem ValidationData (r:1 w:0) // Storage: AppPromotion Staked (r:1 w:1) // Storage: AppPromotion TotalStaked (r:1 w:1) fn stake() -> Weight { - Weight::from_ref_time(20_574_000) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) + Weight::from_ref_time(20_314_000 as u64) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } + // Storage: Configuration AppPromomotionConfigurationOverride (r:1 w:0) // Storage: AppPromotion PendingUnstake (r:1 w:1) - // Storage: AppPromotion Staked (r:2 w:1) + // Storage: AppPromotion Staked (r:11 w:10) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: AppPromotion TotalStaked (r:1 w:1) // Storage: AppPromotion StakesPerAccount (r:0 w:1) fn unstake() -> Weight { - Weight::from_ref_time(31_703_000) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) + Weight::from_ref_time(64_582_000 as u64) + .saturating_add(RocksDbWeight::get().reads(16 as u64)) + .saturating_add(RocksDbWeight::get().writes(15 as u64)) } // Storage: AppPromotion Admin (r:1 w:0) // Storage: Common CollectionById (r:1 w:1) fn sponsor_collection() -> Weight { - Weight::from_ref_time(12_932_000) + Weight::from_ref_time(16_364_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: AppPromotion Admin (r:1 w:0) // Storage: Common CollectionById (r:1 w:1) fn stop_sponsoring_collection() -> Weight { - Weight::from_ref_time(12_453_000) + Weight::from_ref_time(15_710_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: AppPromotion Admin (r:1 w:0) // Storage: EvmContractHelpers Sponsoring (r:0 w:1) fn sponsor_contract() -> Weight { - Weight::from_ref_time(11_952_000) + Weight::from_ref_time(12_669_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: AppPromotion Admin (r:1 w:0) // Storage: EvmContractHelpers Sponsoring (r:1 w:1) fn stop_sponsoring_contract() -> Weight { - Weight::from_ref_time(12_538_000) + Weight::from_ref_time(14_406_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/pallets/common/CHANGELOG.md b/pallets/common/CHANGELOG.md index a2edeaa3d5..8ae3a890b2 100644 --- a/pallets/common/CHANGELOG.md +++ b/pallets/common/CHANGELOG.md @@ -2,29 +2,59 @@ All notable changes to this project will be documented in this file. + + +## [0.1.12] - 2022-11-16 + +### Changed + +- Behavior of the `setCollectionLimit` method. + Removed method overload: single signature `(string, uint256)` + is used for both cases. + +## [0.1.11] - 2022-11-12 + +### Changed + +- In the `Collection` solidity interface, + the `allowed` function has been renamed to `allow_listed_cross`. + Also `EthCrossAccount` type is now used as `user` arg. + +## [0.1.10] - 2022-11-02 + +### Changed + +- Use named structure `EthCrossAccount` in eth functions. + +## [0.1.9] - 2022-10-13 + +## Added + +- EVM event for `destroy_collection`. + ## [0.1.8] - 2022-08-24 ## Added - - Eth methods for collection - + set_collection_sponsor_substrate - + has_collection_pending_sponsor - + remove_collection_sponsor - + get_collection_sponsor + +- Eth methods for collection + - set_collection_sponsor_substrate + - has_collection_pending_sponsor + - remove_collection_sponsor + - get_collection_sponsor - Add convert function from `uint256` to `CrossAccountId`. ## [0.1.7] - 2022-08-19 ### Added - - Add convert funtion from `CrossAccountId` to eth `uint256`. +- Add convert funtion from `CrossAccountId` to eth `uint256`. - ## [0.1.6] - 2022-08-16 ### Added -- New Ethereum API methods: changeOwner, changeOwner(Substrate) and verifyOwnerOrAdmin(Substrate). - +- New Ethereum API methods: changeOwner, changeOwner(Substrate) and verifyOwnerOrAdmin(Substrate). + ## [v0.1.5] 2022-08-16 ### Other changes @@ -45,19 +75,21 @@ Upstream-Change: https://github.com/paritytech/substrate/pull/11490 - build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b ## [0.1.3] - 2022-07-25 + ### Add -- Some static property keys and values. + +- Some static property keys and values. ## [0.1.2] - 2022-07-20 ### Fixed -- Some methods in `#[solidity_interface]` for `CollectionHandle` had invalid - mutability modifiers, causing invalid stub/abi generation. +- Some methods in `#[solidity_interface]` for `CollectionHandle` had invalid + mutability modifiers, causing invalid stub/abi generation. ## [0.1.1] - 2022-07-14 ### Added - - Implementation of RPC method `token_owners` returning 10 owners in no particular order. - This was an internal request to improve the web interface and support fractionalization event. +- Implementation of RPC method `token_owners` returning 10 owners in no particular order. + This was an internal request to improve the web interface and support fractionalization event. diff --git a/pallets/common/Cargo.toml b/pallets/common/Cargo.toml index 645e45bb75..5c111cf060 100644 --- a/pallets/common/Cargo.toml +++ b/pallets/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-common" -version = "0.1.8" +version = "0.1.12" license = "GPLv3" edition = "2021" @@ -11,18 +11,19 @@ package = 'parity-scale-codec' version = '3.1.2' [dependencies] -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } up-data-structs = { default-features = false, path = '../../primitives/data-structs' } pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' } evm-coder = { default-features = false, path = '../../crates/evm-coder' } -ethereum = { version = "0.12.0", default-features = false } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +ethereum = { version = "0.14.0", default-features = false } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +up-pov-estimate-rpc = { default-features = false, path = "../../primitives/pov-estimate-rpc" } serde = { version = "1.0.130", default-features = false } scale-info = { version = "2.0.1", default-features = false, features = [ @@ -39,9 +40,11 @@ std = [ "fp-evm-mapping/std", "up-data-structs/std", "pallet-evm/std", + "up-pov-estimate-rpc/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "up-data-structs/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] +stubgen = ["evm-coder/stubgen"] diff --git a/pallets/common/src/erc.rs b/pallets/common/src/erc.rs index 5a5121a265..79764e19d2 100644 --- a/pallets/common/src/erc.rs +++ b/pallets/common/src/erc.rs @@ -16,28 +16,23 @@ //! This module contains the implementation of pallet methods for evm. +pub use pallet_evm::{PrecompileOutput, PrecompileResult, PrecompileHandle, account::CrossAccountId}; use evm_coder::{ + abi::AbiType, solidity_interface, solidity, ToLog, types::*, execution::{Result, Error}, weight, }; -pub use pallet_evm::{PrecompileOutput, PrecompileResult, PrecompileHandle, account::CrossAccountId}; use pallet_evm_coder_substrate::dispatch_to_evm; -use sp_std::vec::Vec; +use sp_std::{vec, vec::Vec}; use up_data_structs::{ AccessMode, CollectionMode, CollectionPermissions, OwnerRestrictedSet, Property, SponsoringRateLimit, SponsorshipState, }; -use alloc::format; use crate::{ - Pallet, CollectionHandle, Config, CollectionProperties, SelfWeightOf, - eth::{ - convert_cross_account_to_uint256, convert_uint256_to_cross_account, - convert_cross_account_to_tuple, - }, - weights::WeightInfo, + Pallet, CollectionHandle, Config, CollectionProperties, SelfWeightOf, eth, weights::WeightInfo, }; /// Events for ethereum collection helper. @@ -53,11 +48,33 @@ pub enum CollectionHelpersEvents { #[indexed] collection_id: address, }, + /// The collection has been destroyed. + CollectionDestroyed { + /// Collection ID. + #[indexed] + collection_id: address, + }, + /// The collection has been changed. + CollectionChanged { + /// Collection ID. + #[indexed] + collection_id: address, + }, + + /// The token has been changed. + TokenChanged { + /// Collection ID. + #[indexed] + collection_id: address, + /// Token ID. + token_id: uint256, + }, } /// Does not always represent a full collection, for RFT it is either /// collection (Implementing ERC721), or specific collection token (Implementing ERC20). pub trait CommonEvmHandler { + /// Raw compiled binary code of the contract stub const CODE: &'static [u8]; /// Call precompiled handle. @@ -74,6 +91,7 @@ where /// /// @param key Property key. /// @param value Propery value. + #[solidity(hide)] #[weight(>::set_collection_properties(1))] fn set_collection_property( &mut self, @@ -85,19 +103,38 @@ where let key = >::from(key) .try_into() .map_err(|_| "key too large")?; - let value = value.try_into().map_err(|_| "value too large")?; + let value = value.0.try_into().map_err(|_| "value too large")?; >::set_collection_property(self, &caller, Property { key, value }) .map_err(dispatch_to_evm::) } + /// Set collection properties. + /// + /// @param properties Vector of properties key/value pair. + #[weight(>::set_collection_properties(properties.len() as u32))] + fn set_collection_properties( + &mut self, + caller: caller, + properties: Vec, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + + let properties = properties + .into_iter() + .map(eth::Property::try_into) + .collect::>>()?; + + >::set_collection_properties(self, &caller, properties) + .map_err(dispatch_to_evm::) + } + /// Delete collection property. /// /// @param key Property key. + #[solidity(hide)] #[weight(>::delete_collection_properties(1))] fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> { - self.consume_store_reads_and_writes(1, 1)?; - let caller = T::CrossAccountId::from_eth(caller); let key = >::from(key) .try_into() @@ -106,6 +143,24 @@ where >::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::) } + /// Delete collection properties. + /// + /// @param keys Properties keys. + #[weight(>::delete_collection_properties(keys.len() as u32))] + fn delete_collection_properties(&mut self, caller: caller, keys: Vec) -> Result<()> { + let caller = T::CrossAccountId::from_eth(caller); + let keys = keys + .into_iter() + .map(|key| { + >::from(key) + .try_into() + .map_err(|_| Error::Revert("key too large".into())) + }) + .collect::>>()?; + + >::delete_collection_properties(self, &caller, keys).map_err(dispatch_to_evm::) + } + /// Get collection property. /// /// @dev Throws error if key not found. @@ -117,10 +172,37 @@ where .try_into() .map_err(|_| "key too large")?; - let props = >::get(self.id); + let props = CollectionProperties::::get(self.id); let prop = props.get(&key).ok_or("key not found")?; - Ok(prop.to_vec()) + Ok(bytes(prop.to_vec())) + } + + /// Get collection properties. + /// + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + fn collection_properties(&self, keys: Vec) -> Result> { + let keys = keys + .into_iter() + .map(|key| { + >::from(key) + .try_into() + .map_err(|_| Error::Revert("key too large".into())) + }) + .collect::>>()?; + + let properties = Pallet::::filter_collection_properties( + self.id, + if keys.is_empty() { None } else { Some(keys) }, + ) + .map_err(dispatch_to_evm::)?; + + let properties = properties + .into_iter() + .map(Property::try_into) + .collect::>>()?; + Ok(properties) } /// Set the sponsor of the collection. @@ -128,37 +210,35 @@ where /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. /// /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. + #[solidity(hide)] fn set_collection_sponsor(&mut self, caller: caller, sponsor: address) -> Result { self.consume_store_reads_and_writes(1, 1)?; - check_is_owner_or_admin(caller, self)?; + let caller = T::CrossAccountId::from_eth(caller); let sponsor = T::CrossAccountId::from_eth(sponsor); - self.set_sponsor(sponsor.as_sub().clone()) - .map_err(dispatch_to_evm::)?; - save(self) - } - - // TODO: Temprorary off. Need refactor - // /// Set the substrate sponsor of the collection. - // /// - // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. - // /// - // /// @param sponsor Substrate address of the sponsor from whose account funds will be debited for operations with the contract. - // fn set_collection_sponsor_substrate( - // &mut self, - // caller: caller, - // sponsor: uint256, - // ) -> Result { - // self.consume_store_reads_and_writes(1, 1)?; - - // check_is_owner_or_admin(caller, self)?; - - // let sponsor = convert_uint256_to_cross_account::(sponsor); - // self.set_sponsor(sponsor.as_sub().clone()) - // .map_err(dispatch_to_evm::)?; - // save(self) - // } + self.set_sponsor(&caller, sponsor.as_sub().clone()) + .map_err(dispatch_to_evm::) + } + + /// Set the sponsor of the collection. + /// + /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. + /// + /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract. + fn set_collection_sponsor_cross( + &mut self, + caller: caller, + sponsor: eth::CrossAddress, + ) -> Result { + self.consume_store_reads_and_writes(1, 1)?; + + let caller = T::CrossAccountId::from_eth(caller); + + let sponsor = sponsor.into_sub_cross_account::()?; + self.set_sponsor(&caller, sponsor.as_sub().clone()) + .map_err(dispatch_to_evm::) + } /// Whether there is a pending sponsor. fn has_collection_pending_sponsor(&self) -> Result { @@ -175,124 +255,101 @@ where self.consume_store_writes(1)?; let caller = T::CrossAccountId::from_eth(caller); - if !self - .confirm_sponsorship(caller.as_sub()) - .map_err(dispatch_to_evm::)? - { - return Err("caller is not set as sponsor".into()); - } - save(self) + self.confirm_sponsorship(caller.as_sub()) + .map_err(dispatch_to_evm::) } /// Remove collection sponsor. fn remove_collection_sponsor(&mut self, caller: caller) -> Result { self.consume_store_reads_and_writes(1, 1)?; - check_is_owner_or_admin(caller, self)?; - self.remove_sponsor().map_err(dispatch_to_evm::)?; - save(self) + let caller = T::CrossAccountId::from_eth(caller); + self.remove_sponsor(&caller).map_err(dispatch_to_evm::) } /// Get current sponsor. /// /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. - fn collection_sponsor(&self) -> Result<(address, uint256)> { + fn collection_sponsor(&self) -> Result { let sponsor = match self.collection.sponsorship.sponsor() { Some(sponsor) => sponsor, None => return Ok(Default::default()), }; - let sponsor = T::CrossAccountId::from_sub(sponsor.clone()); - let result: (address, uint256) = if sponsor.is_canonical_substrate() { - let sponsor = convert_cross_account_to_uint256::(&sponsor); - (Default::default(), sponsor) - } else { - let sponsor = *sponsor.as_eth(); - (sponsor, Default::default()) - }; - Ok(result) - } - /// Set limits for the collection. - /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "accountTokenOwnershipLimit", - /// "sponsoredDataSize", - /// "sponsoredDataRateLimit", - /// "tokenLimit", - /// "sponsorTransferTimeout", - /// "sponsorApproveTimeout" - /// @param value Value of the limit. - #[solidity(rename_selector = "setCollectionLimit")] - fn set_int_limit(&mut self, caller: caller, limit: string, value: uint32) -> Result { - self.consume_store_reads_and_writes(1, 1)?; - - check_is_owner_or_admin(caller, self)?; - let mut limits = self.limits.clone(); + Ok(eth::CrossAddress::from_sub::(&sponsor)) + } - match limit.as_str() { - "accountTokenOwnershipLimit" => { - limits.account_token_ownership_limit = Some(value); - } - "sponsoredDataSize" => { - limits.sponsored_data_size = Some(value); - } - "sponsoredDataRateLimit" => { - limits.sponsored_data_rate_limit = Some(SponsoringRateLimit::Blocks(value)); - } - "tokenLimit" => { - limits.token_limit = Some(value); - } - "sponsorTransferTimeout" => { - limits.sponsor_transfer_timeout = Some(value); - } - "sponsorApproveTimeout" => { - limits.sponsor_approve_timeout = Some(value); - } - _ => { - return Err(Error::Revert(format!( - "unknown integer limit \"{}\"", - limit - ))) - } - } - self.limits = >::clamp_limits(self.mode.clone(), &self.limits, limits) - .map_err(dispatch_to_evm::)?; - save(self) + /// Get current collection limits. + /// + /// @return Array of collection limits + fn collection_limits(&self) -> Result> { + let limits = &self.collection.limits; + + Ok(vec![ + eth::CollectionLimit::new( + eth::CollectionLimitField::AccountTokenOwnership, + limits.account_token_ownership_limit, + ), + eth::CollectionLimit::new( + eth::CollectionLimitField::SponsoredDataSize, + limits.sponsored_data_size, + ), + limits + .sponsored_data_rate_limit + .and_then(|limit| { + if let SponsoringRateLimit::Blocks(blocks) = limit { + Some(eth::CollectionLimit::new::( + eth::CollectionLimitField::SponsoredDataRateLimit, + blocks, + )) + } else { + None + } + }) + .unwrap_or(eth::CollectionLimit::new::( + eth::CollectionLimitField::SponsoredDataRateLimit, + Default::default(), + )), + eth::CollectionLimit::new(eth::CollectionLimitField::TokenLimit, limits.token_limit), + eth::CollectionLimit::new( + eth::CollectionLimitField::SponsorTransferTimeout, + limits.sponsor_transfer_timeout, + ), + eth::CollectionLimit::new( + eth::CollectionLimitField::SponsorApproveTimeout, + limits.sponsor_approve_timeout, + ), + eth::CollectionLimit::new( + eth::CollectionLimitField::OwnerCanTransfer, + limits.owner_can_transfer, + ), + eth::CollectionLimit::new( + eth::CollectionLimitField::OwnerCanDestroy, + limits.owner_can_destroy, + ), + eth::CollectionLimit::new( + eth::CollectionLimitField::TransferEnabled, + limits.transfers_enabled, + ), + ]) } /// Set limits for the collection. /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "ownerCanTransfer", - /// "ownerCanDestroy", - /// "transfersEnabled" - /// @param value Value of the limit. + /// @param limit Some limit. #[solidity(rename_selector = "setCollectionLimit")] - fn set_bool_limit(&mut self, caller: caller, limit: string, value: bool) -> Result { + fn set_collection_limit( + &mut self, + caller: caller, + limit: eth::CollectionLimit, + ) -> Result { self.consume_store_reads_and_writes(1, 1)?; - check_is_owner_or_admin(caller, self)?; - let mut limits = self.limits.clone(); - - match limit.as_str() { - "ownerCanTransfer" => { - limits.owner_can_transfer = Some(value); - } - "ownerCanDestroy" => { - limits.owner_can_destroy = Some(value); - } - "transfersEnabled" => { - limits.transfers_enabled = Some(value); - } - _ => { - return Err(Error::Revert(format!( - "unknown boolean limit \"{}\"", - limit - ))) - } + if !limit.has_value() { + return Err(Error::Revert("user can't disable limits".into())); } - self.limits = >::clamp_limits(self.mode.clone(), &self.limits, limits) - .map_err(dispatch_to_evm::)?; - save(self) + + let caller = T::CrossAccountId::from_eth(caller); + >::update_limits(&caller, self, limit.try_into()?).map_err(dispatch_to_evm::) } /// Get contract address. @@ -300,42 +357,41 @@ where Ok(crate::eth::collection_id_to_address(self.id)) } - // TODO: Temprorary off. Need refactor - // /// Add collection admin by substrate address. - // /// @param newAdmin Substrate administrator address. - // fn add_collection_admin_substrate( - // &mut self, - // caller: caller, - // new_admin: uint256, - // ) -> Result { - // self.consume_store_writes(2)?; - - // let caller = T::CrossAccountId::from_eth(caller); - // let new_admin = convert_uint256_to_cross_account::(new_admin); - // >::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::)?; - // Ok(()) - // } - - // TODO: Temprorary off. Need refactor - // /// Remove collection admin by substrate address. - // /// @param admin Substrate administrator address. - // fn remove_collection_admin_substrate( - // &mut self, - // caller: caller, - // admin: uint256, - // ) -> Result { - // self.consume_store_writes(2)?; - - // let caller = T::CrossAccountId::from_eth(caller); - // let admin = convert_uint256_to_cross_account::(admin); - // >::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::)?; - // Ok(()) - // } + /// Add collection admin. + /// @param newAdmin Cross account administrator address. + fn add_collection_admin_cross( + &mut self, + caller: caller, + new_admin: eth::CrossAddress, + ) -> Result { + self.consume_store_reads_and_writes(2, 2)?; + + let caller = T::CrossAccountId::from_eth(caller); + let new_admin = new_admin.into_sub_cross_account::()?; + >::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::)?; + Ok(()) + } + + /// Remove collection admin. + /// @param admin Cross account administrator address. + fn remove_collection_admin_cross( + &mut self, + caller: caller, + admin: eth::CrossAddress, + ) -> Result { + self.consume_store_reads_and_writes(2, 2)?; + + let caller = T::CrossAccountId::from_eth(caller); + let admin = admin.into_sub_cross_account::()?; + >::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::)?; + Ok(()) + } /// Add collection admin. /// @param newAdmin Address of the added administrator. + #[solidity(hide)] fn add_collection_admin(&mut self, caller: caller, new_admin: address) -> Result { - self.consume_store_writes(2)?; + self.consume_store_reads_and_writes(2, 2)?; let caller = T::CrossAccountId::from_eth(caller); let new_admin = T::CrossAccountId::from_eth(new_admin); @@ -346,8 +402,9 @@ where /// Remove collection admin. /// /// @param admin Address of the removed administrator. + #[solidity(hide)] fn remove_collection_admin(&mut self, caller: caller, admin: address) -> Result { - self.consume_store_writes(2)?; + self.consume_store_reads_and_writes(2, 2)?; let caller = T::CrossAccountId::from_eth(caller); let admin = T::CrossAccountId::from_eth(admin); @@ -362,7 +419,7 @@ where fn set_nesting_bool(&mut self, caller: caller, enable: bool) -> Result { self.consume_store_reads_and_writes(1, 1)?; - check_is_owner_or_admin(caller, self)?; + let caller = T::CrossAccountId::from_eth(caller); let mut permissions = self.collection.permissions.clone(); let mut nesting = permissions.nesting().clone(); @@ -370,14 +427,7 @@ where nesting.restricted = None; permissions.nesting = Some(nesting); - self.collection.permissions = >::clamp_permissions( - self.collection.mode.clone(), - &self.collection.permissions, - permissions, - ) - .map_err(dispatch_to_evm::)?; - - save(self) + >::update_permissions(&caller, self, permissions).map_err(dispatch_to_evm::) } /// Toggle accessibility of collection nesting. @@ -396,7 +446,7 @@ where if collections.is_empty() { return Err("no addresses provided".into()); } - check_is_owner_or_admin(caller, self)?; + let caller = T::CrossAccountId::from_eth(caller); let mut permissions = self.collection.permissions.clone(); match enable { @@ -421,16 +471,38 @@ where } }; - self.collection.permissions = >::clamp_permissions( - self.collection.mode.clone(), - &self.collection.permissions, - permissions, - ) - .map_err(dispatch_to_evm::)?; + >::update_permissions(&caller, self, permissions).map_err(dispatch_to_evm::) + } - save(self) + /// Returns nesting for a collection + #[solidity(rename_selector = "collectionNestingRestrictedCollectionIds")] + fn collection_nesting_restricted_ids(&self) -> Result { + let nesting = self.collection.permissions.nesting(); + + Ok(eth::CollectionNesting::new( + nesting.token_owner, + nesting + .restricted + .clone() + .map(|b| b.0.into_inner().iter().map(|id| id.0.into()).collect()) + .unwrap_or_default(), + )) } + /// Returns permissions for a collection + fn collection_nesting_permissions(&self) -> Result> { + let nesting = self.collection.permissions.nesting(); + Ok(vec![ + eth::CollectionNestingPermission::new( + eth::CollectionPermissionField::CollectionAdmin, + nesting.collection_admin, + ), + eth::CollectionNestingPermission::new( + eth::CollectionPermissionField::TokenOwner, + nesting.token_owner, + ), + ]) + } /// Set the collection access method. /// @param mode Access mode /// 0 for Normal @@ -438,7 +510,7 @@ where fn set_collection_access(&mut self, caller: caller, mode: uint8) -> Result { self.consume_store_reads_and_writes(1, 1)?; - check_is_owner_or_admin(caller, self)?; + let caller = T::CrossAccountId::from_eth(caller); let permissions = CollectionPermissions { access: Some(match mode { 0 => AccessMode::Normal, @@ -447,29 +519,21 @@ where }), ..Default::default() }; - self.collection.permissions = >::clamp_permissions( - self.collection.mode.clone(), - &self.collection.permissions, - permissions, - ) - .map_err(dispatch_to_evm::)?; - - save(self) + >::update_permissions(&caller, self, permissions).map_err(dispatch_to_evm::) } /// Checks that user allowed to operate with collection. /// /// @param user User address to check. - fn allowed(&self, user: address) -> Result { - Ok(Pallet::::allowed( - self.id, - T::CrossAccountId::from_eth(user), - )) + fn allowlisted_cross(&self, user: eth::CrossAddress) -> Result { + let user = user.into_sub_cross_account::()?; + Ok(Pallet::::allowed(self.id, user)) } /// Add the user to the allowed list. /// /// @param user Address of a trusted user. + #[solidity(hide)] fn add_to_collection_allow_list(&mut self, caller: caller, user: address) -> Result { self.consume_store_writes(1)?; @@ -479,26 +543,26 @@ where Ok(()) } - // TODO: Temprorary off. Need refactor - // /// Add substrate user to allowed list. - // /// - // /// @param user User substrate address. - // fn add_to_collection_allow_list_substrate( - // &mut self, - // caller: caller, - // user: uint256, - // ) -> Result { - // self.consume_store_writes(1)?; + /// Add user to allowed list. + /// + /// @param user User cross account address. + fn add_to_collection_allow_list_cross( + &mut self, + caller: caller, + user: eth::CrossAddress, + ) -> Result { + self.consume_store_writes(1)?; - // let caller = T::CrossAccountId::from_eth(caller); - // let user = convert_uint256_to_cross_account::(user); - // Pallet::::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::)?; - // Ok(()) - // } + let caller = T::CrossAccountId::from_eth(caller); + let user = user.into_sub_cross_account::()?; + Pallet::::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::)?; + Ok(()) + } /// Remove the user from the allowed list. /// /// @param user Address of a removed user. + #[solidity(hide)] fn remove_from_collection_allow_list(&mut self, caller: caller, user: address) -> Result { self.consume_store_writes(1)?; @@ -508,22 +572,21 @@ where Ok(()) } - // TODO: Temprorary off. Need refactor - // /// Remove substrate user from allowed list. - // /// - // /// @param user User substrate address. - // fn remove_from_collection_allow_list_substrate( - // &mut self, - // caller: caller, - // user: uint256, - // ) -> Result { - // self.consume_store_writes(1)?; + /// Remove user from allowed list. + /// + /// @param user User cross account address. + fn remove_from_collection_allow_list_cross( + &mut self, + caller: caller, + user: eth::CrossAddress, + ) -> Result { + self.consume_store_writes(1)?; - // let caller = T::CrossAccountId::from_eth(caller); - // let user = convert_uint256_to_cross_account::(user); - // Pallet::::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::)?; - // Ok(()) - // } + let caller = T::CrossAccountId::from_eth(caller); + let user = user.into_sub_cross_account::()?; + Pallet::::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::)?; + Ok(()) + } /// Switch permission for minting. /// @@ -531,40 +594,32 @@ where fn set_collection_mint_mode(&mut self, caller: caller, mode: bool) -> Result { self.consume_store_reads_and_writes(1, 1)?; - check_is_owner_or_admin(caller, self)?; + let caller = T::CrossAccountId::from_eth(caller); let permissions = CollectionPermissions { mint_mode: Some(mode), ..Default::default() }; - self.collection.permissions = >::clamp_permissions( - self.collection.mode.clone(), - &self.collection.permissions, - permissions, - ) - .map_err(dispatch_to_evm::)?; - - save(self) + >::update_permissions(&caller, self, permissions).map_err(dispatch_to_evm::) } /// Check that account is the owner or admin of the collection /// /// @param user account to verify /// @return "true" if account is the owner or admin - #[solidity(rename_selector = "isOwnerOrAdmin")] + #[solidity(hide, rename_selector = "isOwnerOrAdmin")] fn is_owner_or_admin_eth(&self, user: address) -> Result { let user = T::CrossAccountId::from_eth(user); Ok(self.is_owner_or_admin(&user)) } - // TODO: Temprorary off. Need refactor - // /// Check that substrate account is the owner or admin of the collection - // /// - // /// @param user account to verify - // /// @return "true" if account is the owner or admin - // fn is_owner_or_admin_substrate(&self, user: uint256) -> Result { - // let user = convert_uint256_to_cross_account::(user); - // Ok(self.is_owner_or_admin(&user)) - // } + /// Check that account is the owner or admin of the collection + /// + /// @param user User cross account to verify + /// @return "true" if account is the owner or admin + fn is_owner_or_admin_cross(&self, user: eth::CrossAddress) -> Result { + let user = user.into_sub_cross_account::()?; + Ok(self.is_owner_or_admin(&user)) + } /// Returns collection type /// @@ -582,8 +637,8 @@ where /// /// @return Tuble with sponsor address and his substrate mirror. /// If address is canonical then substrate mirror is zero and vice versa. - fn collection_owner(&self) -> Result<(address, uint256)> { - Ok(convert_cross_account_to_tuple::( + fn collection_owner(&self) -> Result { + Ok(eth::CrossAddress::from_sub_cross_account::( &T::CrossAccountId::from_sub(self.owner.clone()), )) } @@ -592,60 +647,43 @@ where /// /// @dev Owner can be changed only by current owner /// @param newOwner new owner account - #[solidity(rename_selector = "changeCollectionOwner")] + #[solidity(hide, rename_selector = "changeCollectionOwner")] fn set_owner(&mut self, caller: caller, new_owner: address) -> Result { self.consume_store_writes(1)?; let caller = T::CrossAccountId::from_eth(caller); let new_owner = T::CrossAccountId::from_eth(new_owner); - self.set_owner_internal(caller, new_owner) + self.change_owner(caller, new_owner) .map_err(dispatch_to_evm::) } - // TODO: Temprorary off. Need refactor - // /// Changes collection owner to another substrate account - // /// - // /// @dev Owner can be changed only by current owner - // /// @param newOwner new owner substrate account - // fn set_owner_substrate(&mut self, caller: caller, new_owner: uint256) -> Result { - // self.consume_store_writes(1)?; - - // let caller = T::CrossAccountId::from_eth(caller); - // let new_owner = convert_uint256_to_cross_account::(new_owner); - // self.set_owner_internal(caller, new_owner) - // .map_err(dispatch_to_evm::) - // } - - // TODO: need implement AbiWriter for &Vec - // fn collection_admins(&self) -> Result> { - // let result = pallet_common::IsAdmin::::iter_prefix((self.id,)) - // .map(|(admin, _)| pallet_common::eth::convert_cross_account_to_tuple::(&admin)) - // .collect(); - // Ok(result) - // } -} + /// Get collection administrators + /// + /// @return Vector of tuples with admins address and his substrate mirror. + /// If address is canonical then substrate mirror is zero and vice versa. + fn collection_admins(&self) -> Result> { + let result = crate::IsAdmin::::iter_prefix((self.id,)) + .map(|(admin, _)| eth::CrossAddress::from_sub_cross_account::(&admin)) + .collect(); + Ok(result) + } -/// ### Note -/// Do not forget to add: `self.consume_store_reads(1)?;` -fn check_is_owner_or_admin( - caller: caller, - collection: &CollectionHandle, -) -> Result { - let caller = T::CrossAccountId::from_eth(caller); - collection - .check_is_owner_or_admin(&caller) - .map_err(dispatch_to_evm::)?; - Ok(caller) -} + /// Changes collection owner to another account + /// + /// @dev Owner can be changed only by current owner + /// @param newOwner new owner cross account + fn change_collection_owner_cross( + &mut self, + caller: caller, + new_owner: eth::CrossAddress, + ) -> Result { + self.consume_store_writes(1)?; -/// ### Note -/// Do not forget to add: `self.consume_store_writes(1)?;` -fn save(collection: &CollectionHandle) -> Result { - collection - .check_is_internal() - .map_err(dispatch_to_evm::)?; - collection.save().map_err(dispatch_to_evm::)?; - Ok(()) + let caller = T::CrossAccountId::from_eth(caller); + let new_owner = new_owner.into_sub_cross_account::()?; + self.change_owner(caller, new_owner) + .map_err(dispatch_to_evm::) + } } /// Contains static property keys and values. diff --git a/pallets/common/src/eth.rs b/pallets/common/src/eth.rs index f25c65a6f4..ee2ff62d2b 100644 --- a/pallets/common/src/eth.rs +++ b/pallets/common/src/eth.rs @@ -16,8 +16,13 @@ //! The module contains a number of functions for converting and checking ethereum identifiers. -use evm_coder::types::{uint256, address}; -pub use pallet_evm::account::{Config, CrossAccountId}; +use alloc::format; +use sp_std::{vec, vec::Vec}; +use evm_coder::{ + AbiCoder, + types::{uint256, address}, +}; +pub use pallet_evm::{Config, account::CrossAccountId}; use sp_core::H160; use up_data_structs::CollectionId; @@ -50,15 +55,6 @@ pub fn is_collection(address: &H160) -> bool { address[0..16] == ETH_COLLECTION_PREFIX } -/// Convert `CrossAccountId` to `uint256`. -pub fn convert_cross_account_to_uint256(from: &T::CrossAccountId) -> uint256 -where - T::AccountId: AsRef<[u8; 32]>, -{ - let slice = from.as_sub().as_ref(); - uint256::from_big_endian(slice) -} - /// Convert `uint256` to `CrossAccountId`. pub fn convert_uint256_to_cross_account(from: uint256) -> T::CrossAccountId where @@ -70,18 +66,410 @@ where T::CrossAccountId::from_sub(account_id) } -/// Convert `CrossAccountId` to `(address, uint256)`. -pub fn convert_cross_account_to_tuple( - cross_account_id: &T::CrossAccountId, -) -> (address, uint256) -where - T::AccountId: AsRef<[u8; 32]>, +/// Ethereum representation of Optional value with uint256. +#[derive(Debug, Default, AbiCoder)] +pub struct OptionUint { + status: bool, + value: uint256, +} + +impl From for OptionUint { + fn from(value: u32) -> Self { + Self { + status: true, + value: uint256::from(value), + } + } +} + +impl From> for OptionUint { + fn from(value: Option) -> Self { + match value { + Some(value) => Self { + status: true, + value: value.into(), + }, + None => Self { + status: false, + value: Default::default(), + }, + } + } +} + +impl From for OptionUint { + fn from(value: bool) -> Self { + Self { + status: true, + value: if value { + uint256::from(1) + } else { + Default::default() + }, + } + } +} + +impl From> for OptionUint { + fn from(value: Option) -> Self { + match value { + Some(value) => Self::from(value), + None => Self { + status: false, + value: Default::default(), + }, + } + } +} + +/// Ethereum representation of Optional value with CrossAddress. +#[derive(Debug, Default, AbiCoder)] +pub struct OptionCrossAddress { + /// Whether or not this CrossAdress is valid and has meaning. + pub status: bool, + /// The underlying CrossAddress value. If the status is false, can be set to whatever. + pub value: CrossAddress, +} + +/// Cross account struct +#[derive(Debug, Default, AbiCoder)] +pub struct CrossAddress { + pub(crate) eth: address, + pub(crate) sub: uint256, +} + +impl CrossAddress { + /// Converts `CrossAccountId` to [`CrossAddress`] to be correctly usable with Ethereum. + pub fn from_sub_cross_account(cross_account_id: &T::CrossAccountId) -> Self + where + T: pallet_evm::Config, + T::AccountId: AsRef<[u8; 32]>, + { + if cross_account_id.is_canonical_substrate() { + Self::from_sub::(cross_account_id.as_sub()) + } else { + Self { + eth: *cross_account_id.as_eth(), + sub: Default::default(), + } + } + } + /// Creates [`CrossAddress`] from Substrate account. + pub fn from_sub(account_id: &T::AccountId) -> Self + where + T: pallet_evm::Config, + T::AccountId: AsRef<[u8; 32]>, + { + Self { + eth: Default::default(), + sub: uint256::from_big_endian(account_id.as_ref()), + } + } + /// Converts [`CrossAddress`] to `CrossAccountId`. + pub fn into_sub_cross_account(&self) -> evm_coder::execution::Result + where + T: pallet_evm::Config, + T::AccountId: From<[u8; 32]>, + { + if self.eth == Default::default() && self.sub == Default::default() { + Err("All fields of cross account is zeroed".into()) + } else if self.eth == Default::default() { + Ok(convert_uint256_to_cross_account::(self.sub)) + } else if self.sub == Default::default() { + Ok(T::CrossAccountId::from_eth(self.eth)) + } else { + Err("All fields of cross account is non zeroed".into()) + } + } +} + +/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue). +#[derive(Debug, Default, AbiCoder)] +pub struct Property { + key: evm_coder::types::string, + value: evm_coder::types::bytes, +} + +impl TryFrom for Property { + type Error = evm_coder::execution::Error; + + fn try_from(from: up_data_structs::Property) -> Result { + let key = evm_coder::types::string::from_utf8(from.key.into()) + .map_err(|e| Self::Error::Revert(format!("utf8 conversion error: {}", e)))?; + let value = evm_coder::types::bytes(from.value.to_vec()); + Ok(Property { key, value }) + } +} + +impl TryInto for Property { + type Error = evm_coder::execution::Error; + + fn try_into(self) -> Result { + let key = >::from(self.key) + .try_into() + .map_err(|_| "key too large")?; + + let value = self.value.0.try_into().map_err(|_| "value too large")?; + + Ok(up_data_structs::Property { key, value }) + } +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM. +#[derive(Debug, Default, Clone, Copy, AbiCoder)] +#[repr(u8)] +pub enum CollectionLimitField { + /// How many tokens can a user have on one account. + #[default] + AccountTokenOwnership, + + /// How many bytes of data are available for sponsorship. + SponsoredDataSize, + + /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`] + SponsoredDataRateLimit, + + /// How many tokens can be mined into this collection. + TokenLimit, + + /// Timeouts for transfer sponsoring. + SponsorTransferTimeout, + + /// Timeout for sponsoring an approval in passed blocks. + SponsorApproveTimeout, + + /// Whether the collection owner of the collection can send tokens (which belong to other users). + OwnerCanTransfer, + + /// Can the collection owner burn other people's tokens. + OwnerCanDestroy, + + /// Is it possible to send tokens from this collection between users. + TransferEnabled, +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM. +#[derive(Debug, Default, AbiCoder)] +pub struct CollectionLimit { + field: CollectionLimitField, + value: OptionUint, +} + +impl CollectionLimit { + /// Create [`CollectionLimit`] from field and value. + pub fn new(field: CollectionLimitField, value: T) -> Self + where + OptionUint: From, + { + Self { + field, + value: value.into(), + } + } + /// Whether the field contains a value. + pub fn has_value(&self) -> bool { + self.value.status + } +} + +impl TryInto for CollectionLimit { + type Error = evm_coder::execution::Error; + + fn try_into(self) -> Result { + let value = self.value.value.try_into().map_err(|error| { + Self::Error::Revert(format!( + "can't convert value to u32 \"{}\" because: \"{error}\"", + self.value.value + )) + })?; + + let convert_value_to_bool = || match value { + 0 => Ok(false), + 1 => Ok(true), + _ => { + return Err(Self::Error::Revert(format!( + "can't convert value to boolean \"{value}\"" + ))) + } + }; + + let mut limits = up_data_structs::CollectionLimits::default(); + match self.field { + CollectionLimitField::AccountTokenOwnership => { + limits.account_token_ownership_limit = Some(value); + } + CollectionLimitField::SponsoredDataSize => { + limits.sponsored_data_size = Some(value); + } + CollectionLimitField::SponsoredDataRateLimit => { + limits.sponsored_data_rate_limit = + Some(up_data_structs::SponsoringRateLimit::Blocks(value)); + } + CollectionLimitField::TokenLimit => { + limits.token_limit = Some(value); + } + CollectionLimitField::SponsorTransferTimeout => { + limits.sponsor_transfer_timeout = Some(value); + } + CollectionLimitField::SponsorApproveTimeout => { + limits.sponsor_approve_timeout = Some(value); + } + CollectionLimitField::OwnerCanTransfer => { + limits.owner_can_transfer = Some(convert_value_to_bool()?); + } + CollectionLimitField::OwnerCanDestroy => { + limits.owner_can_destroy = Some(convert_value_to_bool()?); + } + CollectionLimitField::TransferEnabled => { + limits.transfers_enabled = Some(convert_value_to_bool()?); + } + }; + Ok(limits) + } +} + +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration. +#[derive(Default, Debug, Clone, Copy, AbiCoder)] +#[repr(u8)] +pub enum CollectionPermissionField { + /// Owner of token can nest tokens under it. + #[default] + TokenOwner, + + /// Admin of token collection can nest tokens under token. + CollectionAdmin, +} + +/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration. +#[derive(AbiCoder, Copy, Clone, Default, Debug)] +#[repr(u8)] +pub enum TokenPermissionField { + /// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`] + #[default] + Mutable, + + /// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`] + TokenOwner, + + /// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`] + CollectionAdmin, +} + +/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value. +#[derive(Debug, Default, AbiCoder)] +pub struct PropertyPermission { + /// TokenPermission field. + code: TokenPermissionField, + /// TokenPermission value. + value: bool, +} + +impl PropertyPermission { + /// Make vector of [`PropertyPermission`] from [`up_data_structs::PropertyPermission`]. + pub fn into_vec(pp: up_data_structs::PropertyPermission) -> Vec { + vec![ + PropertyPermission { + code: TokenPermissionField::Mutable, + value: pp.mutable, + }, + PropertyPermission { + code: TokenPermissionField::TokenOwner, + value: pp.token_owner, + }, + PropertyPermission { + code: TokenPermissionField::CollectionAdmin, + value: pp.collection_admin, + }, + ] + } + + /// Make [`up_data_structs::PropertyPermission`] from vector of [`PropertyPermission`]. + pub fn from_vec(permission: Vec) -> up_data_structs::PropertyPermission { + let mut token_permission = up_data_structs::PropertyPermission::default(); + + for PropertyPermission { code, value } in permission { + match code { + TokenPermissionField::Mutable => token_permission.mutable = value, + TokenPermissionField::TokenOwner => token_permission.token_owner = value, + TokenPermissionField::CollectionAdmin => token_permission.collection_admin = value, + } + } + token_permission + } +} + +/// Ethereum representation of Token Property Permissions. +#[derive(Debug, Default, AbiCoder)] +pub struct TokenPropertyPermission { + /// Token property key. + key: evm_coder::types::string, + /// Token property permissions. + permissions: Vec, +} + +impl + From<( + up_data_structs::PropertyKey, + up_data_structs::PropertyPermission, + )> for TokenPropertyPermission { - if cross_account_id.is_canonical_substrate() { - let sub = convert_cross_account_to_uint256::(cross_account_id); - (Default::default(), sub) - } else { - let eth = *cross_account_id.as_eth(); - (eth, Default::default()) + fn from( + value: ( + up_data_structs::PropertyKey, + up_data_structs::PropertyPermission, + ), + ) -> Self { + let (key, permission) = value; + let key = evm_coder::types::string::from_utf8(key.into_inner()) + .expect("Stored key must be valid"); + let permissions = PropertyPermission::into_vec(permission); + Self { key, permissions } + } +} + +impl TokenPropertyPermission { + /// Convert vector of [`TokenPropertyPermission`] into vector of [`up_data_structs::PropertyKeyPermission`]. + pub fn into_property_key_permissions( + permissions: Vec, + ) -> evm_coder::execution::Result> { + let mut perms = Vec::new(); + + for TokenPropertyPermission { key, permissions } in permissions { + let token_permission = PropertyPermission::from_vec(permissions); + + perms.push(up_data_structs::PropertyKeyPermission { + key: key.into_bytes().try_into().map_err(|_| "too long key")?, + permission: token_permission, + }); + } + Ok(perms) + } +} + +/// Nested collections. +#[derive(Debug, Default, AbiCoder)] +pub struct CollectionNesting { + token_owner: bool, + ids: Vec, +} + +impl CollectionNesting { + /// Create [`CollectionNesting`]. + pub fn new(token_owner: bool, ids: Vec) -> Self { + Self { token_owner, ids } + } +} + +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field. +#[derive(Debug, Default, AbiCoder)] +pub struct CollectionNestingPermission { + field: CollectionPermissionField, + value: bool, +} + +impl CollectionNestingPermission { + /// Create [`CollectionNestingPermission`]. + pub fn new(field: CollectionPermissionField, value: bool) -> Self { + Self { field, value } } } diff --git a/pallets/common/src/lib.rs b/pallets/common/src/lib.rs index 962611dff6..1fd467b8d5 100644 --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -115,6 +115,7 @@ use up_data_structs::{ RmrkNftChild, CollectionPermissions, }; +use up_pov_estimate_rpc::PovInfo; pub use pallet::*; use sp_core::H160; @@ -229,28 +230,111 @@ impl CollectionHandle { /// Unique collections allows sponsoring for certain actions. /// This method allows you to set the sponsor of the collection. /// In order for sponsorship to become active, it must be confirmed through [`Self::confirm_sponsorship`]. - pub fn set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult { - self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor); - Ok(()) + pub fn set_sponsor( + &mut self, + sender: &T::CrossAccountId, + sponsor: T::AccountId, + ) -> DispatchResult { + self.check_is_internal()?; + self.check_is_owner_or_admin(sender)?; + + self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor.clone()); + + >::deposit_event(Event::::CollectionSponsorSet(self.id, sponsor)); + >::deposit_log( + erc::CollectionHelpersEvents::CollectionChanged { + collection_id: eth::collection_id_to_address(self.id), + } + .to_log(T::ContractAddress::get()), + ); + + self.save() + } + + /// Force set `sponsor`. + /// + /// Differs from [`set_sponsor`][`Self::set_sponsor`] in that confirmation + /// from the `sponsor` is not required. + /// + /// # Arguments + /// + /// * `sender`: Caller's account. + /// * `sponsor`: ID of the account of the sponsor-to-be. + pub fn force_set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult { + self.check_is_internal()?; + + self.collection.sponsorship = SponsorshipState::Confirmed(sponsor.clone()); + + >::deposit_event(Event::::CollectionSponsorSet(self.id, sponsor.clone())); + >::deposit_event(Event::::SponsorshipConfirmed(self.id, sponsor)); + >::deposit_log( + erc::CollectionHelpersEvents::CollectionChanged { + collection_id: eth::collection_id_to_address(self.id), + } + .to_log(T::ContractAddress::get()), + ); + + self.save() } /// Confirm sponsorship /// /// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation. /// Before confirming sponsorship, the user must be specified as the sponsor of the collection via [`Self::set_sponsor`]. - pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> Result { - if self.collection.sponsorship.pending_sponsor() != Some(sender) { - return Ok(false); - } + pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> DispatchResult { + self.check_is_internal()?; + ensure!( + self.collection.sponsorship.pending_sponsor() == Some(sender), + Error::::ConfirmSponsorshipFail + ); self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone()); - Ok(true) + + >::deposit_event(Event::::SponsorshipConfirmed(self.id, sender.clone())); + >::deposit_log( + erc::CollectionHelpersEvents::CollectionChanged { + collection_id: eth::collection_id_to_address(self.id), + } + .to_log(T::ContractAddress::get()), + ); + + self.save() } /// Remove collection sponsor. - pub fn remove_sponsor(&mut self) -> DispatchResult { + pub fn remove_sponsor(&mut self, sender: &T::CrossAccountId) -> DispatchResult { + self.check_is_internal()?; + self.check_is_owner_or_admin(sender)?; + self.collection.sponsorship = SponsorshipState::Disabled; - Ok(()) + + >::deposit_event(Event::::CollectionSponsorRemoved(self.id)); + >::deposit_log( + erc::CollectionHelpersEvents::CollectionChanged { + collection_id: eth::collection_id_to_address(self.id), + } + .to_log(T::ContractAddress::get()), + ); + self.save() + } + + /// Force remove `sponsor`. + /// + /// Differs from `remove_sponsor` in that + /// it doesn't require consent from the `owner` of the collection. + pub fn force_remove_sponsor(&mut self) -> DispatchResult { + self.check_is_internal()?; + + self.collection.sponsorship = SponsorshipState::Disabled; + + >::deposit_event(Event::::CollectionSponsorRemoved(self.id)); + >::deposit_log( + erc::CollectionHelpersEvents::CollectionChanged { + collection_id: eth::collection_id_to_address(self.id), + } + .to_log(T::ContractAddress::get()), + ); + self.save() } /// Checks that the collection was created with, and must be operated upon through **Unique API**. @@ -328,13 +412,26 @@ impl CollectionHandle { /// Changes collection owner to another account /// #### Store read/writes /// 1 writes - fn set_owner_internal( + pub fn change_owner( &mut self, caller: T::CrossAccountId, new_owner: T::CrossAccountId, ) -> DispatchResult { + self.check_is_internal()?; self.check_is_owner(&caller)?; self.collection.owner = new_owner.as_sub().clone(); + + >::deposit_event(Event::::CollectionOwnerChanged( + self.id, + new_owner.as_sub().clone(), + )); + >::deposit_log( + erc::CollectionHelpersEvents::CollectionChanged { + collection_id: eth::collection_id_to_address(self.id), + } + .to_log(T::ContractAddress::get()), + ); + self.save() } } @@ -342,7 +439,6 @@ impl CollectionHandle { #[frame_support::pallet] pub mod pallet { use super::*; - use pallet_evm::account; use dispatch::CollectionDispatch; use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion}; use frame_system::pallet_prelude::*; @@ -353,11 +449,7 @@ pub mod pallet { #[pallet::config] pub trait Config: - frame_system::Config - + pallet_evm_coder_substrate::Config - + pallet_evm::Config - + TypeInfo - + account::Config + frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::Config + TypeInfo { /// Weight information for functions of this pallet. type WeightInfo: WeightInfo; @@ -381,6 +473,7 @@ pub mod pallet { type TreasuryAccountId: Get; /// Address under which the CollectionHelper contract would be available. + #[pallet::constant] type ContractAddress: Get; /// Mapper for token addresses to Ethereum addresses. @@ -476,6 +569,18 @@ pub mod pallet { u128, ), + /// A `sender` approves operations on all owned tokens for `spender`. + ApprovedForAll( + /// Id of collection to which item is belong. + CollectionId, + /// Owner of a wallet. + T::CrossAccountId, + /// Id for which operator status was granted or rewoked. + T::CrossAccountId, + /// Is operator status granted or revoked? + bool, + ), + /// The colletion property has been added or edited. CollectionPropertySet( /// Id of collection to which property has been set. @@ -519,6 +624,80 @@ pub mod pallet { /// The property permission that was set. PropertyKey, ), + + /// Address was added to the allow list. + AllowListAddressAdded( + /// ID of the affected collection. + CollectionId, + /// Address of the added account. + T::CrossAccountId, + ), + + /// Address was removed from the allow list. + AllowListAddressRemoved( + /// ID of the affected collection. + CollectionId, + /// Address of the removed account. + T::CrossAccountId, + ), + + /// Collection admin was added. + CollectionAdminAdded( + /// ID of the affected collection. + CollectionId, + /// Admin address. + T::CrossAccountId, + ), + + /// Collection admin was removed. + CollectionAdminRemoved( + /// ID of the affected collection. + CollectionId, + /// Removed admin address. + T::CrossAccountId, + ), + + /// Collection limits were set. + CollectionLimitSet( + /// ID of the affected collection. + CollectionId, + ), + + /// Collection owned was changed. + CollectionOwnerChanged( + /// ID of the affected collection. + CollectionId, + /// New owner address. + T::AccountId, + ), + + /// Collection permissions were set. + CollectionPermissionSet( + /// ID of the affected collection. + CollectionId, + ), + + /// Collection sponsor was set. + CollectionSponsorSet( + /// ID of the affected collection. + CollectionId, + /// New sponsor address. + T::AccountId, + ), + + /// New sponsor was confirm. + SponsorshipConfirmed( + /// ID of the affected collection. + CollectionId, + /// New sponsor address. + T::AccountId, + ), + + /// Collection sponsor was removed. + CollectionSponsorRemoved( + /// ID of the affected collection. + CollectionId, + ), } #[pallet::error] @@ -605,6 +784,12 @@ pub mod pallet { /// Tried to access an internal collection with an external API CollectionIsInternal, + + /// This address is not set as sponsor, use setCollectionSponsor first. + ConfirmSponsorshipFail, + + /// The user is not an administrator. + UserIsNotCollectionAdmin, } /// Storage of the count of created collections. Essentially contains the last collection ID. @@ -697,6 +882,8 @@ pub mod pallet { RmrkPartType, RmrkBoundedTheme, RmrkNftChild, + // PoV Estimate Info + PovInfo, )>, ), QueryKind = OptionQuery, @@ -999,6 +1186,13 @@ impl Pallet { >::remove(collection.id); >::deposit_event(Event::CollectionDestroyed(collection.id)); + + >::deposit_log( + erc::CollectionHelpersEvents::CollectionDestroyed { + collection_id: eth::collection_id_to_address(collection.id), + } + .to_log(T::ContractAddress::get()), + ); Ok(()) } @@ -1021,11 +1215,18 @@ impl Pallet { .map_err(>::from)?; Self::deposit_event(Event::CollectionPropertySet(collection.id, property.key)); + >::deposit_log( + erc::CollectionHelpersEvents::CollectionChanged { + collection_id: eth::collection_id_to_address(collection.id), + } + .to_log(T::ContractAddress::get()), + ); Ok(()) } - /// Set scouped collection property. + /// Set a scoped collection property, where the scope is a special prefix + /// prohibiting a user access to change the property directly. /// /// * `collection_id` - ID of the collection for which the property is being set. /// * `scope` - Property scope. @@ -1043,7 +1244,8 @@ impl Pallet { Ok(()) } - /// Set scouped collection properties. + /// Set scoped collection properties, where the scope is a special prefix + /// prohibiting a user access to change the properties directly. /// /// * `collection_id` - ID of the collection for which the properties is being set. /// * `scope` - Property scope. @@ -1100,6 +1302,12 @@ impl Pallet { collection.id, property_key, )); + >::deposit_log( + erc::CollectionHelpersEvents::CollectionChanged { + collection_id: eth::collection_id_to_address(collection.id), + } + .to_log(T::ContractAddress::get()), + ); Ok(()) } @@ -1194,6 +1402,12 @@ impl Pallet { collection.id, property_permission.key, )); + >::deposit_log( + erc::CollectionHelpersEvents::CollectionChanged { + collection_id: eth::collection_id_to_address(collection.id), + } + .to_log(T::ContractAddress::get()), + ); Ok(()) } @@ -1330,30 +1544,52 @@ impl Pallet { if allowed { >::insert((collection.id, user), true); + Self::deposit_event(Event::::AllowListAddressAdded( + collection.id, + user.clone(), + )); } else { >::remove((collection.id, user)); + Self::deposit_event(Event::::AllowListAddressRemoved( + collection.id, + user.clone(), + )); } + >::deposit_log( + erc::CollectionHelpersEvents::CollectionChanged { + collection_id: eth::collection_id_to_address(collection.id), + } + .to_log(T::ContractAddress::get()), + ); + Ok(()) } /// Toggle `user` participation in the `collection`'s admin list. /// #### Store read/writes - /// 2 writes + /// 2 reads, 2 writes pub fn toggle_admin( collection: &CollectionHandle, sender: &T::CrossAccountId, user: &T::CrossAccountId, admin: bool, ) -> DispatchResult { + collection.check_is_internal()?; collection.check_is_owner(sender)?; - let was_admin = >::get((collection.id, user)); - if was_admin == admin { - return Ok(()); + let is_admin = >::get((collection.id, user)); + if is_admin == admin { + if admin { + return Ok(()); + } else { + return Err(Error::::UserIsNotCollectionAdmin.into()); + } } let amount = >::get(collection.id); + // ========= + if admin { let amount = amount .checked_add(1) @@ -1363,20 +1599,58 @@ impl Pallet { >::CollectionAdminCountExceeded, ); - // ========= - >::insert(collection.id, amount); >::insert((collection.id, user), true); + + Self::deposit_event(Event::::CollectionAdminAdded( + collection.id, + user.clone(), + )); } else { >::insert(collection.id, amount.saturating_sub(1)); >::remove((collection.id, user)); + + Self::deposit_event(Event::::CollectionAdminRemoved( + collection.id, + user.clone(), + )); } + >::deposit_log( + erc::CollectionHelpersEvents::CollectionChanged { + collection_id: eth::collection_id_to_address(collection.id), + } + .to_log(T::ContractAddress::get()), + ); + Ok(()) } + /// Update collection limits. + pub fn update_limits( + user: &T::CrossAccountId, + collection: &mut CollectionHandle, + new_limit: CollectionLimits, + ) -> DispatchResult { + collection.check_is_internal()?; + collection.check_is_owner_or_admin(user)?; + + collection.limits = + Self::clamp_limits(collection.mode.clone(), &collection.limits, new_limit)?; + + Self::deposit_event(Event::::CollectionLimitSet(collection.id)); + >::deposit_log( + erc::CollectionHelpersEvents::CollectionChanged { + collection_id: eth::collection_id_to_address(collection.id), + } + .to_log(T::ContractAddress::get()), + ); + + collection.save() + } + /// Merge set fields from `new_limit` to `old_limit`. - pub fn clamp_limits( + fn clamp_limits( mode: CollectionMode, old_limit: &CollectionLimits, mut new_limit: CollectionLimits, @@ -1421,8 +1695,33 @@ impl Pallet { Ok(new_limit) } + /// Update collection permissions. + pub fn update_permissions( + user: &T::CrossAccountId, + collection: &mut CollectionHandle, + new_permission: CollectionPermissions, + ) -> DispatchResult { + collection.check_is_internal()?; + collection.check_is_owner_or_admin(user)?; + collection.permissions = Self::clamp_permissions( + collection.mode.clone(), + &collection.permissions, + new_permission, + )?; + + Self::deposit_event(Event::::CollectionPermissionSet(collection.id)); + >::deposit_log( + erc::CollectionHelpersEvents::CollectionChanged { + collection_id: eth::collection_id_to_address(collection.id), + } + .to_log(T::ContractAddress::get()), + ); + + collection.save() + } + /// Merge set fields from `new_permission` to `old_permission`. - pub fn clamp_permissions( + fn clamp_permissions( _mode: CollectionMode, old_permission: &CollectionPermissions, mut new_permission: CollectionPermissions, @@ -1434,6 +1733,15 @@ impl Pallet { ); Ok(new_permission) } + + /// Repair possibly broken properties of a collection. + pub fn repair_collection(collection_id: CollectionId) -> DispatchResult { + CollectionProperties::::mutate(collection_id, |properties| { + properties.recompute_consumed_space(); + }); + + Ok(()) + } } /// Indicates unsupported methods by returning [Error::UnsupportedOperation]. @@ -1519,8 +1827,11 @@ pub trait CommonWeightInfo { /// The price of retrieving token owner fn token_owner() -> Weight; + /// The price of setting approval for all + fn set_allowance_for_all() -> Weight; + /// The price of repairing an item. - fn repair_item() -> Weight; + fn force_repair_item() -> Weight; } /// Weight info extension trait for refungible pallet. @@ -1829,6 +2140,20 @@ pub trait CommonCollectionOperations { /// Get extension for RFT collection. fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions>; + /// The `operator` is allowed to transfer all tokens of the `owner` on their behalf. + /// * `owner` - Token owner + /// * `operator` - Operator + /// * `approve` - Should operator status be granted or revoked? + fn set_allowance_for_all( + &self, + owner: T::CrossAccountId, + operator: T::CrossAccountId, + approve: bool, + ) -> DispatchResultWithPostInfo; + + /// Tells whether the given `owner` approves the `operator`. + fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool; + /// Repairs a possibly broken item. fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo; } diff --git a/pallets/common/src/weights.rs b/pallets/common/src/weights.rs index 756d94a9e6..924732fbb7 100644 --- a/pallets/common/src/weights.rs +++ b/pallets/common/src/weights.rs @@ -26,6 +26,7 @@ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] #![allow(clippy::unnecessary_cast)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; diff --git a/pallets/configuration/Cargo.toml b/pallets/configuration/Cargo.toml index 1026ac7169..f65a0e78ee 100644 --- a/pallets/configuration/Cargo.toml +++ b/pallets/configuration/Cargo.toml @@ -10,15 +10,15 @@ parity-scale-codec = { version = "3.1.5", features = [ scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-arithmetic = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-arithmetic = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } smallvec = "1.6.1" -xcm = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.30" } +xcm = { default-features = false, git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.36" } [features] default = ["std"] diff --git a/pallets/configuration/src/lib.rs b/pallets/configuration/src/lib.rs index 72f60dbf05..e18f53c8c4 100644 --- a/pallets/configuration/src/lib.rs +++ b/pallets/configuration/src/lib.rs @@ -25,12 +25,14 @@ use frame_support::{ }; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_arithmetic::traits::{BaseArithmetic, Unsigned}; +use sp_arithmetic::{ + per_things::{Perbill, PerThing}, + traits::{BaseArithmetic, Unsigned}, +}; use smallvec::smallvec; pub use pallet::*; use sp_core::U256; -use sp_runtime::Perbill; #[pallet] mod pallet { @@ -46,8 +48,7 @@ mod pallet { #[pallet::config] pub trait Config: frame_system::Config { #[pallet::constant] - type DefaultWeightToFeeCoefficient: Get; - + type DefaultWeightToFeeCoefficient: Get; #[pallet::constant] type DefaultMinGasPrice: Get; @@ -66,7 +67,7 @@ mod pallet { #[pallet::storage] pub type WeightToFeeCoefficientOverride = StorageValue< - Value = u32, + Value = u64, QueryKind = ValueQuery, OnEmpty = T::DefaultWeightToFeeCoefficient, >; @@ -87,10 +88,11 @@ mod pallet { #[pallet::call] impl Pallet { + #[pallet::call_index(0)] #[pallet::weight(T::DbWeight::get().writes(1))] pub fn set_weight_to_fee_coefficient_override( origin: OriginFor, - coeff: Option, + coeff: Option, ) -> DispatchResult { ensure_root(origin)?; if let Some(coeff) = coeff { @@ -101,6 +103,7 @@ mod pallet { Ok(()) } + #[pallet::call_index(1)] #[pallet::weight(T::DbWeight::get().writes(1))] pub fn set_min_gas_price_override( origin: OriginFor, @@ -115,6 +118,7 @@ mod pallet { Ok(()) } + #[pallet::call_index(2)] #[pallet::weight(T::DbWeight::get().writes(1))] pub fn set_xcm_allowed_locations( origin: OriginFor, @@ -125,6 +129,7 @@ mod pallet { Ok(()) } + #[pallet::call_index(3)] #[pallet::weight(T::DbWeight::get().writes(1))] pub fn set_app_promotion_configuration_override( origin: OriginFor, @@ -156,14 +161,17 @@ pub struct WeightToFee(PhantomData<(T, B)>); impl WeightToFeePolynomial for WeightToFee where T: Config, - B: BaseArithmetic + From + Copy + Unsigned, + B: BaseArithmetic + From + From + Copy + Unsigned, { type Balance = B; fn polynomial() -> WeightToFeeCoefficients { smallvec!(WeightToFeeCoefficient { - coeff_integer: >::get().into(), - coeff_frac: Perbill::zero(), + coeff_integer: (>::get() / Perbill::ACCURACY as u64) + .into(), + coeff_frac: Perbill::from_parts( + (>::get() % Perbill::ACCURACY as u64) as u32 + ), negative: false, degree: 1, }) diff --git a/pallets/evm-coder-substrate/Cargo.toml b/pallets/evm-coder-substrate/Cargo.toml index a24f275296..10c6ce729e 100644 --- a/pallets/evm-coder-substrate/Cargo.toml +++ b/pallets/evm-coder-substrate/Cargo.toml @@ -8,15 +8,15 @@ edition = "2021" scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -ethereum = { version = "0.12.0", default-features = false } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +ethereum = { version = "0.14.0", default-features = false } evm-coder = { default-features = false, path = "../../crates/evm-coder" } -pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } up-data-structs = { default-features = false, path = "../../primitives/data-structs" } [dependencies.codec] diff --git a/pallets/evm-coder-substrate/src/lib.rs b/pallets/evm-coder-substrate/src/lib.rs index 6d9bc2644f..0bbd74b626 100644 --- a/pallets/evm-coder-substrate/src/lib.rs +++ b/pallets/evm-coder-substrate/src/lib.rs @@ -73,6 +73,7 @@ pub mod pallet { #[pallet::call] impl Pallet { + #[pallet::call_index(0)] #[pallet::weight(0)] pub fn empty_call(origin: OriginFor) -> DispatchResult { let _sender = ensure_signed(origin)?; diff --git a/pallets/evm-contract-helpers/Cargo.toml b/pallets/evm-contract-helpers/Cargo.toml index 287044a30e..54e2df8703 100644 --- a/pallets/evm-contract-helpers/Cargo.toml +++ b/pallets/evm-contract-helpers/Cargo.toml @@ -9,25 +9,25 @@ scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } log = { default-features = false, version = "0.4.14" } -ethereum = { version = "0.12.0", default-features = false } +ethereum = { version = "0.14.0", default-features = false } # Substrate -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } # Unique -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.36" } # Locals evm-coder = { default-features = false, path = '../../crates/evm-coder' } pallet-common = { default-features = false, path = '../../pallets/common' } pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' } -pallet-evm-transaction-payment = { default-features = false, path = '../../pallets/evm-transaction-payment' } +pallet-evm-transaction-payment = { default-features = false, path = '../../pallets/evm-transaction-payment' } up-data-structs = { default-features = false, path = '../../primitives/data-structs', features = [ 'serde1', ] } @@ -50,5 +50,7 @@ std = [ "pallet-evm-coder-substrate/std", "pallet-evm/std", "up-sponsorship/std", + "pallet-common/std", ] try-runtime = ["frame-support/try-runtime"] +stubgen = ["evm-coder/stubgen", "pallet-common/stubgen"] diff --git a/pallets/evm-contract-helpers/src/eth.rs b/pallets/evm-contract-helpers/src/eth.rs index 9d41395e42..be3666bd22 100644 --- a/pallets/evm-contract-helpers/src/eth.rs +++ b/pallets/evm-contract-helpers/src/eth.rs @@ -16,10 +16,16 @@ //! Implementation of magic contract +extern crate alloc; use core::marker::PhantomData; use evm_coder::{ - abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*, ToLog, + abi::{AbiWriter, AbiType}, + execution::Result, + generate_stubgen, solidity_interface, + types::*, + ToLog, }; +use pallet_common::eth; use pallet_evm::{ ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure, PrecompileHandle, account::CrossAccountId, @@ -169,12 +175,17 @@ where /// /// @param contractAddress The contract for which a sponsor is requested. /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. - fn sponsor(&self, contract_address: address) -> Result<(address, uint256)> { - let sponsor = - Pallet::::get_sponsor(contract_address).ok_or("Contract has no sponsor")?; - Ok(pallet_common::eth::convert_cross_account_to_tuple::( - &sponsor, - )) + fn sponsor(&self, contract_address: address) -> Result { + Ok(match Pallet::::get_sponsor(contract_address) { + Some(ref value) => eth::OptionCrossAddress { + status: true, + value: eth::CrossAddress::from_sub_cross_account::(value), + }, + None => eth::OptionCrossAddress { + status: false, + value: Default::default(), + }, + }) } /// Check tat contract has confirmed sponsor. @@ -204,14 +215,12 @@ where &mut self, caller: caller, contract_address: address, - // TODO: implement support for enums in evm-coder - mode: uint8, + mode: SponsoringModeT, ) -> Result { self.recorder().consume_sload()?; self.recorder().consume_sstore()?; >::ensure_owner(contract_address, caller).map_err(dispatch_to_evm::)?; - let mode = SponsoringModeT::from_eth(mode).ok_or("unknown mode")?; >::set_sponsoring_mode(contract_address, mode); Ok(()) diff --git a/pallets/evm-contract-helpers/src/lib.rs b/pallets/evm-contract-helpers/src/lib.rs index 7cd363cc19..3e5b80b23a 100644 --- a/pallets/evm-contract-helpers/src/lib.rs +++ b/pallets/evm-contract-helpers/src/lib.rs @@ -19,6 +19,7 @@ #![warn(missing_docs)] use codec::{Decode, Encode, MaxEncodedLen}; +use evm_coder::AbiCoder; pub use pallet::*; pub use eth::*; use scale_info::TypeInfo; @@ -41,12 +42,13 @@ pub mod pallet { #[pallet::config] pub trait Config: - frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config + frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::Config { /// Overarching event type. type RuntimeEvent: IsType<::RuntimeEvent> + From>; /// Address, under which magic contract will be available + #[pallet::constant] type ContractAddress: Get; /// In case of enabled sponsoring, but no sponsoring rate limit set, @@ -172,7 +174,7 @@ pub mod pallet { >; #[pallet::event] - #[pallet::generate_deposit(pub fn deposit_event)] + #[pallet::generate_deposit(fn deposit_event)] pub enum Event { /// Contract sponsor was set. ContractSponsorSet( @@ -350,6 +352,7 @@ pub mod pallet { pub fn sponsoring_mode(contract: H160) -> SponsoringModeT { >::get(contract) .or_else(|| { + #[allow(deprecated)] >::get(contract).then(|| SponsoringModeT::Allowlisted) }) .unwrap_or_default() @@ -362,6 +365,7 @@ pub mod pallet { } else { >::insert(contract, mode); } + #[allow(deprecated)] >::remove(contract) } @@ -404,7 +408,10 @@ pub mod pallet { } /// Available contract sponsoring modes -#[derive(Encode, Decode, PartialEq, TypeInfo, MaxEncodedLen, Default)] +#[derive( + Encode, Decode, Debug, PartialEq, TypeInfo, MaxEncodedLen, Default, AbiCoder, Clone, Copy, +)] +#[repr(u8)] pub enum SponsoringModeT { /// Sponsoring is disabled #[default] @@ -414,21 +421,3 @@ pub enum SponsoringModeT { /// All users will be sponsored Generous, } - -impl SponsoringModeT { - fn from_eth(v: u8) -> Option { - Some(match v { - 0 => Self::Disabled, - 1 => Self::Allowlisted, - 2 => Self::Generous, - _ => return None, - }) - } - fn to_eth(self) -> u8 { - match self { - SponsoringModeT::Disabled => 0, - SponsoringModeT::Allowlisted => 1, - SponsoringModeT::Generous => 2, - } - } -} diff --git a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.raw b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.raw index 23965de275..67e057368e 100644 Binary files a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.raw and b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.raw differ diff --git a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol index 78098a6478..a58704c0d0 100644 --- a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol +++ b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol @@ -96,11 +96,11 @@ contract ContractHelpers is Dummy, ERC165, ContractHelpersEvents { /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x766c4f37, /// or in textual repr: sponsor(address) - function sponsor(address contractAddress) public view returns (Tuple0 memory) { + function sponsor(address contractAddress) public view returns (OptionCrossAddress memory) { require(false, stub_error); contractAddress; dummy; - return Tuple0(0x0000000000000000000000000000000000000000, 0); + return OptionCrossAddress(false, CrossAddress(0x0000000000000000000000000000000000000000, 0)); } /// Check tat contract has confirmed sponsor. @@ -140,7 +140,7 @@ contract ContractHelpers is Dummy, ERC165, ContractHelpersEvents { /// @dev EVM selector for this function is: 0xfde8a560, /// or in textual repr: setSponsoringMode(address,uint8) - function setSponsoringMode(address contractAddress, uint8 mode) public { + function setSponsoringMode(address contractAddress, SponsoringModeT mode) public { require(false, stub_error); contractAddress; mode; @@ -265,8 +265,26 @@ contract ContractHelpers is Dummy, ERC165, ContractHelpersEvents { } } -/// @dev anonymous struct -struct Tuple0 { - address field_0; - uint256 field_1; +/// Available contract sponsoring modes +enum SponsoringModeT { + /// Sponsoring is disabled + Disabled, + /// Only users from allowlist will be sponsored + Allowlisted, + /// All users will be sponsored + Generous +} + +/// Cross account struct +struct CrossAddress { + address eth; + uint256 sub; +} + +/// Ethereum representation of Optional value with CrossAddress. +struct OptionCrossAddress { + /// TODO: field description + bool status; + /// TODO: field description + CrossAddress value; } diff --git a/pallets/evm-migration/Cargo.toml b/pallets/evm-migration/Cargo.toml index cf7a839547..76ee3c6af0 100644 --- a/pallets/evm-migration/Cargo.toml +++ b/pallets/evm-migration/Cargo.toml @@ -8,16 +8,16 @@ edition = "2021" scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } -ethereum = { version = "0.12.0", default-features = false } -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +ethereum = { version = "0.14.0", default-features = false } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } [dependencies.codec] default-features = false diff --git a/pallets/evm-migration/src/lib.rs b/pallets/evm-migration/src/lib.rs index 7b2a332e6f..0fe6f2c3bb 100644 --- a/pallets/evm-migration/src/lib.rs +++ b/pallets/evm-migration/src/lib.rs @@ -73,6 +73,7 @@ pub mod pallet { impl Pallet { /// Start contract migration, inserts contract stub at target address, /// and marks account as pending, allowing to insert storage + #[pallet::call_index(0)] #[pallet::weight(>::begin())] pub fn begin(origin: OriginFor, address: H160) -> DispatchResult { ensure_root(origin)?; @@ -87,6 +88,7 @@ pub mod pallet { /// Insert items into contract storage, this method can be called /// multiple times + #[pallet::call_index(1)] #[pallet::weight(>::set_data(data.len() as u32))] pub fn set_data( origin: OriginFor, @@ -108,6 +110,7 @@ pub mod pallet { /// Finish contract migration, allows it to be called. /// It is not possible to alter contract storage via [`Self::set_data`] /// after this call. + #[pallet::call_index(2)] #[pallet::weight(>::finish(code.len() as u32))] pub fn finish(origin: OriginFor, address: H160, code: Vec) -> DispatchResult { ensure_root(origin)?; @@ -122,6 +125,7 @@ pub mod pallet { } /// Create ethereum events attached to the fake transaction + #[pallet::call_index(3)] #[pallet::weight(>::insert_eth_logs(logs.len() as u32))] pub fn insert_eth_logs(origin: OriginFor, logs: Vec) -> DispatchResult { ensure_root(origin)?; @@ -133,6 +137,7 @@ pub mod pallet { } /// Create substrate events + #[pallet::call_index(4)] #[pallet::weight(>::insert_events(events.len() as u32))] pub fn insert_events(origin: OriginFor, events: Vec>) -> DispatchResult { ensure_root(origin)?; diff --git a/pallets/evm-transaction-payment/Cargo.toml b/pallets/evm-transaction-payment/Cargo.toml index 7f7bae15ce..57806ad878 100644 --- a/pallets/evm-transaction-payment/Cargo.toml +++ b/pallets/evm-transaction-payment/Cargo.toml @@ -8,17 +8,17 @@ edition = "2021" scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30" } -fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.36" } +fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } [dependencies.codec] default-features = false diff --git a/pallets/evm-transaction-payment/src/lib.rs b/pallets/evm-transaction-payment/src/lib.rs index 5aca441ba2..6bf0976fab 100644 --- a/pallets/evm-transaction-payment/src/lib.rs +++ b/pallets/evm-transaction-payment/src/lib.rs @@ -44,7 +44,7 @@ pub mod pallet { } #[pallet::config] - pub trait Config: frame_system::Config + pallet_evm::account::Config { + pub trait Config: frame_system::Config + pallet_evm::Config { /// Loosly-coupled handlers for evm call sponsoring type EvmSponsorshipHandler: SponsorshipHandler; } diff --git a/pallets/foreign-assets/Cargo.toml b/pallets/foreign-assets/Cargo.toml index a7362bc5d3..13254536cf 100644 --- a/pallets/foreign-assets/Cargo.toml +++ b/pallets/foreign-assets/Cargo.toml @@ -1,5 +1,3 @@ -cargo-features = ["workspace-inheritance"] - [package] name = "pallet-foreign-assets" version = "0.1.0" @@ -13,27 +11,27 @@ scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30", default-features = false } -sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30", default-features = false } -frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30", default-features = false } -frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36", default-features = false } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36", default-features = false } up-data-structs = { default-features = false, path = '../../primitives/data-structs' } -pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30", default-features = false } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36", default-features = false } pallet-common = { default-features = false, path = '../common' } pallet-fungible = { default-features = false, path = '../fungible' } -xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.30", default-features = false } -xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.30", default-features = false } -xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.30", default-features = false } +xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.36", default-features = false } +xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.36", default-features = false } +xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.36", default-features = false } orml-tokens.workspace = true -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } [dev-dependencies] serde_json = "1.0.68" hex = { version = "0.4" } -sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } [features] default = ["std"] diff --git a/pallets/foreign-assets/src/impl_fungibles.rs b/pallets/foreign-assets/src/impl_fungibles.rs index 6980ff1f61..ddfa526ce3 100644 --- a/pallets/foreign-assets/src/impl_fungibles.rs +++ b/pallets/foreign-assets/src/impl_fungibles.rs @@ -258,6 +258,13 @@ where }, } } + + fn asset_exists(asset: AssetIds) -> bool { + match asset { + AssetIds::NativeAssetId(_) => true, + AssetIds::ForeignAssetId(fid) => >::contains_key(fid), + } + } } impl fungibles::Mutate<::AccountId> for Pallet diff --git a/pallets/foreign-assets/src/lib.rs b/pallets/foreign-assets/src/lib.rs index 8021267186..4640effa52 100644 --- a/pallets/foreign-assets/src/lib.rs +++ b/pallets/foreign-assets/src/lib.rs @@ -161,9 +161,7 @@ impl AssetIdMapping Option { log::trace!(target: "fassets::get_currency_id", "call"); - Some(AssetIds::ForeignAssetId( - Pallet::::location_to_currency_ids(multi_location).unwrap_or(0), - )) + Pallet::::location_to_currency_ids(multi_location).map(|id| AssetIds::ForeignAssetId(id)) } } @@ -283,6 +281,7 @@ pub mod module { #[pallet::call] impl Pallet { + #[pallet::call_index(0)] #[pallet::weight(::WeightInfo::register_foreign_asset())] pub fn register_foreign_asset( origin: OriginFor, @@ -323,6 +322,7 @@ pub mod module { Ok(()) } + #[pallet::call_index(1)] #[pallet::weight(::WeightInfo::update_foreign_asset())] pub fn update_foreign_asset( origin: OriginFor, diff --git a/pallets/fungible/CHANGELOG.md b/pallets/fungible/CHANGELOG.md index ef52e80d02..502b4f1855 100644 --- a/pallets/fungible/CHANGELOG.md +++ b/pallets/fungible/CHANGELOG.md @@ -2,19 +2,48 @@ All notable changes to this project will be documented in this file. + + +## [0.1.9] - 2022-12-01 + +### Added + +- The functions `mintCross` to `ERC20UniqueExtensions` interface. + +## [0.1.8] - 2022-11-18 + +### Added + +- The function `description` to `ERC20UniqueExtensions` interface. + +## [0.1.7] - 2022-11-14 + +### Changed + +- Added `transfer_cross` in eth functions. + +### Changed + +- Use named structure `EthCrossAccount` in eth functions. + +## [0.1.6] - 2022-11-02 + +### Changed + +- Use named structure `EthCrossAccount` in eth functions. ## [0.1.5] - 2022-08-29 ### Added - - Implementation of `mint` and `mint_bulk` methods for ERC20 API. +- Implementation of `mint` and `mint_bulk` methods for ERC20 API. ## [v0.1.4] - 2022-08-24 ### Change - - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`. - +- Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`. + ## [v0.1.3] 2022-08-16 ### Other changes @@ -38,11 +67,11 @@ Upstream-Change: https://github.com/paritytech/substrate/pull/11490 ### Fixed - - Issue with ItemCreated event containing total supply of tokens instead minted amount +- Issue with ItemCreated event containing total supply of tokens instead minted amount ## [0.1.1] - 2022-07-14 ### Added - - Implementation of RPC method `token_owners` returning 10 owners in no particular order. - This was an internal request to improve the web interface and support fractionalization event. +- Implementation of RPC method `token_owners` returning 10 owners in no particular order. + This was an internal request to improve the web interface and support fractionalization event. diff --git a/pallets/fungible/Cargo.toml b/pallets/fungible/Cargo.toml index 8669d9e75a..23c8e0d97e 100644 --- a/pallets/fungible/Cargo.toml +++ b/pallets/fungible/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-fungible" -version = "0.1.5" +version = "0.1.9" license = "GPLv3" edition = "2021" @@ -11,19 +11,19 @@ package = 'parity-scale-codec' version = '3.1.2' [dependencies] -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } pallet-common = { default-features = false, path = '../common' } pallet-structure = { default-features = false, path = '../structure' } up-data-structs = { default-features = false, path = '../../primitives/data-structs' } evm-coder = { default-features = false, path = '../../crates/evm-coder' } pallet-evm-coder-substrate = { default-features = false, path = '../evm-coder-substrate' } -ethereum = { version = "0.12.0", default-features = false } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +ethereum = { version = "0.14.0", default-features = false } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } @@ -46,3 +46,4 @@ std = [ ] runtime-benchmarks = ['frame-benchmarking', 'pallet-common/runtime-benchmarks'] try-runtime = ["frame-support/try-runtime"] +stubgen = ["evm-coder/stubgen", "pallet-common/stubgen"] diff --git a/pallets/fungible/src/common.rs b/pallets/fungible/src/common.rs index 7ffdeb693b..47fec7b196 100644 --- a/pallets/fungible/src/common.rs +++ b/pallets/fungible/src/common.rs @@ -18,7 +18,10 @@ use core::marker::PhantomData; use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get}; use up_data_structs::{TokenId, CollectionId, CreateItemExData, budget::Budget, CreateItemData}; -use pallet_common::{CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight}; +use pallet_common::{ + CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight, + weights::WeightInfo as _, +}; use pallet_structure::Error as StructureError; use sp_runtime::ArithmeticError; use sp_std::{vec::Vec, vec}; @@ -53,14 +56,12 @@ impl CommonWeightInfo for CommonWeights { >::burn_item() } - fn set_collection_properties(_amount: u32) -> Weight { - // Error - Weight::zero() + fn set_collection_properties(amount: u32) -> Weight { + >::set_collection_properties(amount) } - fn delete_collection_properties(_amount: u32) -> Weight { - // Error - Weight::zero() + fn delete_collection_properties(amount: u32) -> Weight { + >::delete_collection_properties(amount) } fn set_token_properties(_amount: u32) -> Weight { @@ -108,7 +109,11 @@ impl CommonWeightInfo for CommonWeights { Weight::zero() } - fn repair_item() -> Weight { + fn set_allowance_for_all() -> Weight { + Weight::zero() + } + + fn force_repair_item() -> Weight { Weight::zero() } } @@ -290,18 +295,28 @@ impl CommonCollectionOperations for FungibleHandle { fn set_collection_properties( &self, - _sender: T::CrossAccountId, - _property: Vec, + sender: T::CrossAccountId, + properties: Vec, ) -> DispatchResultWithPostInfo { - fail!(>::SettingPropertiesNotAllowed) + let weight = >::set_collection_properties(properties.len() as u32); + + with_weight( + >::set_collection_properties(self, &sender, properties), + weight, + ) } fn delete_collection_properties( &self, - _sender: &T::CrossAccountId, - _property_keys: Vec, + sender: &T::CrossAccountId, + property_keys: Vec, ) -> DispatchResultWithPostInfo { - fail!(>::SettingPropertiesNotAllowed) + let weight = >::delete_collection_properties(property_keys.len() as u32); + + with_weight( + >::delete_collection_properties(self, sender, property_keys), + weight, + ) } fn set_token_properties( @@ -429,6 +444,19 @@ impl CommonCollectionOperations for FungibleHandle { >::try_get(self.id).ok() } + fn set_allowance_for_all( + &self, + _owner: T::CrossAccountId, + _operator: T::CrossAccountId, + _approve: bool, + ) -> DispatchResultWithPostInfo { + fail!(>::SettingAllowanceForAllNotAllowed) + } + + fn allowance_for_all(&self, _owner: T::CrossAccountId, _operator: T::CrossAccountId) -> bool { + false + } + /// Repairs a possibly broken item. fn repair_item(&self, _token: TokenId) -> DispatchResultWithPostInfo { fail!(>::FungibleTokensAreAlwaysValid) diff --git a/pallets/fungible/src/erc.rs b/pallets/fungible/src/erc.rs index 088f841b34..6109ca4fe0 100644 --- a/pallets/fungible/src/erc.rs +++ b/pallets/fungible/src/erc.rs @@ -16,16 +16,23 @@ //! ERC-20 standart support implementation. +extern crate alloc; use core::char::{REPLACEMENT_CHARACTER, decode_utf16}; use core::convert::TryInto; -use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight}; +use evm_coder::{ + abi::AbiType, ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, + weight, +}; use up_data_structs::CollectionMode; -use pallet_common::erc::{CommonEvmHandler, PrecompileResult}; +use pallet_common::{ + CollectionHandle, + erc::{CommonEvmHandler, PrecompileResult, CollectionCall}, +}; use sp_std::vec::Vec; use pallet_evm::{account::CrossAccountId, PrecompileHandle}; use pallet_evm_coder_substrate::{call, dispatch_to_evm}; use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _}; -use pallet_common::{CollectionHandle, erc::CollectionCall}; +use sp_core::Get; use crate::{ Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply, @@ -90,6 +97,7 @@ impl FungibleHandle { >::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?; Ok(true) } + #[weight(>::transfer_from())] fn transfer_from( &mut self, @@ -127,6 +135,11 @@ impl FungibleHandle { Ok(>::get((self.id, owner, spender)).into()) } + + /// @notice Returns collection helper contract address + fn collection_helper_address(&self) -> Result

{ + Ok(T::ContractAddress::get()) + } } #[solidity_interface(name = ERC20Mintable)] @@ -149,12 +162,57 @@ impl FungibleHandle { } #[solidity_interface(name = ERC20UniqueExtensions)] -impl FungibleHandle { +impl FungibleHandle +where + T::AccountId: From<[u8; 32]>, +{ + /// @notice A description for the collection. + fn description(&self) -> Result { + Ok(decode_utf16(self.description.iter().copied()) + .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) + .collect::()) + } + + #[weight(>::create_item())] + fn mint_cross( + &mut self, + caller: caller, + to: pallet_common::eth::CrossAddress, + amount: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let to = to.into_sub_cross_account::()?; + let amount = amount.try_into().map_err(|_| "amount overflow")?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + >::create_item(&self, &caller, (to, amount), &budget) + .map_err(dispatch_to_evm::)?; + Ok(true) + } + + #[weight(>::approve())] + fn approve_cross( + &mut self, + caller: caller, + spender: pallet_common::eth::CrossAddress, + amount: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let spender = spender.into_sub_cross_account::()?; + let amount = amount.try_into().map_err(|_| "amount overflow")?; + + >::set_allowance(self, &caller, &spender, amount) + .map_err(dispatch_to_evm::)?; + Ok(true) + } + /// Burn tokens from account /// @dev Function that burns an `amount` of the tokens of a given account, /// deducting from the sender's allowance for said account. /// @param from The account whose tokens will be burnt. /// @param amount The amount that will be burnt. + #[solidity(hide)] #[weight(>::burn_from())] fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result { let caller = T::CrossAccountId::from_eth(caller); @@ -169,6 +227,30 @@ impl FungibleHandle { Ok(true) } + /// Burn tokens from account + /// @dev Function that burns an `amount` of the tokens of a given account, + /// deducting from the sender's allowance for said account. + /// @param from The account whose tokens will be burnt. + /// @param amount The amount that will be burnt. + #[weight(>::burn_from())] + fn burn_from_cross( + &mut self, + caller: caller, + from: pallet_common::eth::CrossAddress, + amount: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let from = from.into_sub_cross_account::()?; + let amount = amount.try_into().map_err(|_| "amount overflow")?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + >::burn_from(self, &caller, &from, amount, &budget) + .map_err(dispatch_to_evm::)?; + Ok(true) + } + /// Mint tokens for multiple accounts. /// @param amounts array of pairs of account address and amount #[weight(>::create_multiple_items_ex(amounts.len() as u32))] @@ -191,6 +273,45 @@ impl FungibleHandle { .map_err(dispatch_to_evm::)?; Ok(true) } + + #[weight(>::transfer())] + fn transfer_cross( + &mut self, + caller: caller, + to: pallet_common::eth::CrossAddress, + amount: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let to = to.into_sub_cross_account::()?; + let amount = amount.try_into().map_err(|_| "amount overflow")?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + >::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?; + Ok(true) + } + + #[weight(>::transfer_from())] + fn transfer_from_cross( + &mut self, + caller: caller, + from: pallet_common::eth::CrossAddress, + to: pallet_common::eth::CrossAddress, + amount: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let from = from.into_sub_cross_account::()?; + let to = to.into_sub_cross_account::()?; + let amount = amount.try_into().map_err(|_| "amount overflow")?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + >::transfer_from(self, &caller, &from, &to, amount, &budget) + .map_err(dispatch_to_evm::)?; + Ok(true) + } } #[solidity_interface( diff --git a/pallets/fungible/src/lib.rs b/pallets/fungible/src/lib.rs index da4df9bd74..e8eecb68db 100644 --- a/pallets/fungible/src/lib.rs +++ b/pallets/fungible/src/lib.rs @@ -80,11 +80,11 @@ use core::ops::Deref; use evm_coder::ToLog; -use frame_support::{ensure}; +use frame_support::ensure; use pallet_evm::account::CrossAccountId; use up_data_structs::{ AccessMode, CollectionId, CollectionFlags, TokenId, CreateCollectionData, - mapping::TokenAddressMapping, budget::Budget, + mapping::TokenAddressMapping, budget::Budget, PropertyKey, Property, }; use pallet_common::{ Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, @@ -106,7 +106,7 @@ pub mod common; pub mod erc; pub mod weights; -pub type CreateItemData = (::CrossAccountId, u128); +pub type CreateItemData = (::CrossAccountId, u128); pub(crate) type SelfWeightOf = ::WeightInfo; #[frame_support::pallet] @@ -127,6 +127,8 @@ pub mod pallet { FungibleDisallowsNesting, /// Setting item properties is not allowed. SettingPropertiesNotAllowed, + /// Setting allowance for all is not allowed. + SettingAllowanceForAllNotAllowed, /// Only a fungible collection could be possibly broken; any fungible token is valid. FungibleTokensAreAlwaysValid, } @@ -258,7 +260,25 @@ impl Pallet { Ok(()) } - ///Checks if collection has tokens. Return `true` if it has. + /// Add properties to the collection. + pub fn set_collection_properties( + collection: &FungibleHandle, + sender: &T::CrossAccountId, + properties: Vec, + ) -> DispatchResult { + >::set_collection_properties(collection, sender, properties) + } + + /// Delete properties of the collection, associated with the provided keys. + pub fn delete_collection_properties( + collection: &FungibleHandle, + sender: &T::CrossAccountId, + property_keys: Vec, + ) -> DispatchResult { + >::delete_collection_properties(collection, sender, property_keys) + } + + /// Checks if collection has tokens. Return `true` if it has. fn collection_has_tokens(collection_id: CollectionId) -> bool { >::get(collection_id) != 0 } diff --git a/pallets/fungible/src/stubs/UniqueFungible.raw b/pallets/fungible/src/stubs/UniqueFungible.raw index 6a25cedd15..66f6af732f 100644 Binary files a/pallets/fungible/src/stubs/UniqueFungible.raw and b/pallets/fungible/src/stubs/UniqueFungible.raw differ diff --git a/pallets/fungible/src/stubs/UniqueFungible.sol b/pallets/fungible/src/stubs/UniqueFungible.sol index 91d55ee0e4..89ad9f7316 100644 --- a/pallets/fungible/src/stubs/UniqueFungible.sol +++ b/pallets/fungible/src/stubs/UniqueFungible.sol @@ -18,29 +18,51 @@ contract ERC165 is Dummy { } /// @title A contract that allows you to work with collections. -/// @dev the ERC-165 identifier for this interface is 0x62e22290 +/// @dev the ERC-165 identifier for this interface is 0x2a14cfd1 contract Collection is Dummy, ERC165 { - /// Set collection property. + // /// Set collection property. + // /// + // /// @param key Property key. + // /// @param value Propery value. + // /// @dev EVM selector for this function is: 0x2f073f66, + // /// or in textual repr: setCollectionProperty(string,bytes) + // function setCollectionProperty(string memory key, bytes memory value) public { + // require(false, stub_error); + // key; + // value; + // dummy = 0; + // } + + /// Set collection properties. /// - /// @param key Property key. - /// @param value Propery value. - /// @dev EVM selector for this function is: 0x2f073f66, - /// or in textual repr: setCollectionProperty(string,bytes) - function setCollectionProperty(string memory key, bytes memory value) public { + /// @param properties Vector of properties key/value pair. + /// @dev EVM selector for this function is: 0x50b26b2a, + /// or in textual repr: setCollectionProperties((string,bytes)[]) + function setCollectionProperties(Property[] memory properties) public { require(false, stub_error); - key; - value; + properties; dummy = 0; } - /// Delete collection property. + // /// Delete collection property. + // /// + // /// @param key Property key. + // /// @dev EVM selector for this function is: 0x7b7debce, + // /// or in textual repr: deleteCollectionProperty(string) + // function deleteCollectionProperty(string memory key) public { + // require(false, stub_error); + // key; + // dummy = 0; + // } + + /// Delete collection properties. /// - /// @param key Property key. - /// @dev EVM selector for this function is: 0x7b7debce, - /// or in textual repr: deleteCollectionProperty(string) - function deleteCollectionProperty(string memory key) public { + /// @param keys Properties keys. + /// @dev EVM selector for this function is: 0xee206ee3, + /// or in textual repr: deleteCollectionProperties(string[]) + function deleteCollectionProperties(string[] memory keys) public { require(false, stub_error); - key; + keys; dummy = 0; } @@ -59,14 +81,40 @@ contract Collection is Dummy, ERC165 { return hex""; } + /// Get collection properties. + /// + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0x285fb8e6, + /// or in textual repr: collectionProperties(string[]) + function collectionProperties(string[] memory keys) public view returns (Property[] memory) { + require(false, stub_error); + keys; + dummy; + return new Property[](0); + } + + // /// Set the sponsor of the collection. + // /// + // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. + // /// + // /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. + // /// @dev EVM selector for this function is: 0x7623402e, + // /// or in textual repr: setCollectionSponsor(address) + // function setCollectionSponsor(address sponsor) public { + // require(false, stub_error); + // sponsor; + // dummy = 0; + // } + /// Set the sponsor of the collection. /// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. /// - /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. - /// @dev EVM selector for this function is: 0x7623402e, - /// or in textual repr: setCollectionSponsor(address) - function setCollectionSponsor(address sponsor) public { + /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract. + /// @dev EVM selector for this function is: 0x84a1d5a8, + /// or in textual repr: setCollectionSponsorCross((address,uint256)) + function setCollectionSponsorCross(CrossAddress memory sponsor) public { require(false, stub_error); sponsor; dummy = 0; @@ -104,44 +152,31 @@ contract Collection is Dummy, ERC165 { /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x6ec0a9f1, /// or in textual repr: collectionSponsor() - function collectionSponsor() public view returns (Tuple6 memory) { + function collectionSponsor() public view returns (CrossAddress memory) { require(false, stub_error); dummy; - return Tuple6(0x0000000000000000000000000000000000000000, 0); + return CrossAddress(0x0000000000000000000000000000000000000000, 0); } - /// Set limits for the collection. - /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "accountTokenOwnershipLimit", - /// "sponsoredDataSize", - /// "sponsoredDataRateLimit", - /// "tokenLimit", - /// "sponsorTransferTimeout", - /// "sponsorApproveTimeout" - /// @param value Value of the limit. - /// @dev EVM selector for this function is: 0x6a3841db, - /// or in textual repr: setCollectionLimit(string,uint32) - function setCollectionLimit(string memory limit, uint32 value) public { + /// Get current collection limits. + /// + /// @return Array of collection limits + /// @dev EVM selector for this function is: 0xf63bc572, + /// or in textual repr: collectionLimits() + function collectionLimits() public view returns (CollectionLimit[] memory) { require(false, stub_error); - limit; - value; - dummy = 0; + dummy; + return new CollectionLimit[](0); } /// Set limits for the collection. /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "ownerCanTransfer", - /// "ownerCanDestroy", - /// "transfersEnabled" - /// @param value Value of the limit. - /// @dev EVM selector for this function is: 0x993b7fba, - /// or in textual repr: setCollectionLimit(string,bool) - function setCollectionLimit(string memory limit, bool value) public { + /// @param limit Some limit. + /// @dev EVM selector for this function is: 0x2316ee74, + /// or in textual repr: setCollectionLimit((uint8,(bool,uint256))) + function setCollectionLimit(CollectionLimit memory limit) public { require(false, stub_error); limit; - value; dummy = 0; } @@ -155,26 +190,46 @@ contract Collection is Dummy, ERC165 { } /// Add collection admin. - /// @param newAdmin Address of the added administrator. - /// @dev EVM selector for this function is: 0x92e462c7, - /// or in textual repr: addCollectionAdmin(address) - function addCollectionAdmin(address newAdmin) public { + /// @param newAdmin Cross account administrator address. + /// @dev EVM selector for this function is: 0x859aa7d6, + /// or in textual repr: addCollectionAdminCross((address,uint256)) + function addCollectionAdminCross(CrossAddress memory newAdmin) public { require(false, stub_error); newAdmin; dummy = 0; } /// Remove collection admin. - /// - /// @param admin Address of the removed administrator. - /// @dev EVM selector for this function is: 0xfafd7b42, - /// or in textual repr: removeCollectionAdmin(address) - function removeCollectionAdmin(address admin) public { + /// @param admin Cross account administrator address. + /// @dev EVM selector for this function is: 0x6c0cd173, + /// or in textual repr: removeCollectionAdminCross((address,uint256)) + function removeCollectionAdminCross(CrossAddress memory admin) public { require(false, stub_error); admin; dummy = 0; } + // /// Add collection admin. + // /// @param newAdmin Address of the added administrator. + // /// @dev EVM selector for this function is: 0x92e462c7, + // /// or in textual repr: addCollectionAdmin(address) + // function addCollectionAdmin(address newAdmin) public { + // require(false, stub_error); + // newAdmin; + // dummy = 0; + // } + + // /// Remove collection admin. + // /// + // /// @param admin Address of the removed administrator. + // /// @dev EVM selector for this function is: 0xfafd7b42, + // /// or in textual repr: removeCollectionAdmin(address) + // function removeCollectionAdmin(address admin) public { + // require(false, stub_error); + // admin; + // dummy = 0; + // } + /// Toggle accessibility of collection nesting. /// /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled' @@ -199,6 +254,24 @@ contract Collection is Dummy, ERC165 { dummy = 0; } + /// Returns nesting for a collection + /// @dev EVM selector for this function is: 0x22d25bfe, + /// or in textual repr: collectionNestingRestrictedCollectionIds() + function collectionNestingRestrictedCollectionIds() public view returns (CollectionNesting memory) { + require(false, stub_error); + dummy; + return CollectionNesting(false, new uint256[](0)); + } + + /// Returns permissions for a collection + /// @dev EVM selector for this function is: 0x5b2eaf4b, + /// or in textual repr: collectionNestingPermissions() + function collectionNestingPermissions() public view returns (CollectionNestingPermission[] memory) { + require(false, stub_error); + dummy; + return new CollectionNestingPermission[](0); + } + /// Set the collection access method. /// @param mode Access mode /// 0 for Normal @@ -214,32 +287,54 @@ contract Collection is Dummy, ERC165 { /// Checks that user allowed to operate with collection. /// /// @param user User address to check. - /// @dev EVM selector for this function is: 0xd63a8e11, - /// or in textual repr: allowed(address) - function allowed(address user) public view returns (bool) { + /// @dev EVM selector for this function is: 0x91b6df49, + /// or in textual repr: allowlistedCross((address,uint256)) + function allowlistedCross(CrossAddress memory user) public view returns (bool) { require(false, stub_error); user; dummy; return false; } - /// Add the user to the allowed list. + // /// Add the user to the allowed list. + // /// + // /// @param user Address of a trusted user. + // /// @dev EVM selector for this function is: 0x67844fe6, + // /// or in textual repr: addToCollectionAllowList(address) + // function addToCollectionAllowList(address user) public { + // require(false, stub_error); + // user; + // dummy = 0; + // } + + /// Add user to allowed list. /// - /// @param user Address of a trusted user. - /// @dev EVM selector for this function is: 0x67844fe6, - /// or in textual repr: addToCollectionAllowList(address) - function addToCollectionAllowList(address user) public { + /// @param user User cross account address. + /// @dev EVM selector for this function is: 0xa0184a3a, + /// or in textual repr: addToCollectionAllowListCross((address,uint256)) + function addToCollectionAllowListCross(CrossAddress memory user) public { require(false, stub_error); user; dummy = 0; } - /// Remove the user from the allowed list. + // /// Remove the user from the allowed list. + // /// + // /// @param user Address of a removed user. + // /// @dev EVM selector for this function is: 0x85c51acb, + // /// or in textual repr: removeFromCollectionAllowList(address) + // function removeFromCollectionAllowList(address user) public { + // require(false, stub_error); + // user; + // dummy = 0; + // } + + /// Remove user from allowed list. /// - /// @param user Address of a removed user. - /// @dev EVM selector for this function is: 0x85c51acb, - /// or in textual repr: removeFromCollectionAllowList(address) - function removeFromCollectionAllowList(address user) public { + /// @param user User cross account address. + /// @dev EVM selector for this function is: 0x09ba452a, + /// or in textual repr: removeFromCollectionAllowListCross((address,uint256)) + function removeFromCollectionAllowListCross(CrossAddress memory user) public { require(false, stub_error); user; dummy = 0; @@ -256,13 +351,26 @@ contract Collection is Dummy, ERC165 { dummy = 0; } + // /// Check that account is the owner or admin of the collection + // /// + // /// @param user account to verify + // /// @return "true" if account is the owner or admin + // /// @dev EVM selector for this function is: 0x9811b0c7, + // /// or in textual repr: isOwnerOrAdmin(address) + // function isOwnerOrAdmin(address user) public view returns (bool) { + // require(false, stub_error); + // user; + // dummy; + // return false; + // } + /// Check that account is the owner or admin of the collection /// - /// @param user account to verify + /// @param user User cross account to verify /// @return "true" if account is the owner or admin - /// @dev EVM selector for this function is: 0x9811b0c7, - /// or in textual repr: isOwnerOrAdmin(address) - function isOwnerOrAdmin(address user) public view returns (bool) { + /// @dev EVM selector for this function is: 0x3e75a905, + /// or in textual repr: isOwnerOrAdminCross((address,uint256)) + function isOwnerOrAdminCross(CrossAddress memory user) public view returns (bool) { require(false, stub_error); user; dummy; @@ -286,35 +394,169 @@ contract Collection is Dummy, ERC165 { /// If address is canonical then substrate mirror is zero and vice versa. /// @dev EVM selector for this function is: 0xdf727d3b, /// or in textual repr: collectionOwner() - function collectionOwner() public view returns (Tuple6 memory) { + function collectionOwner() public view returns (CrossAddress memory) { require(false, stub_error); dummy; - return Tuple6(0x0000000000000000000000000000000000000000, 0); + return CrossAddress(0x0000000000000000000000000000000000000000, 0); + } + + // /// Changes collection owner to another account + // /// + // /// @dev Owner can be changed only by current owner + // /// @param newOwner new owner account + // /// @dev EVM selector for this function is: 0x4f53e226, + // /// or in textual repr: changeCollectionOwner(address) + // function changeCollectionOwner(address newOwner) public { + // require(false, stub_error); + // newOwner; + // dummy = 0; + // } + + /// Get collection administrators + /// + /// @return Vector of tuples with admins address and his substrate mirror. + /// If address is canonical then substrate mirror is zero and vice versa. + /// @dev EVM selector for this function is: 0x5813216b, + /// or in textual repr: collectionAdmins() + function collectionAdmins() public view returns (CrossAddress[] memory) { + require(false, stub_error); + dummy; + return new CrossAddress[](0); } /// Changes collection owner to another account /// /// @dev Owner can be changed only by current owner - /// @param newOwner new owner account - /// @dev EVM selector for this function is: 0x4f53e226, - /// or in textual repr: changeCollectionOwner(address) - function changeCollectionOwner(address newOwner) public { + /// @param newOwner new owner cross account + /// @dev EVM selector for this function is: 0x6496c497, + /// or in textual repr: changeCollectionOwnerCross((address,uint256)) + function changeCollectionOwnerCross(CrossAddress memory newOwner) public { require(false, stub_error); newOwner; dummy = 0; } } -/// @dev the ERC-165 identifier for this interface is 0x63034ac5 +/// Cross account struct +struct CrossAddress { + address eth; + uint256 sub; +} + +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field. +struct CollectionNestingPermission { + CollectionPermissionField field; + bool value; +} + +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration. +enum CollectionPermissionField { + /// Owner of token can nest tokens under it. + TokenOwner, + /// Admin of token collection can nest tokens under token. + CollectionAdmin +} + +/// Nested collections. +struct CollectionNesting { + bool token_owner; + uint256[] ids; +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM. +struct CollectionLimit { + CollectionLimitField field; + OptionUint value; +} + +/// Ethereum representation of Optional value with uint256. +struct OptionUint { + bool status; + uint256 value; +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM. +enum CollectionLimitField { + /// How many tokens can a user have on one account. + AccountTokenOwnership, + /// How many bytes of data are available for sponsorship. + SponsoredDataSize, + /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`] + SponsoredDataRateLimit, + /// How many tokens can be mined into this collection. + TokenLimit, + /// Timeouts for transfer sponsoring. + SponsorTransferTimeout, + /// Timeout for sponsoring an approval in passed blocks. + SponsorApproveTimeout, + /// Whether the collection owner of the collection can send tokens (which belong to other users). + OwnerCanTransfer, + /// Can the collection owner burn other people's tokens. + OwnerCanDestroy, + /// Is it possible to send tokens from this collection between users. + TransferEnabled +} + +/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue). +struct Property { + string key; + bytes value; +} + +/// @dev the ERC-165 identifier for this interface is 0x7dee5997 contract ERC20UniqueExtensions is Dummy, ERC165 { + /// @notice A description for the collection. + /// @dev EVM selector for this function is: 0x7284e416, + /// or in textual repr: description() + function description() public view returns (string memory) { + require(false, stub_error); + dummy; + return ""; + } + + /// @dev EVM selector for this function is: 0x269e6158, + /// or in textual repr: mintCross((address,uint256),uint256) + function mintCross(CrossAddress memory to, uint256 amount) public returns (bool) { + require(false, stub_error); + to; + amount; + dummy = 0; + return false; + } + + /// @dev EVM selector for this function is: 0x0ecd0ab0, + /// or in textual repr: approveCross((address,uint256),uint256) + function approveCross(CrossAddress memory spender, uint256 amount) public returns (bool) { + require(false, stub_error); + spender; + amount; + dummy = 0; + return false; + } + + // /// Burn tokens from account + // /// @dev Function that burns an `amount` of the tokens of a given account, + // /// deducting from the sender's allowance for said account. + // /// @param from The account whose tokens will be burnt. + // /// @param amount The amount that will be burnt. + // /// @dev EVM selector for this function is: 0x79cc6790, + // /// or in textual repr: burnFrom(address,uint256) + // function burnFrom(address from, uint256 amount) public returns (bool) { + // require(false, stub_error); + // from; + // amount; + // dummy = 0; + // return false; + // } + /// Burn tokens from account /// @dev Function that burns an `amount` of the tokens of a given account, /// deducting from the sender's allowance for said account. /// @param from The account whose tokens will be burnt. /// @param amount The amount that will be burnt. - /// @dev EVM selector for this function is: 0x79cc6790, - /// or in textual repr: burnFrom(address,uint256) - function burnFrom(address from, uint256 amount) public returns (bool) { + /// @dev EVM selector for this function is: 0xbb2f5a58, + /// or in textual repr: burnFromCross((address,uint256),uint256) + function burnFromCross(CrossAddress memory from, uint256 amount) public returns (bool) { require(false, stub_error); from; amount; @@ -326,16 +568,41 @@ contract ERC20UniqueExtensions is Dummy, ERC165 { /// @param amounts array of pairs of account address and amount /// @dev EVM selector for this function is: 0x1acf2d55, /// or in textual repr: mintBulk((address,uint256)[]) - function mintBulk(Tuple6[] memory amounts) public returns (bool) { + function mintBulk(Tuple9[] memory amounts) public returns (bool) { require(false, stub_error); amounts; dummy = 0; return false; } + + /// @dev EVM selector for this function is: 0x2ada85ff, + /// or in textual repr: transferCross((address,uint256),uint256) + function transferCross(CrossAddress memory to, uint256 amount) public returns (bool) { + require(false, stub_error); + to; + amount; + dummy = 0; + return false; + } + + /// @dev EVM selector for this function is: 0xd5cf430b, + /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256) + function transferFromCross( + CrossAddress memory from, + CrossAddress memory to, + uint256 amount + ) public returns (bool) { + require(false, stub_error); + from; + to; + amount; + dummy = 0; + return false; + } } /// @dev anonymous struct -struct Tuple6 { +struct Tuple9 { address field_0; uint256 field_1; } @@ -362,7 +629,7 @@ contract ERC20Events { event Approval(address indexed owner, address indexed spender, uint256 value); } -/// @dev the ERC-165 identifier for this interface is 0x942e8b22 +/// @dev the ERC-165 identifier for this interface is 0x8cb847c4 contract ERC20 is Dummy, ERC165, ERC20Events { /// @dev EVM selector for this function is: 0x06fdde03, /// or in textual repr: name() @@ -449,6 +716,15 @@ contract ERC20 is Dummy, ERC165, ERC20Events { dummy; return 0; } + + /// @notice Returns collection helper contract address + /// @dev EVM selector for this function is: 0x1896cce6, + /// or in textual repr: collectionHelperAddress() + function collectionHelperAddress() public view returns (address) { + require(false, stub_error); + dummy; + return 0x0000000000000000000000000000000000000000; + } } contract UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {} diff --git a/pallets/inflation/Cargo.toml b/pallets/inflation/Cargo.toml index b4d4e6dc56..bfe107dc36 100644 --- a/pallets/inflation/Cargo.toml +++ b/pallets/inflation/Cargo.toml @@ -44,37 +44,37 @@ version = '3.1.2' default-features = false optional = true git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-support] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-system] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-balances] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-timestamp] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-randomness-collective-flip] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-std] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.serde] default-features = false @@ -84,17 +84,17 @@ version = '1.0.130' [dependencies.sp-runtime] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-core] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-io] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies] scale-info = { version = "2.0.1", default-features = false, features = [ diff --git a/pallets/inflation/src/lib.rs b/pallets/inflation/src/lib.rs index 1e2f984a38..df35262366 100644 --- a/pallets/inflation/src/lib.rs +++ b/pallets/inflation/src/lib.rs @@ -163,6 +163,7 @@ pub mod pallet { /// # Arguments /// /// * inflation_start_relay_block: The relay chain block at which inflation should start + #[pallet::call_index(0)] #[pallet::weight(0)] pub fn start_inflation( origin: OriginFor, diff --git a/pallets/maintenance/Cargo.toml b/pallets/maintenance/Cargo.toml index 3b19834ca3..96b9eb3163 100644 --- a/pallets/maintenance/Cargo.toml +++ b/pallets/maintenance/Cargo.toml @@ -10,12 +10,16 @@ description = "Unique Maintenance pallet" readme = "README.md" [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.1.1", default-features = false, features = [ + "derive", +] } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } [features] default = ["std"] diff --git a/pallets/maintenance/src/lib.rs b/pallets/maintenance/src/lib.rs index 6d08840d64..24a7565acf 100644 --- a/pallets/maintenance/src/lib.rs +++ b/pallets/maintenance/src/lib.rs @@ -55,6 +55,7 @@ pub mod pallet { #[pallet::call] impl Pallet { + #[pallet::call_index(0)] #[pallet::weight(::WeightInfo::enable())] pub fn enable(origin: OriginFor) -> DispatchResult { ensure_root(origin)?; @@ -66,6 +67,7 @@ pub mod pallet { Ok(()) } + #[pallet::call_index(1)] #[pallet::weight(::WeightInfo::disable())] pub fn disable(origin: OriginFor) -> DispatchResult { ensure_root(origin)?; diff --git a/pallets/nonfungible/CHANGELOG.md b/pallets/nonfungible/CHANGELOG.md index 90cd277bff..3055de414f 100644 --- a/pallets/nonfungible/CHANGELOG.md +++ b/pallets/nonfungible/CHANGELOG.md @@ -2,12 +2,60 @@ All notable changes to this project will be documented in this file. + + +## [0.1.12] - 2022-12-16 + +### Added + +- The function `tokenPropertyPermissions` and `setTokenPropertyPermissions` to `TokenProperties` interface. + +### Changed + +- Hide `setTokenPropertyPermission` function in `TokenProperties` interface. + +## [0.1.11] - 2022-12-01 + +### Added + +- The functions `mintCross` to `ERC721UniqueExtensions` interface. + +## [0.1.10] - 2022-11-18 + +### Added + +- The functions `description`, `crossOwnerOf`, `tokenProperties` to `ERC721UniqueExtensions` interface. + +## [0.1.9] - 2022-11-14 + +### Changed + +- Added `transfer_cross` in eth functions. + +## [v0.1.8] - 2022-11-11 + +### Changed + +- Added `delete_properties` in eth functions. The `delete_property` function is now deprecated. + +## [v0.1.7] - 2022-11-02 + +### Changed + +- Use named structure `EthCrossAccount` in eth functions. + +## [v0.1.6] - 2022-20-10 + +### Change + +- Added `set_properties` method for `TokenProperties` interface. + ## [v0.1.5] - 2022-08-24 ### Change - - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`. - +- Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`. + ## [v0.1.4] 2022-08-16 ### Other changes @@ -28,7 +76,9 @@ Upstream-Change: https://github.com/paritytech/substrate/pull/11490 - build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b ## [0.1.2] - 2022-07-25 + ### Changed + - New `token_uri` retrieval logic: If the collection has a `url` property and it is not empty, it is returned. @@ -39,8 +89,9 @@ Upstream-Change: https://github.com/paritytech/substrate/pull/11490 otherwise, return concatenation of `baseURI` and stringified token id (decimal stringifying, without paddings). ## [0.1.1] - 2022-07-14 + ### Added - Implementation of RPC method `token_owners`. - For reasons of compatibility with this pallet, returns only one owner if token exists. - This was an internal request to improve the web interface and support fractionalization event. + For reasons of compatibility with this pallet, returns only one owner if token exists. + This was an internal request to improve the web interface and support fractionalization event. diff --git a/pallets/nonfungible/Cargo.toml b/pallets/nonfungible/Cargo.toml index a392482e60..5267fe3bd3 100644 --- a/pallets/nonfungible/Cargo.toml +++ b/pallets/nonfungible/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-nonfungible" -version = "0.1.5" +version = "0.1.12" license = "GPLv3" edition = "2021" @@ -11,19 +11,19 @@ package = 'parity-scale-codec' version = '3.1.2' [dependencies] -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } pallet-common = { default-features = false, path = '../common' } pallet-structure = { default-features = false, path = '../structure' } up-data-structs = { default-features = false, path = '../../primitives/data-structs' } evm-coder = { default-features = false, path = '../../crates/evm-coder' } pallet-evm-coder-substrate = { default-features = false, path = '../evm-coder-substrate' } -ethereum = { version = "0.12.0", default-features = false } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +ethereum = { version = "0.14.0", default-features = false } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } @@ -52,3 +52,4 @@ runtime-benchmarks = [ 'up-data-structs/runtime-benchmarks', ] try-runtime = ["frame-support/try-runtime"] +stubgen = ["evm-coder/stubgen", "pallet-common/stubgen"] diff --git a/pallets/nonfungible/src/benchmarking.rs b/pallets/nonfungible/src/benchmarking.rs index c60ccbe6dd..0d8b16ab4f 100644 --- a/pallets/nonfungible/src/benchmarking.rs +++ b/pallets/nonfungible/src/benchmarking.rs @@ -223,6 +223,20 @@ benchmarks! { }: {collection.token_owner(item)} + set_allowance_for_all { + bench_init!{ + owner: sub; collection: collection(owner); owner: cross_from_sub; + operator: cross_sub; + }; + }: {>::set_allowance_for_all(&collection, &owner, &operator, true)?} + + allowance_for_all { + bench_init!{ + owner: sub; collection: collection(owner); owner: cross_from_sub; + operator: cross_sub; + }; + }: {>::allowance_for_all(&collection, &owner, &operator)} + repair_item { bench_init!{ owner: sub; collection: collection(owner); diff --git a/pallets/nonfungible/src/common.rs b/pallets/nonfungible/src/common.rs index 32aa4a33cf..c891465f00 100644 --- a/pallets/nonfungible/src/common.rs +++ b/pallets/nonfungible/src/common.rs @@ -123,7 +123,11 @@ impl CommonWeightInfo for CommonWeights { >::token_owner() } - fn repair_item() -> Weight { + fn set_allowance_for_all() -> Weight { + >::set_allowance_for_all() + } + + fn force_repair_item() -> Weight { >::repair_item() } } @@ -517,10 +521,26 @@ impl CommonCollectionOperations for NonfungibleHandle { } } + fn set_allowance_for_all( + &self, + owner: T::CrossAccountId, + operator: T::CrossAccountId, + approve: bool, + ) -> DispatchResultWithPostInfo { + with_weight( + >::set_allowance_for_all(self, &owner, &operator, approve), + >::set_allowance_for_all(), + ) + } + + fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool { + >::allowance_for_all(self, &owner, &operator) + } + fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo { with_weight( >::repair_item(self, token), - >::repair_item(), + >::force_repair_item(), ) } } diff --git a/pallets/nonfungible/src/erc.rs b/pallets/nonfungible/src/erc.rs index 677efc6c0d..598a146ce7 100644 --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -24,21 +24,26 @@ use core::{ char::{REPLACEMENT_CHARACTER, decode_utf16}, convert::TryInto, }; -use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight}; +use evm_coder::{ + abi::AbiType, ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, + weight, +}; use frame_support::BoundedVec; use up_data_structs::{ TokenId, PropertyPermission, PropertyKeyPermission, Property, CollectionId, PropertyKey, CollectionPropertiesVec, }; use pallet_evm_coder_substrate::dispatch_to_evm; -use sp_std::vec::Vec; +use sp_std::{vec::Vec, vec}; use pallet_common::{ + CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations, erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key}, - CollectionHandle, CollectionPropertyPermissions, + eth, }; use pallet_evm::{account::CrossAccountId, PrecompileHandle}; use pallet_evm_coder_substrate::call; use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _}; +use sp_core::Get; use crate::{ AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted, @@ -54,6 +59,8 @@ impl NonfungibleHandle { /// @param isMutable Permission to mutate property. /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable. /// @param tokenOwner Permission to mutate property by token owner if property is mutable. + #[weight(>::set_token_property_permissions(1))] + #[solidity(hide)] fn set_token_property_permission( &mut self, caller: caller, @@ -63,10 +70,10 @@ impl NonfungibleHandle { token_owner: bool, ) -> Result<()> { let caller = T::CrossAccountId::from_eth(caller); - >::set_property_permission( + >::set_token_property_permissions( self, &caller, - PropertyKeyPermission { + vec![PropertyKeyPermission { key: >::from(key) .try_into() .map_err(|_| "too long key")?, @@ -75,16 +82,43 @@ impl NonfungibleHandle { collection_admin, token_owner, }, - }, + }], ) .map_err(dispatch_to_evm::) } + /// @notice Set permissions for token property. + /// @dev Throws error if `msg.sender` is not admin or owner of the collection. + /// @param permissions Permissions for keys. + #[weight(>::set_token_property_permissions(permissions.len() as u32))] + fn set_token_property_permissions( + &mut self, + caller: caller, + permissions: Vec, + ) -> Result<()> { + let caller = T::CrossAccountId::from_eth(caller); + let perms = eth::TokenPropertyPermission::into_property_key_permissions(permissions)?; + + >::set_token_property_permissions(self, &caller, perms) + .map_err(dispatch_to_evm::) + } + + /// @notice Get permissions for token properties. + fn token_property_permissions(&self) -> Result> { + let perms = >::token_property_permission(self.id); + Ok(perms + .into_iter() + .map(eth::TokenPropertyPermission::from) + .collect()) + } + /// @notice Set token property value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. /// @param key Property key. /// @param value Property value. + #[solidity(hide)] + #[weight(>::set_token_properties(1))] fn set_property( &mut self, caller: caller, @@ -97,7 +131,7 @@ impl NonfungibleHandle { let key = >::from(key) .try_into() .map_err(|_| "key too long")?; - let value = value.try_into().map_err(|_| "value too long")?; + let value = value.0.try_into().map_err(|_| "value too long")?; let nesting_budget = self .recorder @@ -113,10 +147,46 @@ impl NonfungibleHandle { .map_err(dispatch_to_evm::) } + /// @notice Set token properties value. + /// @dev Throws error if `msg.sender` has no permission to edit the property. + /// @param tokenId ID of the token. + /// @param properties settable properties + #[weight(>::set_token_properties(properties.len() as u32))] + fn set_properties( + &mut self, + caller: caller, + token_id: uint256, + properties: Vec, + ) -> Result<()> { + let caller = T::CrossAccountId::from_eth(caller); + let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; + + let nesting_budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + let properties = properties + .into_iter() + .map(eth::Property::try_into) + .collect::>>()?; + + >::set_token_properties( + self, + &caller, + TokenId(token_id), + properties.into_iter(), + false, + &nesting_budget, + ) + .map_err(dispatch_to_evm::) + } + /// @notice Delete token property value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. /// @param key Property key. + #[solidity(hide)] + #[weight(>::delete_token_properties(1))] fn delete_property(&mut self, token_id: uint256, caller: caller, key: string) -> Result<()> { let caller = T::CrossAccountId::from_eth(caller); let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; @@ -132,6 +202,38 @@ impl NonfungibleHandle { .map_err(dispatch_to_evm::) } + /// @notice Delete token properties value. + /// @dev Throws error if `msg.sender` has no permission to edit the property. + /// @param tokenId ID of the token. + /// @param keys Properties key. + #[weight(>::delete_token_properties(keys.len() as u32))] + fn delete_properties( + &mut self, + token_id: uint256, + caller: caller, + keys: Vec, + ) -> Result<()> { + let caller = T::CrossAccountId::from_eth(caller); + let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; + let keys = keys + .into_iter() + .map(|k| Ok(>::from(k).try_into().map_err(|_| "key too long")?)) + .collect::>>()?; + + let nesting_budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + >::delete_token_properties( + self, + &caller, + TokenId(token_id), + keys.into_iter(), + &nesting_budget, + ) + .map_err(dispatch_to_evm::) + } + /// @notice Get token property value. /// @dev Throws error if key not found /// @param tokenId ID of the token. @@ -146,7 +248,7 @@ impl NonfungibleHandle { let props = >::get((self.id, token_id)); let prop = props.get(&key).ok_or("key not found")?; - Ok(prop.to_vec()) + Ok(prop.to_vec().into()) } } @@ -198,7 +300,10 @@ pub enum ERC721UniqueMintableEvents { /// @title ERC-721 Non-Fungible Token Standard, optional metadata extension /// @dev See https://eips.ethereum.org/EIPS/eip-721 #[solidity_interface(name = ERC721Metadata, expect_selector = 0x5b5e139f)] -impl NonfungibleHandle { +impl NonfungibleHandle +where + T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>, +{ /// @notice A descriptive name for a collection of NFTs in this contract /// @dev real implementation of this function lies in `ERC721UniqueExtensions` #[solidity(hide, rename_selector = "name")] @@ -386,15 +491,23 @@ impl NonfungibleHandle { Ok(()) } - /// @dev Not implemented + /// @notice Sets or unsets the approval of a given operator. + /// The `operator` is allowed to transfer all tokens of the `caller` on their behalf. + /// @param operator Operator + /// @param approved Should operator status be granted or revoked? + #[weight(>::set_allowance_for_all())] fn set_approval_for_all( &mut self, - _caller: caller, - _operator: address, - _approved: bool, + caller: caller, + operator: address, + approved: bool, ) -> Result { - // TODO: Not implemetable - Err("not implemented".into()) + let caller = T::CrossAccountId::from_eth(caller); + let operator = T::CrossAccountId::from_eth(operator); + + >::set_allowance_for_all(self, &caller, &operator, approved) + .map_err(dispatch_to_evm::)?; + Ok(()) } /// @dev Not implemented @@ -403,10 +516,18 @@ impl NonfungibleHandle { Err("not implemented".into()) } - /// @dev Not implemented - fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result
{ - // TODO: Not implemetable - Err("not implemented".into()) + /// @notice Tells whether the given `owner` approves the `operator`. + #[weight(>::allowance_for_all())] + fn is_approved_for_all(&self, owner: address, operator: address) -> Result { + let owner = T::CrossAccountId::from_eth(owner); + let operator = T::CrossAccountId::from_eth(operator); + + Ok(>::allowance_for_all(self, &owner, &operator)) + } + + /// @notice Returns collection helper contract address + fn collection_helper_address(&self) -> Result
{ + Ok(T::ContractAddress::get()) } } @@ -434,7 +555,7 @@ impl NonfungibleHandle { Ok(false) } - /// @notice Function to mint token. + /// @notice Function to mint a token. /// @param to The new owner /// @return uint256 The id of the newly minted token #[weight(>::create_item())] @@ -447,7 +568,7 @@ impl NonfungibleHandle { Ok(token_id) } - /// @notice Function to mint token. + /// @notice Function to mint a token. /// @dev `tokenId` should be obtained with `nextTokenId` method, /// unlike standard, you can't specify it manually /// @param to The new owner @@ -603,7 +724,10 @@ fn get_token_permission( /// @title Unique extensions for ERC721. #[solidity_interface(name = ERC721UniqueExtensions)] -impl NonfungibleHandle { +impl NonfungibleHandle +where + T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>, +{ /// @notice A descriptive name for a collection of NFTs in this contract fn name(&self) -> Result { Ok(decode_utf16(self.name.iter().copied()) @@ -616,6 +740,69 @@ impl NonfungibleHandle { Ok(string::from_utf8_lossy(&self.token_prefix).into()) } + /// @notice A description for the collection. + fn description(&self) -> Result { + Ok(decode_utf16(self.description.iter().copied()) + .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) + .collect::()) + } + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + fn cross_owner_of(&self, token_id: uint256) -> Result { + Self::token_owner(&self, token_id.try_into()?) + .map(|o| eth::CrossAddress::from_sub_cross_account::(&o)) + .ok_or(Error::Revert("key too large".into())) + } + + /// Returns the token properties. + /// + /// @param tokenId Id for the token. + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + fn properties(&self, token_id: uint256, keys: Vec) -> Result> { + let keys = keys + .into_iter() + .map(|key| { + >::from(key) + .try_into() + .map_err(|_| Error::Revert("key too large".into())) + }) + .collect::>>()?; + + >::token_properties( + &self, + token_id.try_into()?, + if keys.is_empty() { None } else { Some(keys) }, + ) + .into_iter() + .map(eth::Property::try_from) + .collect::>>() + } + + /// @notice Set or reaffirm the approved address for an NFT + /// @dev The zero address indicates there is no approved address. + /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized + /// operator of the current owner. + /// @param approved The new substrate address approved NFT controller + /// @param tokenId The NFT to approve + #[weight(>::approve())] + fn approve_cross( + &mut self, + caller: caller, + approved: eth::CrossAddress, + token_id: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let approved = approved.into_sub_cross_account::()?; + let token = token_id.try_into()?; + + >::set_allowance(self, &caller, token, Some(&approved)) + .map_err(dispatch_to_evm::)?; + Ok(()) + } + /// @notice Transfer ownership of an NFT /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` /// is the zero address. Throws if `tokenId` is not a valid NFT. @@ -634,12 +821,62 @@ impl NonfungibleHandle { Ok(()) } + /// @notice Transfer ownership of an NFT + /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` + /// is the zero address. Throws if `tokenId` is not a valid NFT. + /// @param to The new owner + /// @param tokenId The NFT to transfer + #[weight(>::transfer())] + fn transfer_cross( + &mut self, + caller: caller, + to: eth::CrossAddress, + token_id: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let to = to.into_sub_cross_account::()?; + let token = token_id.try_into()?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + >::transfer(self, &caller, &to, token, &budget).map_err(dispatch_to_evm::)?; + Ok(()) + } + + /// @notice Transfer ownership of an NFT from cross account address to cross account address + /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` + /// is the zero address. Throws if `tokenId` is not a valid NFT. + /// @param from Cross acccount address of current owner + /// @param to Cross acccount address of new owner + /// @param tokenId The NFT to transfer + #[weight(>::transfer())] + fn transfer_from_cross( + &mut self, + caller: caller, + from: eth::CrossAddress, + to: eth::CrossAddress, + token_id: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let from = from.into_sub_cross_account::()?; + let to = to.into_sub_cross_account::()?; + let token_id = token_id.try_into()?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + Pallet::::transfer_from(self, &caller, &from, &to, token_id, &budget) + .map_err(dispatch_to_evm::)?; + Ok(()) + } + /// @notice Burns a specific ERC721 token. /// @dev Throws unless `msg.sender` is the current owner or an authorized /// operator for this NFT. Throws if `from` is not the current owner. Throws /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT. /// @param from The current owner of the NFT /// @param tokenId The NFT to transfer + #[solidity(hide)] #[weight(>::burn_from())] fn burn_from(&mut self, caller: caller, from: address, token_id: uint256) -> Result { let caller = T::CrossAccountId::from_eth(caller); @@ -654,6 +891,31 @@ impl NonfungibleHandle { Ok(()) } + /// @notice Burns a specific ERC721 token. + /// @dev Throws unless `msg.sender` is the current owner or an authorized + /// operator for this NFT. Throws if `from` is not the current owner. Throws + /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT. + /// @param from The current owner of the NFT + /// @param tokenId The NFT to transfer + #[weight(>::burn_from())] + fn burn_from_cross( + &mut self, + caller: caller, + from: eth::CrossAddress, + token_id: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let from = from.into_sub_cross_account::()?; + let token = token_id.try_into()?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + >::burn_from(self, &caller, &from, token, &budget) + .map_err(dispatch_to_evm::)?; + Ok(()) + } + /// @notice Returns next free NFT ID. fn next_token_id(&self) -> Result { self.consume_store_reads(1)?; @@ -752,6 +1014,50 @@ impl NonfungibleHandle { .map_err(dispatch_to_evm::)?; Ok(true) } + + /// @notice Function to mint a token. + /// @param to The new owner crossAccountId + /// @param properties Properties of minted token + /// @return uint256 The id of the newly minted token + #[weight(>::create_item())] + fn mint_cross( + &mut self, + caller: caller, + to: eth::CrossAddress, + properties: Vec, + ) -> Result { + let token_id = >::get(self.id) + .checked_add(1) + .ok_or("item id overflow")?; + + let to = to.into_sub_cross_account::()?; + + let properties = properties + .into_iter() + .map(eth::Property::try_into) + .collect::>>()? + .try_into() + .map_err(|_| Error::Revert(alloc::format!("too many properties")))?; + + let caller = T::CrossAccountId::from_eth(caller); + + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + >::create_item( + self, + &caller, + CreateItemData:: { + properties, + owner: to, + }, + &budget, + ) + .map_err(dispatch_to_evm::)?; + + Ok(token_id.into()) + } } #[solidity_interface( diff --git a/pallets/nonfungible/src/lib.rs b/pallets/nonfungible/src/lib.rs index 9574eec66c..5eda7cd59a 100644 --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -103,16 +103,16 @@ use up_data_structs::{ AccessMode, CollectionId, CollectionFlags, CustomDataLimit, TokenId, CreateCollectionData, CreateNftExData, mapping::TokenAddressMapping, budget::Budget, Property, PropertyPermission, PropertyKey, PropertyValue, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty, - TokenChild, AuxPropertyValue, + TokenChild, AuxPropertyValue, PropertiesPermissionMap, }; use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm}; use pallet_common::{ Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle, - eth::collection_id_to_address, + eth::collection_id_to_address, erc::CollectionHelpersEvents, }; use pallet_structure::{Pallet as PalletStructure, Error as StructureError}; use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder}; -use sp_core::H160; +use sp_core::{H160, Get}; use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome}; use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap}; use core::ops::Deref; @@ -127,7 +127,7 @@ pub mod common; pub mod erc; pub mod weights; -pub type CreateItemData = CreateNftExData<::CrossAccountId>; +pub type CreateItemData = CreateNftExData<::CrossAccountId>; pub(crate) type SelfWeightOf = ::WeightInfo; /// Token data, stored independently from other data used to describe it @@ -272,6 +272,18 @@ pub mod pallet { QueryKind = OptionQuery, >; + /// Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet. + #[pallet::storage] + pub type CollectionAllowance = StorageNMap< + Key = ( + Key, + Key, + Key, + ), + Value = bool, + QueryKind = ValueQuery, + >; + /// Upgrade from the old schema to properties. #[pallet::hooks] impl Hooks> for Pallet { @@ -438,6 +450,7 @@ impl Pallet { >::remove(id); let _ = >::clear_prefix((id,), u32::MAX, None); let _ = >::clear_prefix((id,), u32::MAX, None); + let _ = >::clear_prefix((id,), u32::MAX, None); Ok(()) } @@ -660,6 +673,14 @@ impl Pallet { )); } } + + >::deposit_log( + CollectionHelpersEvents::TokenChanged { + collection_id: collection_id_to_address(collection.id), + token_id: token_id.into(), + } + .to_log(T::ContractAddress::get()), + ); } Ok(()) @@ -803,15 +824,8 @@ impl Pallet { ) } - /// Set property permissions for the collection. - /// - /// Sender should be the owner or admin of the collection. - pub fn set_property_permission( - collection: &CollectionHandle, - sender: &T::CrossAccountId, - permission: PropertyKeyPermission, - ) -> DispatchResult { - >::set_property_permission(collection, sender, permission) + pub fn token_property_permission(collection_id: CollectionId) -> PropertiesPermissionMap { + >::property_permissions(collection_id) } pub fn check_token_immediate_ownership( @@ -1193,6 +1207,9 @@ impl Pallet { if >::get((collection.id, token)).as_ref() == Some(spender) { return Ok(()); } + if >::get((collection.id, from, spender)) { + return Ok(()); + } ensure!( collection.ignores_allowance(spender), >::ApprovedValueTooLow @@ -1327,6 +1344,54 @@ impl Pallet { Self::create_multiple_items(collection, sender, vec![data], nesting_budget) } + /// Sets or unsets the approval of a given operator. + /// + /// The `operator` is allowed to transfer all token pieces of the `owner` on their behalf. + /// - `owner`: Token owner + /// - `operator`: Operator + /// - `approve`: Should operator status be granted or revoked? + pub fn set_allowance_for_all( + collection: &NonfungibleHandle, + owner: &T::CrossAccountId, + operator: &T::CrossAccountId, + approve: bool, + ) -> DispatchResult { + if collection.permissions.access() == AccessMode::AllowList { + collection.check_allowlist(owner)?; + collection.check_allowlist(operator)?; + } + + >::ensure_correct_receiver(operator)?; + + // ========= + + >::insert((collection.id, owner, operator), approve); + >::deposit_log( + ERC721Events::ApprovalForAll { + owner: *owner.as_eth(), + operator: *operator.as_eth(), + approved: approve, + } + .to_log(collection_id_to_address(collection.id)), + ); + >::deposit_event(CommonEvent::ApprovedForAll( + collection.id, + owner.clone(), + operator.clone(), + approve, + )); + Ok(()) + } + + /// Tells whether the given `owner` approves the `operator`. + pub fn allowance_for_all( + collection: &NonfungibleHandle, + owner: &T::CrossAccountId, + operator: &T::CrossAccountId, + ) -> bool { + >::get((collection.id, owner, operator)) + } + pub fn repair_item(collection: &NonfungibleHandle, token: TokenId) -> DispatchResult { >::mutate((collection.id, token), |properties| { properties.recompute_consumed_space(); diff --git a/pallets/nonfungible/src/stubs/UniqueNFT.raw b/pallets/nonfungible/src/stubs/UniqueNFT.raw index 7447cb23a3..c2da86f565 100644 Binary files a/pallets/nonfungible/src/stubs/UniqueNFT.raw and b/pallets/nonfungible/src/stubs/UniqueNFT.raw differ diff --git a/pallets/nonfungible/src/stubs/UniqueNFT.sol b/pallets/nonfungible/src/stubs/UniqueNFT.sol index 29c312b420..3165a87b1e 100644 --- a/pallets/nonfungible/src/stubs/UniqueNFT.sol +++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol @@ -18,59 +18,96 @@ contract ERC165 is Dummy { } /// @title A contract that allows to set and delete token properties and change token property permissions. -/// @dev the ERC-165 identifier for this interface is 0x41369377 +/// @dev the ERC-165 identifier for this interface is 0xde0695c2 contract TokenProperties is Dummy, ERC165 { + // /// @notice Set permissions for token property. + // /// @dev Throws error if `msg.sender` is not admin or owner of the collection. + // /// @param key Property key. + // /// @param isMutable Permission to mutate property. + // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable. + // /// @param tokenOwner Permission to mutate property by token owner if property is mutable. + // /// @dev EVM selector for this function is: 0x222d97fa, + // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool) + // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) public { + // require(false, stub_error); + // key; + // isMutable; + // collectionAdmin; + // tokenOwner; + // dummy = 0; + // } + /// @notice Set permissions for token property. /// @dev Throws error if `msg.sender` is not admin or owner of the collection. - /// @param key Property key. - /// @param isMutable Permission to mutate property. - /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable. - /// @param tokenOwner Permission to mutate property by token owner if property is mutable. - /// @dev EVM selector for this function is: 0x222d97fa, - /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool) - function setTokenPropertyPermission( - string memory key, - bool isMutable, - bool collectionAdmin, - bool tokenOwner - ) public { + /// @param permissions Permissions for keys. + /// @dev EVM selector for this function is: 0xbd92983a, + /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[]) + function setTokenPropertyPermissions(TokenPropertyPermission[] memory permissions) public { require(false, stub_error); - key; - isMutable; - collectionAdmin; - tokenOwner; + permissions; dummy = 0; } - /// @notice Set token property value. + /// @notice Get permissions for token properties. + /// @dev EVM selector for this function is: 0xf23d7790, + /// or in textual repr: tokenPropertyPermissions() + function tokenPropertyPermissions() public view returns (TokenPropertyPermission[] memory) { + require(false, stub_error); + dummy; + return new TokenPropertyPermission[](0); + } + + // /// @notice Set token property value. + // /// @dev Throws error if `msg.sender` has no permission to edit the property. + // /// @param tokenId ID of the token. + // /// @param key Property key. + // /// @param value Property value. + // /// @dev EVM selector for this function is: 0x1752d67b, + // /// or in textual repr: setProperty(uint256,string,bytes) + // function setProperty(uint256 tokenId, string memory key, bytes memory value) public { + // require(false, stub_error); + // tokenId; + // key; + // value; + // dummy = 0; + // } + + /// @notice Set token properties value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. - /// @param key Property key. - /// @param value Property value. - /// @dev EVM selector for this function is: 0x1752d67b, - /// or in textual repr: setProperty(uint256,string,bytes) - function setProperty( - uint256 tokenId, - string memory key, - bytes memory value - ) public { + /// @param properties settable properties + /// @dev EVM selector for this function is: 0x14ed3a6e, + /// or in textual repr: setProperties(uint256,(string,bytes)[]) + function setProperties(uint256 tokenId, Property[] memory properties) public { require(false, stub_error); tokenId; - key; - value; + properties; dummy = 0; } - /// @notice Delete token property value. + // /// @notice Delete token property value. + // /// @dev Throws error if `msg.sender` has no permission to edit the property. + // /// @param tokenId ID of the token. + // /// @param key Property key. + // /// @dev EVM selector for this function is: 0x066111d1, + // /// or in textual repr: deleteProperty(uint256,string) + // function deleteProperty(uint256 tokenId, string memory key) public { + // require(false, stub_error); + // tokenId; + // key; + // dummy = 0; + // } + + /// @notice Delete token properties value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. - /// @param key Property key. - /// @dev EVM selector for this function is: 0x066111d1, - /// or in textual repr: deleteProperty(uint256,string) - function deleteProperty(uint256 tokenId, string memory key) public { + /// @param keys Properties key. + /// @dev EVM selector for this function is: 0xc472d371, + /// or in textual repr: deleteProperties(uint256,string[]) + function deleteProperties(uint256 tokenId, string[] memory keys) public { require(false, stub_error); tokenId; - key; + keys; dummy = 0; } @@ -90,30 +127,84 @@ contract TokenProperties is Dummy, ERC165 { } } +/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue). +struct Property { + string key; + bytes value; +} + +/// Ethereum representation of Token Property Permissions. +struct TokenPropertyPermission { + /// Token property key. + string key; + /// Token property permissions. + PropertyPermission[] permissions; +} + +/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value. +struct PropertyPermission { + /// TokenPermission field. + TokenPermissionField code; + /// TokenPermission value. + bool value; +} + +/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration. +enum TokenPermissionField { + /// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`] + Mutable, + /// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`] + TokenOwner, + /// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`] + CollectionAdmin +} + /// @title A contract that allows you to work with collections. -/// @dev the ERC-165 identifier for this interface is 0x62e22290 +/// @dev the ERC-165 identifier for this interface is 0x2a14cfd1 contract Collection is Dummy, ERC165 { - /// Set collection property. + // /// Set collection property. + // /// + // /// @param key Property key. + // /// @param value Propery value. + // /// @dev EVM selector for this function is: 0x2f073f66, + // /// or in textual repr: setCollectionProperty(string,bytes) + // function setCollectionProperty(string memory key, bytes memory value) public { + // require(false, stub_error); + // key; + // value; + // dummy = 0; + // } + + /// Set collection properties. /// - /// @param key Property key. - /// @param value Propery value. - /// @dev EVM selector for this function is: 0x2f073f66, - /// or in textual repr: setCollectionProperty(string,bytes) - function setCollectionProperty(string memory key, bytes memory value) public { + /// @param properties Vector of properties key/value pair. + /// @dev EVM selector for this function is: 0x50b26b2a, + /// or in textual repr: setCollectionProperties((string,bytes)[]) + function setCollectionProperties(Property[] memory properties) public { require(false, stub_error); - key; - value; + properties; dummy = 0; } - /// Delete collection property. + // /// Delete collection property. + // /// + // /// @param key Property key. + // /// @dev EVM selector for this function is: 0x7b7debce, + // /// or in textual repr: deleteCollectionProperty(string) + // function deleteCollectionProperty(string memory key) public { + // require(false, stub_error); + // key; + // dummy = 0; + // } + + /// Delete collection properties. /// - /// @param key Property key. - /// @dev EVM selector for this function is: 0x7b7debce, - /// or in textual repr: deleteCollectionProperty(string) - function deleteCollectionProperty(string memory key) public { + /// @param keys Properties keys. + /// @dev EVM selector for this function is: 0xee206ee3, + /// or in textual repr: deleteCollectionProperties(string[]) + function deleteCollectionProperties(string[] memory keys) public { require(false, stub_error); - key; + keys; dummy = 0; } @@ -132,14 +223,40 @@ contract Collection is Dummy, ERC165 { return hex""; } + /// Get collection properties. + /// + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0x285fb8e6, + /// or in textual repr: collectionProperties(string[]) + function collectionProperties(string[] memory keys) public view returns (Property[] memory) { + require(false, stub_error); + keys; + dummy; + return new Property[](0); + } + + // /// Set the sponsor of the collection. + // /// + // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. + // /// + // /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. + // /// @dev EVM selector for this function is: 0x7623402e, + // /// or in textual repr: setCollectionSponsor(address) + // function setCollectionSponsor(address sponsor) public { + // require(false, stub_error); + // sponsor; + // dummy = 0; + // } + /// Set the sponsor of the collection. /// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. /// - /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. - /// @dev EVM selector for this function is: 0x7623402e, - /// or in textual repr: setCollectionSponsor(address) - function setCollectionSponsor(address sponsor) public { + /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract. + /// @dev EVM selector for this function is: 0x84a1d5a8, + /// or in textual repr: setCollectionSponsorCross((address,uint256)) + function setCollectionSponsorCross(CrossAddress memory sponsor) public { require(false, stub_error); sponsor; dummy = 0; @@ -177,44 +294,31 @@ contract Collection is Dummy, ERC165 { /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x6ec0a9f1, /// or in textual repr: collectionSponsor() - function collectionSponsor() public view returns (Tuple17 memory) { + function collectionSponsor() public view returns (CrossAddress memory) { require(false, stub_error); dummy; - return Tuple17(0x0000000000000000000000000000000000000000, 0); + return CrossAddress(0x0000000000000000000000000000000000000000, 0); } - /// Set limits for the collection. - /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "accountTokenOwnershipLimit", - /// "sponsoredDataSize", - /// "sponsoredDataRateLimit", - /// "tokenLimit", - /// "sponsorTransferTimeout", - /// "sponsorApproveTimeout" - /// @param value Value of the limit. - /// @dev EVM selector for this function is: 0x6a3841db, - /// or in textual repr: setCollectionLimit(string,uint32) - function setCollectionLimit(string memory limit, uint32 value) public { + /// Get current collection limits. + /// + /// @return Array of collection limits + /// @dev EVM selector for this function is: 0xf63bc572, + /// or in textual repr: collectionLimits() + function collectionLimits() public view returns (CollectionLimit[] memory) { require(false, stub_error); - limit; - value; - dummy = 0; + dummy; + return new CollectionLimit[](0); } /// Set limits for the collection. /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "ownerCanTransfer", - /// "ownerCanDestroy", - /// "transfersEnabled" - /// @param value Value of the limit. - /// @dev EVM selector for this function is: 0x993b7fba, - /// or in textual repr: setCollectionLimit(string,bool) - function setCollectionLimit(string memory limit, bool value) public { + /// @param limit Some limit. + /// @dev EVM selector for this function is: 0x2316ee74, + /// or in textual repr: setCollectionLimit((uint8,(bool,uint256))) + function setCollectionLimit(CollectionLimit memory limit) public { require(false, stub_error); limit; - value; dummy = 0; } @@ -228,26 +332,46 @@ contract Collection is Dummy, ERC165 { } /// Add collection admin. - /// @param newAdmin Address of the added administrator. - /// @dev EVM selector for this function is: 0x92e462c7, - /// or in textual repr: addCollectionAdmin(address) - function addCollectionAdmin(address newAdmin) public { + /// @param newAdmin Cross account administrator address. + /// @dev EVM selector for this function is: 0x859aa7d6, + /// or in textual repr: addCollectionAdminCross((address,uint256)) + function addCollectionAdminCross(CrossAddress memory newAdmin) public { require(false, stub_error); newAdmin; dummy = 0; } /// Remove collection admin. - /// - /// @param admin Address of the removed administrator. - /// @dev EVM selector for this function is: 0xfafd7b42, - /// or in textual repr: removeCollectionAdmin(address) - function removeCollectionAdmin(address admin) public { + /// @param admin Cross account administrator address. + /// @dev EVM selector for this function is: 0x6c0cd173, + /// or in textual repr: removeCollectionAdminCross((address,uint256)) + function removeCollectionAdminCross(CrossAddress memory admin) public { require(false, stub_error); admin; dummy = 0; } + // /// Add collection admin. + // /// @param newAdmin Address of the added administrator. + // /// @dev EVM selector for this function is: 0x92e462c7, + // /// or in textual repr: addCollectionAdmin(address) + // function addCollectionAdmin(address newAdmin) public { + // require(false, stub_error); + // newAdmin; + // dummy = 0; + // } + + // /// Remove collection admin. + // /// + // /// @param admin Address of the removed administrator. + // /// @dev EVM selector for this function is: 0xfafd7b42, + // /// or in textual repr: removeCollectionAdmin(address) + // function removeCollectionAdmin(address admin) public { + // require(false, stub_error); + // admin; + // dummy = 0; + // } + /// Toggle accessibility of collection nesting. /// /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled' @@ -272,6 +396,24 @@ contract Collection is Dummy, ERC165 { dummy = 0; } + /// Returns nesting for a collection + /// @dev EVM selector for this function is: 0x22d25bfe, + /// or in textual repr: collectionNestingRestrictedCollectionIds() + function collectionNestingRestrictedCollectionIds() public view returns (CollectionNesting memory) { + require(false, stub_error); + dummy; + return CollectionNesting(false, new uint256[](0)); + } + + /// Returns permissions for a collection + /// @dev EVM selector for this function is: 0x5b2eaf4b, + /// or in textual repr: collectionNestingPermissions() + function collectionNestingPermissions() public view returns (CollectionNestingPermission[] memory) { + require(false, stub_error); + dummy; + return new CollectionNestingPermission[](0); + } + /// Set the collection access method. /// @param mode Access mode /// 0 for Normal @@ -287,32 +429,54 @@ contract Collection is Dummy, ERC165 { /// Checks that user allowed to operate with collection. /// /// @param user User address to check. - /// @dev EVM selector for this function is: 0xd63a8e11, - /// or in textual repr: allowed(address) - function allowed(address user) public view returns (bool) { + /// @dev EVM selector for this function is: 0x91b6df49, + /// or in textual repr: allowlistedCross((address,uint256)) + function allowlistedCross(CrossAddress memory user) public view returns (bool) { require(false, stub_error); user; dummy; return false; } - /// Add the user to the allowed list. + // /// Add the user to the allowed list. + // /// + // /// @param user Address of a trusted user. + // /// @dev EVM selector for this function is: 0x67844fe6, + // /// or in textual repr: addToCollectionAllowList(address) + // function addToCollectionAllowList(address user) public { + // require(false, stub_error); + // user; + // dummy = 0; + // } + + /// Add user to allowed list. /// - /// @param user Address of a trusted user. - /// @dev EVM selector for this function is: 0x67844fe6, - /// or in textual repr: addToCollectionAllowList(address) - function addToCollectionAllowList(address user) public { + /// @param user User cross account address. + /// @dev EVM selector for this function is: 0xa0184a3a, + /// or in textual repr: addToCollectionAllowListCross((address,uint256)) + function addToCollectionAllowListCross(CrossAddress memory user) public { require(false, stub_error); user; dummy = 0; } - /// Remove the user from the allowed list. + // /// Remove the user from the allowed list. + // /// + // /// @param user Address of a removed user. + // /// @dev EVM selector for this function is: 0x85c51acb, + // /// or in textual repr: removeFromCollectionAllowList(address) + // function removeFromCollectionAllowList(address user) public { + // require(false, stub_error); + // user; + // dummy = 0; + // } + + /// Remove user from allowed list. /// - /// @param user Address of a removed user. - /// @dev EVM selector for this function is: 0x85c51acb, - /// or in textual repr: removeFromCollectionAllowList(address) - function removeFromCollectionAllowList(address user) public { + /// @param user User cross account address. + /// @dev EVM selector for this function is: 0x09ba452a, + /// or in textual repr: removeFromCollectionAllowListCross((address,uint256)) + function removeFromCollectionAllowListCross(CrossAddress memory user) public { require(false, stub_error); user; dummy = 0; @@ -329,13 +493,26 @@ contract Collection is Dummy, ERC165 { dummy = 0; } + // /// Check that account is the owner or admin of the collection + // /// + // /// @param user account to verify + // /// @return "true" if account is the owner or admin + // /// @dev EVM selector for this function is: 0x9811b0c7, + // /// or in textual repr: isOwnerOrAdmin(address) + // function isOwnerOrAdmin(address user) public view returns (bool) { + // require(false, stub_error); + // user; + // dummy; + // return false; + // } + /// Check that account is the owner or admin of the collection /// - /// @param user account to verify + /// @param user User cross account to verify /// @return "true" if account is the owner or admin - /// @dev EVM selector for this function is: 0x9811b0c7, - /// or in textual repr: isOwnerOrAdmin(address) - function isOwnerOrAdmin(address user) public view returns (bool) { + /// @dev EVM selector for this function is: 0x3e75a905, + /// or in textual repr: isOwnerOrAdminCross((address,uint256)) + function isOwnerOrAdminCross(CrossAddress memory user) public view returns (bool) { require(false, stub_error); user; dummy; @@ -359,29 +536,107 @@ contract Collection is Dummy, ERC165 { /// If address is canonical then substrate mirror is zero and vice versa. /// @dev EVM selector for this function is: 0xdf727d3b, /// or in textual repr: collectionOwner() - function collectionOwner() public view returns (Tuple17 memory) { + function collectionOwner() public view returns (CrossAddress memory) { require(false, stub_error); dummy; - return Tuple17(0x0000000000000000000000000000000000000000, 0); + return CrossAddress(0x0000000000000000000000000000000000000000, 0); + } + + // /// Changes collection owner to another account + // /// + // /// @dev Owner can be changed only by current owner + // /// @param newOwner new owner account + // /// @dev EVM selector for this function is: 0x4f53e226, + // /// or in textual repr: changeCollectionOwner(address) + // function changeCollectionOwner(address newOwner) public { + // require(false, stub_error); + // newOwner; + // dummy = 0; + // } + + /// Get collection administrators + /// + /// @return Vector of tuples with admins address and his substrate mirror. + /// If address is canonical then substrate mirror is zero and vice versa. + /// @dev EVM selector for this function is: 0x5813216b, + /// or in textual repr: collectionAdmins() + function collectionAdmins() public view returns (CrossAddress[] memory) { + require(false, stub_error); + dummy; + return new CrossAddress[](0); } /// Changes collection owner to another account /// /// @dev Owner can be changed only by current owner - /// @param newOwner new owner account - /// @dev EVM selector for this function is: 0x4f53e226, - /// or in textual repr: changeCollectionOwner(address) - function changeCollectionOwner(address newOwner) public { + /// @param newOwner new owner cross account + /// @dev EVM selector for this function is: 0x6496c497, + /// or in textual repr: changeCollectionOwnerCross((address,uint256)) + function changeCollectionOwnerCross(CrossAddress memory newOwner) public { require(false, stub_error); newOwner; dummy = 0; } } -/// @dev anonymous struct -struct Tuple17 { - address field_0; - uint256 field_1; +/// Cross account struct +struct CrossAddress { + address eth; + uint256 sub; +} + +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field. +struct CollectionNestingPermission { + CollectionPermissionField field; + bool value; +} + +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration. +enum CollectionPermissionField { + /// Owner of token can nest tokens under it. + TokenOwner, + /// Admin of token collection can nest tokens under token. + CollectionAdmin +} + +/// Nested collections. +struct CollectionNesting { + bool token_owner; + uint256[] ids; +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM. +struct CollectionLimit { + CollectionLimitField field; + OptionUint value; +} + +/// Ethereum representation of Optional value with uint256. +struct OptionUint { + bool status; + uint256 value; +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM. +enum CollectionLimitField { + /// How many tokens can a user have on one account. + AccountTokenOwnership, + /// How many bytes of data are available for sponsorship. + SponsoredDataSize, + /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`] + SponsoredDataRateLimit, + /// How many tokens can be mined into this collection. + TokenLimit, + /// Timeouts for transfer sponsoring. + SponsorTransferTimeout, + /// Timeout for sponsoring an approval in passed blocks. + SponsorApproveTimeout, + /// Whether the collection owner of the collection can send tokens (which belong to other users). + OwnerCanTransfer, + /// Can the collection owner burn other people's tokens. + OwnerCanDestroy, + /// Is it possible to send tokens from this collection between users. + TransferEnabled } /// @title ERC-721 Non-Fungible Token Standard, optional metadata extension @@ -459,7 +714,7 @@ contract ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents { return false; } - /// @notice Function to mint token. + /// @notice Function to mint a token. /// @param to The new owner /// @return uint256 The id of the newly minted token /// @dev EVM selector for this function is: 0x6a627842, @@ -471,7 +726,7 @@ contract ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents { return 0; } - // /// @notice Function to mint token. + // /// @notice Function to mint a token. // /// @dev `tokenId` should be obtained with `nextTokenId` method, // /// unlike standard, you can't specify it manually // /// @param to The new owner @@ -528,7 +783,7 @@ contract ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents { } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0x4468500d +/// @dev the ERC-165 identifier for this interface is 0x0e48fdb4 contract ERC721UniqueExtensions is Dummy, ERC165 { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev EVM selector for this function is: 0x06fdde03, @@ -548,6 +803,57 @@ contract ERC721UniqueExtensions is Dummy, ERC165 { return ""; } + /// @notice A description for the collection. + /// @dev EVM selector for this function is: 0x7284e416, + /// or in textual repr: description() + function description() public view returns (string memory) { + require(false, stub_error); + dummy; + return ""; + } + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + /// @dev EVM selector for this function is: 0x2b29dace, + /// or in textual repr: crossOwnerOf(uint256) + function crossOwnerOf(uint256 tokenId) public view returns (CrossAddress memory) { + require(false, stub_error); + tokenId; + dummy; + return CrossAddress(0x0000000000000000000000000000000000000000, 0); + } + + /// Returns the token properties. + /// + /// @param tokenId Id for the token. + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0xe07ede7e, + /// or in textual repr: properties(uint256,string[]) + function properties(uint256 tokenId, string[] memory keys) public view returns (Property[] memory) { + require(false, stub_error); + tokenId; + keys; + dummy; + return new Property[](0); + } + + /// @notice Set or reaffirm the approved address for an NFT + /// @dev The zero address indicates there is no approved address. + /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized + /// operator of the current owner. + /// @param approved The new substrate address approved NFT controller + /// @param tokenId The NFT to approve + /// @dev EVM selector for this function is: 0x0ecd0ab0, + /// or in textual repr: approveCross((address,uint256),uint256) + function approveCross(CrossAddress memory approved, uint256 tokenId) public { + require(false, stub_error); + approved; + tokenId; + dummy = 0; + } + /// @notice Transfer ownership of an NFT /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` /// is the zero address. Throws if `tokenId` is not a valid NFT. @@ -562,15 +868,64 @@ contract ERC721UniqueExtensions is Dummy, ERC165 { dummy = 0; } + /// @notice Transfer ownership of an NFT + /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` + /// is the zero address. Throws if `tokenId` is not a valid NFT. + /// @param to The new owner + /// @param tokenId The NFT to transfer + /// @dev EVM selector for this function is: 0x2ada85ff, + /// or in textual repr: transferCross((address,uint256),uint256) + function transferCross(CrossAddress memory to, uint256 tokenId) public { + require(false, stub_error); + to; + tokenId; + dummy = 0; + } + + /// @notice Transfer ownership of an NFT from cross account address to cross account address + /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` + /// is the zero address. Throws if `tokenId` is not a valid NFT. + /// @param from Cross acccount address of current owner + /// @param to Cross acccount address of new owner + /// @param tokenId The NFT to transfer + /// @dev EVM selector for this function is: 0xd5cf430b, + /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256) + function transferFromCross( + CrossAddress memory from, + CrossAddress memory to, + uint256 tokenId + ) public { + require(false, stub_error); + from; + to; + tokenId; + dummy = 0; + } + + // /// @notice Burns a specific ERC721 token. + // /// @dev Throws unless `msg.sender` is the current owner or an authorized + // /// operator for this NFT. Throws if `from` is not the current owner. Throws + // /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT. + // /// @param from The current owner of the NFT + // /// @param tokenId The NFT to transfer + // /// @dev EVM selector for this function is: 0x79cc6790, + // /// or in textual repr: burnFrom(address,uint256) + // function burnFrom(address from, uint256 tokenId) public { + // require(false, stub_error); + // from; + // tokenId; + // dummy = 0; + // } + /// @notice Burns a specific ERC721 token. /// @dev Throws unless `msg.sender` is the current owner or an authorized /// operator for this NFT. Throws if `from` is not the current owner. Throws /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT. /// @param from The current owner of the NFT /// @param tokenId The NFT to transfer - /// @dev EVM selector for this function is: 0x79cc6790, - /// or in textual repr: burnFrom(address,uint256) - function burnFrom(address from, uint256 tokenId) public { + /// @dev EVM selector for this function is: 0xbb2f5a58, + /// or in textual repr: burnFromCross((address,uint256),uint256) + function burnFromCross(CrossAddress memory from, uint256 tokenId) public { require(false, stub_error); from; tokenId; @@ -585,6 +940,7 @@ contract ERC721UniqueExtensions is Dummy, ERC165 { dummy; return 0; } + // /// @notice Function to mint multiple tokens. // /// @dev `tokenIds` should be an array of consecutive numbers and first number // /// should be obtained with `nextTokenId` method @@ -607,7 +963,7 @@ contract ERC721UniqueExtensions is Dummy, ERC165 { // /// @param tokens array of pairs of token ID and token URI for minted tokens // /// @dev EVM selector for this function is: 0x36543006, // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[]) - // function mintBulkWithTokenURI(address to, Tuple6[] memory tokens) public returns (bool) { + // function mintBulkWithTokenURI(address to, Tuple15[] memory tokens) public returns (bool) { // require(false, stub_error); // to; // tokens; @@ -615,10 +971,23 @@ contract ERC721UniqueExtensions is Dummy, ERC165 { // return false; // } + /// @notice Function to mint a token. + /// @param to The new owner crossAccountId + /// @param properties Properties of minted token + /// @return uint256 The id of the newly minted token + /// @dev EVM selector for this function is: 0xb904db03, + /// or in textual repr: mintCross((address,uint256),(string,bytes)[]) + function mintCross(CrossAddress memory to, Property[] memory properties) public returns (uint256) { + require(false, stub_error); + to; + properties; + dummy = 0; + return 0; + } } /// @dev anonymous struct -struct Tuple6 { +struct Tuple15 { uint256 field_0; string field_1; } @@ -672,7 +1041,7 @@ contract ERC721Events { /// @title ERC-721 Non-Fungible Token Standard /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md -/// @dev the ERC-165 identifier for this interface is 0x80ac58cd +/// @dev the ERC-165 identifier for this interface is 0x983a942b contract ERC721 is Dummy, ERC165, ERC721Events { /// @notice Count all NFTs assigned to an owner /// @dev NFTs assigned to the zero address are considered invalid, and this @@ -772,7 +1141,10 @@ contract ERC721 is Dummy, ERC165, ERC721Events { dummy = 0; } - /// @dev Not implemented + /// @notice Sets or unsets the approval of a given operator. + /// The `operator` is allowed to transfer all tokens of the `caller` on their behalf. + /// @param operator Operator + /// @param approved Should operator status be granted or revoked? /// @dev EVM selector for this function is: 0xa22cb465, /// or in textual repr: setApprovalForAll(address,bool) function setApprovalForAll(address operator, bool approved) public { @@ -792,14 +1164,23 @@ contract ERC721 is Dummy, ERC165, ERC721Events { return 0x0000000000000000000000000000000000000000; } - /// @dev Not implemented + /// @notice Tells whether the given `owner` approves the `operator`. /// @dev EVM selector for this function is: 0xe985e9c5, /// or in textual repr: isApprovedForAll(address,address) - function isApprovedForAll(address owner, address operator) public view returns (address) { + function isApprovedForAll(address owner, address operator) public view returns (bool) { require(false, stub_error); owner; operator; dummy; + return false; + } + + /// @notice Returns collection helper contract address + /// @dev EVM selector for this function is: 0x1896cce6, + /// or in textual repr: collectionHelperAddress() + function collectionHelperAddress() public view returns (address) { + require(false, stub_error); + dummy; return 0x0000000000000000000000000000000000000000; } } diff --git a/pallets/nonfungible/src/weights.rs b/pallets/nonfungible/src/weights.rs index 6b5366e231..df4d95adf8 100644 --- a/pallets/nonfungible/src/weights.rs +++ b/pallets/nonfungible/src/weights.rs @@ -26,6 +26,7 @@ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] #![allow(clippy::unnecessary_cast)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; @@ -47,6 +48,8 @@ pub trait WeightInfo { fn set_token_properties(b: u32, ) -> Weight; fn delete_token_properties(b: u32, ) -> Weight; fn token_owner() -> Weight; + fn set_allowance_for_all() -> Weight; + fn allowance_for_all() -> Weight; fn repair_item() -> Weight; } @@ -196,6 +199,16 @@ impl WeightInfo for SubstrateWeight { Weight::from_ref_time(4_366_000) .saturating_add(T::DbWeight::get().reads(1 as u64)) } + // Storage: Nonfungible WalletOperator (r:0 w:1) + fn set_allowance_for_all() -> Weight { + Weight::from_ref_time(16_231_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: Nonfungible WalletOperator (r:1 w:0) + fn allowance_for_all() -> Weight { + Weight::from_ref_time(6_161_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + } // Storage: Nonfungible TokenProperties (r:1 w:1) fn repair_item() -> Weight { Weight::from_ref_time(5_701_000 as u64) @@ -349,6 +362,16 @@ impl WeightInfo for () { Weight::from_ref_time(4_366_000) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } + // Storage: Nonfungible WalletOperator (r:0 w:1) + fn set_allowance_for_all() -> Weight { + Weight::from_ref_time(16_231_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + // Storage: Nonfungible WalletOperator (r:1 w:0) + fn allowance_for_all() -> Weight { + Weight::from_ref_time(6_161_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + } // Storage: Nonfungible TokenProperties (r:1 w:1) fn repair_item() -> Weight { Weight::from_ref_time(5_701_000 as u64) diff --git a/pallets/proxy-rmrk-core/Cargo.toml b/pallets/proxy-rmrk-core/Cargo.toml index 16bd4c987f..2679a63685 100644 --- a/pallets/proxy-rmrk-core/Cargo.toml +++ b/pallets/proxy-rmrk-core/Cargo.toml @@ -11,17 +11,17 @@ package = 'parity-scale-codec' version = '3.1.2' [dependencies] -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } pallet-common = { default-features = false, path = '../common' } pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" } pallet-structure = { default-features = false, path = "../../pallets/structure" } up-data-structs = { default-features = false, path = '../../primitives/data-structs' } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } rmrk-traits = { default-features = false, path = "../../primitives/rmrk-traits" } scale-info = { version = "2.0.1", default-features = false, features = [ "derive", diff --git a/pallets/proxy-rmrk-core/src/lib.rs b/pallets/proxy-rmrk-core/src/lib.rs index 33db5f30b0..0694ccd3ac 100644 --- a/pallets/proxy-rmrk-core/src/lib.rs +++ b/pallets/proxy-rmrk-core/src/lib.rs @@ -178,7 +178,7 @@ pub use property::*; use RmrkProperty::*; -/// Maximum number of levels of depth in the token nesting tree. +/// A maximum number of levels of depth in the token nesting tree. pub const NESTING_BUDGET: u32 = 5; type PendingTarget = (CollectionId, TokenId); @@ -190,11 +190,13 @@ type BasesMap = BTreeMap; #[frame_support::pallet] pub mod pallet { use super::*; - use pallet_evm::account; #[pallet::config] pub trait Config: - frame_system::Config + pallet_common::Config + pallet_nonfungible::Config + account::Config + frame_system::Config + + pallet_common::Config + + pallet_nonfungible::Config + + pallet_evm::Config { /// Overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -355,6 +357,7 @@ pub mod pallet { /// - `max`: Optional maximum number of tokens. /// - `symbol`: UTF-8 string with token prefix, by which to represent the token in wallets and UIs. /// Analogous to Unique's [`token_prefix`](up_data_structs::Collection). Cannot be changed. + #[pallet::call_index(0)] #[pallet::weight(>::create_collection())] pub fn create_collection( origin: OriginFor, @@ -428,6 +431,7 @@ pub mod pallet { /// # Arguments: /// - `origin`: sender of the transaction /// - `collection_id`: RMRK ID of the collection to destroy. + #[pallet::call_index(1)] #[pallet::weight(>::destroy_collection())] pub fn destroy_collection( origin: OriginFor, @@ -462,6 +466,7 @@ pub mod pallet { /// - `origin`: sender of the transaction /// - `collection_id`: RMRK collection ID to change the issuer of. /// - `new_issuer`: Collection's new issuer. + #[pallet::call_index(2)] #[pallet::weight(>::change_collection_issuer())] pub fn change_collection_issuer( origin: OriginFor, @@ -499,6 +504,7 @@ pub mod pallet { /// # Arguments: /// - `origin`: sender of the transaction /// - `collection_id`: RMRK ID of the collection to lock. + #[pallet::call_index(3)] #[pallet::weight(>::lock_collection())] pub fn lock_collection( origin: OriginFor, @@ -543,6 +549,7 @@ pub mod pallet { /// - `metadata`: Arbitrary data about an NFT, e.g. IPFS hash. Cannot be changed. /// - `transferable`: Can this NFT be transferred? Cannot be changed. /// - `resources`: Resource data to be added to the NFT immediately after minting. + #[pallet::call_index(4)] #[pallet::weight(>::mint_nft(resources.as_ref().map(|r| r.len() as u32).unwrap_or(0)))] pub fn mint_nft( origin: OriginFor, @@ -626,6 +633,7 @@ pub mod pallet { /// - `max_burns`: Maximum number of tokens to burn, assuming nesting. The transaction /// is reverted if there are more tokens to burn in the nesting tree than this number. /// This is primarily a mechanism of transaction weight control. + #[pallet::call_index(5)] #[pallet::weight(>::burn_nft(*max_burns))] pub fn burn_nft( origin: OriginFor, @@ -673,6 +681,7 @@ pub mod pallet { /// - `rmrk_collection_id`: RMRK ID of the collection of the NFT to be transferred. /// - `rmrk_nft_id`: ID of the NFT to be transferred. /// - `new_owner`: New owner of the nft which can be either an account or a NFT. + #[pallet::call_index(6)] #[pallet::weight(>::send())] pub fn send( origin: OriginFor, @@ -798,6 +807,7 @@ pub mod pallet { /// - `rmrk_nft_id`: ID of the NFT to be accepted. /// - `new_owner`: Either the sender's account ID or a sender-owned NFT, /// whichever the accepted NFT was sent to. + #[pallet::call_index(7)] #[pallet::weight(>::accept_nft())] pub fn accept_nft( origin: OriginFor, @@ -888,6 +898,7 @@ pub mod pallet { /// - `origin`: sender of the transaction /// - `rmrk_collection_id`: RMRK ID of the NFT to be rejected. /// - `rmrk_nft_id`: ID of the NFT to be rejected. + #[pallet::call_index(8)] #[pallet::weight(>::reject_nft())] pub fn reject_nft( origin: OriginFor, @@ -955,6 +966,7 @@ pub mod pallet { /// - `rmrk_nft_id`: ID of the NFT with a pending resource to be accepted. /// - `resource_id`: ID of the newly created pending resource. /// accept the addition of a new resource to an existing NFT + #[pallet::call_index(9)] #[pallet::weight(>::accept_resource())] pub fn accept_resource( origin: OriginFor, @@ -1009,6 +1021,7 @@ pub mod pallet { /// - `rmrk_collection_id`: RMRK collection ID of the NFT. /// - `rmrk_nft_id`: ID of the NFT with a resource to be removed. /// - `resource_id`: ID of the removal-pending resource. + #[pallet::call_index(10)] #[pallet::weight(>::accept_resource_removal())] pub fn accept_resource_removal( origin: OriginFor, @@ -1090,6 +1103,7 @@ pub mod pallet { /// - `maybe_nft_id`: Optional ID of the NFT. If left empty, then the property is set for the collection. /// - `key`: Key of the custom property to be referenced by. /// - `value`: Value of the custom property to be stored. + #[pallet::call_index(11)] #[pallet::weight(>::set_property())] pub fn set_property( origin: OriginFor, @@ -1163,6 +1177,7 @@ pub mod pallet { /// - `rmrk_collection_id`: RMRK collection ID of the NFT. /// - `rmrk_nft_id`: ID of the NFT to rearrange resource priorities for. /// - `priorities`: Ordered vector of resource IDs. + #[pallet::call_index(12)] #[pallet::weight(>::set_priority())] pub fn set_priority( origin: OriginFor, @@ -1214,6 +1229,7 @@ pub mod pallet { /// - `rmrk_collection_id`: RMRK collection ID of the NFT. /// - `nft_id`: ID of the NFT to assign a resource to. /// - `resource`: Data of the resource to be created. + #[pallet::call_index(13)] #[pallet::weight(>::add_basic_resource())] pub fn add_basic_resource( origin: OriginFor, @@ -1256,6 +1272,7 @@ pub mod pallet { /// - `rmrk_collection_id`: RMRK collection ID of the NFT. /// - `nft_id`: ID of the NFT to assign a resource to. /// - `resource`: Data of the resource to be created. + #[pallet::call_index(14)] #[pallet::weight(>::add_composable_resource())] pub fn add_composable_resource( origin: OriginFor, @@ -1318,6 +1335,7 @@ pub mod pallet { /// - `rmrk_collection_id`: RMRK collection ID of the NFT. /// - `nft_id`: ID of the NFT to assign a resource to. /// - `resource`: Data of the resource to be created. + #[pallet::call_index(15)] #[pallet::weight(>::add_slot_resource())] pub fn add_slot_resource( origin: OriginFor, @@ -1359,6 +1377,7 @@ pub mod pallet { /// - `rmrk_collection_id`: RMRK ID of a collection to which the NFT making use of the resource belongs to. /// - `nft_id`: ID of the NFT with a resource to be removed. /// - `resource_id`: ID of the resource to be removed. + #[pallet::call_index(16)] #[pallet::weight(>::remove_resource())] pub fn remove_resource( origin: OriginFor, diff --git a/pallets/proxy-rmrk-equip/Cargo.toml b/pallets/proxy-rmrk-equip/Cargo.toml index c786411b6a..3f66eb7353 100644 --- a/pallets/proxy-rmrk-equip/Cargo.toml +++ b/pallets/proxy-rmrk-equip/Cargo.toml @@ -11,16 +11,16 @@ package = 'parity-scale-codec' version = '3.1.2' [dependencies] -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } pallet-common = { default-features = false, path = '../common' } pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" } up-data-structs = { default-features = false, path = '../../primitives/data-structs' } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } rmrk-traits = { default-features = false, path = "../../primitives/rmrk-traits" } scale-info = { version = "2.0.1", default-features = false, features = [ "derive", diff --git a/pallets/proxy-rmrk-equip/src/lib.rs b/pallets/proxy-rmrk-equip/src/lib.rs index 82b2719626..457e19e066 100644 --- a/pallets/proxy-rmrk-equip/src/lib.rs +++ b/pallets/proxy-rmrk-equip/src/lib.rs @@ -231,6 +231,7 @@ pub mod pallet { /// - `symbol`: Arbitrary client-chosen symbol. /// - `parts`: Array of Fixed and Slot Parts composing the Base, /// confined in length by [`RmrkPartsLimit`](up_data_structs::RmrkPartsLimit). + #[pallet::call_index(0)] #[pallet::weight(>::create_base(parts.len() as u32))] pub fn create_base( origin: OriginFor, @@ -309,6 +310,7 @@ pub mod pallet { /// - `key`: Arbitrary BoundedString, defined by client. /// - `value`: Arbitrary BoundedString, defined by client. /// - `inherit`: Optional bool. + #[pallet::call_index(1)] #[pallet::weight(>::theme_add(theme.properties.len() as u32))] pub fn theme_add( origin: OriginFor, @@ -370,6 +372,7 @@ pub mod pallet { /// - `base_id`: Base containing the Slot Part to be updated. /// - `slot_id`: Slot Part whose Equippable List is being updated . /// - `equippables`: List of equippables that will override the current Equippables list. + #[pallet::call_index(2)] #[pallet::weight(>::equippable())] pub fn equippable( origin: OriginFor, diff --git a/pallets/refungible/CHANGELOG.md b/pallets/refungible/CHANGELOG.md index 3041556898..22f7a92902 100644 --- a/pallets/refungible/CHANGELOG.md +++ b/pallets/refungible/CHANGELOG.md @@ -2,12 +2,60 @@ All notable changes to this project will be documented in this file. + + +## [0.2.11] - 2022-12-16 + +### Added + +- The function `tokenPropertyPermissions` and `setTokenPropertyPermissions` to `TokenProperties` interface. + +### Changed + +- Hide `setTokenPropertyPermission` function in `TokenProperties` interface. + +## [0.2.10] - 2022-12-01 + +### Added + +- The functions `mintCross` to `ERC721UniqueExtensions` interface. + +## [0.2.9] - 2022-11-18 + +### Added + +- The functions `description`, `crossOwnerOf`, `tokenProperties` to `ERC721UniqueExtensions` interface. + +## [0.2.8] - 2022-11-14 + +### Changed + +- Added `transfer_cross` in eth functions. + +## [v0.2.7] - 2022-11-11 + +### Changed + +- Added `delete_properties` in eth functions. The `delete_property` function is now deprecated. + +## [v0.2.6] - 2022-11-02 + +### Changed + +- Use named structure `EthCrossAccount` in eth functions. + +## [v0.2.5] - 2022-20-10 + +### Change + +- Added `set_properties` method for `TokenProperties` interface. + ## [v0.2.4] - 2022-08-24 ### Change - - Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`. - +- Add bound `AsRef<[u8; 32]>` to `T::CrossAccountId`. + ## [v0.2.3] 2022-08-16 ### Other changes diff --git a/pallets/refungible/Cargo.toml b/pallets/refungible/Cargo.toml index 93de8f9923..b36bf447a9 100644 --- a/pallets/refungible/Cargo.toml +++ b/pallets/refungible/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-refungible" -version = "0.2.4" +version = "0.2.11" license = "GPLv3" edition = "2021" @@ -11,22 +11,24 @@ package = 'parity-scale-codec' version = '3.1.2' [dependencies] -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } evm-coder = { default-features = false, path = '../../crates/evm-coder' } pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' } pallet-common = { default-features = false, path = '../common' } pallet-structure = { default-features = false, path = '../structure' } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } struct-versioning = { path = "../../crates/struct-versioning" } up-data-structs = { default-features = false, path = '../../primitives/data-structs' } -ethereum = { version = "0.12.0", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive",] } +ethereum = { version = "0.14.0", default-features = false } +scale-info = { version = "2.0.1", default-features = false, features = [ + "derive", +] } derivative = { version = "2.2.0", features = ["use_core"] } [features] @@ -52,3 +54,4 @@ runtime-benchmarks = [ 'up-data-structs/runtime-benchmarks', ] try-runtime = ["frame-support/try-runtime"] +stubgen = ["evm-coder/stubgen", "pallet-common/stubgen"] diff --git a/pallets/refungible/src/benchmarking.rs b/pallets/refungible/src/benchmarking.rs index aa2f1e1607..8f926c7a4e 100644 --- a/pallets/refungible/src/benchmarking.rs +++ b/pallets/refungible/src/benchmarking.rs @@ -22,21 +22,17 @@ use core::iter::IntoIterator; use frame_benchmarking::{benchmarks, account}; use pallet_common::{ bench_init, - benchmarking::{create_collection_raw, property_key, property_value, create_data}, + benchmarking::{create_collection_raw, property_key, property_value}, }; -use sp_core::H160; use sp_std::prelude::*; -use up_data_structs::{ - CollectionMode, MAX_ITEMS_PER_BATCH, MAX_PROPERTIES_PER_ITEM, CUSTOM_DATA_LIMIT, - budget::Unlimited, -}; +use up_data_structs::{CollectionMode, MAX_ITEMS_PER_BATCH, MAX_PROPERTIES_PER_ITEM, budget::Unlimited}; const SEED: u32 = 1; -fn create_max_item_data( - users: impl IntoIterator, -) -> CreateItemData { - CreateItemData { +fn create_max_item_data( + users: impl IntoIterator, +) -> CreateItemData { + CreateItemData:: { users: users .into_iter() .collect::>() @@ -51,7 +47,7 @@ fn create_max_item( sender: &T::CrossAccountId, users: impl IntoIterator, ) -> Result { - let data: CreateItemData = create_max_item_data(users); + let data: CreateItemData = create_max_item_data::(users); >::create_item(&collection, sender, data, &Unlimited)?; Ok(TokenId(>::get(&collection.id))) } @@ -83,7 +79,7 @@ benchmarks! { owner: sub; collection: collection(owner); sender: cross_from_sub(owner); to: cross_sub; }; - let data = (0..b).map(|_| create_max_item_data([(to.clone(), 200)])).collect(); + let data = (0..b).map(|_| create_max_item_data::([(to.clone(), 200)])).collect(); }: {>::create_multiple_items(&collection, &sender, data, &Unlimited)?} create_multiple_items_ex_multiple_items { @@ -94,7 +90,7 @@ benchmarks! { }; let data = (0..b).map(|t| { bench_init!(to: cross_sub(t);); - create_max_item_data([(to, 200)]) + create_max_item_data::([(to, 200)]) }).collect(); }: {>::create_multiple_items(&collection, &sender, data, &Unlimited)?} @@ -104,7 +100,7 @@ benchmarks! { owner: sub; collection: collection(owner); sender: cross_from_sub(owner); }; - let data = vec![create_max_item_data((0..b).map(|u| { + let data = vec![create_max_item_data::((0..b).map(|u| { bench_init!(to: cross_sub(u);); (to, 200) }))].try_into().unwrap(); @@ -291,6 +287,20 @@ benchmarks! { let item = create_max_item(&collection, &sender, [(owner.clone(), 100)])?; }: {>::token_owner(collection.id, item)} + set_allowance_for_all { + bench_init!{ + owner: sub; collection: collection(owner); owner: cross_from_sub; + operator: cross_sub; + }; + }: {>::set_allowance_for_all(&collection, &owner, &operator, true)?} + + allowance_for_all { + bench_init!{ + owner: sub; collection: collection(owner); owner: cross_from_sub; + operator: cross_sub; + }; + }: {>::allowance_for_all(&collection, &owner, &operator)} + repair_item { bench_init!{ owner: sub; collection: collection(owner); diff --git a/pallets/refungible/src/common.rs b/pallets/refungible/src/common.rs index 4120bbbcd3..6abd061a16 100644 --- a/pallets/refungible/src/common.rs +++ b/pallets/refungible/src/common.rs @@ -153,7 +153,11 @@ impl CommonWeightInfo for CommonWeights { >::token_owner() } - fn repair_item() -> Weight { + fn set_allowance_for_all() -> Weight { + >::set_allowance_for_all() + } + + fn force_repair_item() -> Weight { >::repair_item() } } @@ -161,9 +165,9 @@ impl CommonWeightInfo for CommonWeights { fn map_create_data( data: up_data_structs::CreateItemData, to: &T::CrossAccountId, -) -> Result, DispatchError> { +) -> Result, DispatchError> { match data { - up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateItemData { + up_data_structs::CreateItemData::ReFungible(data) => Ok(CreateItemData:: { users: { let mut out = BTreeMap::new(); out.insert(to.clone(), data.pieces); @@ -226,7 +230,7 @@ impl CommonCollectionOperations for RefungibleHandle { CreateItemExData::RefungibleMultipleOwners(CreateRefungibleExMultipleOwners { users, properties, - }) => vec![CreateItemData { users, properties }], + }) => vec![CreateItemData:: { users, properties }], CreateItemExData::RefungibleMultipleItems(r) => r .into_inner() .into_iter() @@ -235,7 +239,7 @@ impl CommonCollectionOperations for RefungibleHandle { user, pieces, properties, - }| CreateItemData { + }| CreateItemData:: { users: BTreeMap::from([(user, pieces)]) .try_into() .expect("limit >= 1"), @@ -521,10 +525,26 @@ impl CommonCollectionOperations for RefungibleHandle { >::total_pieces(self.id, token) } + fn set_allowance_for_all( + &self, + owner: T::CrossAccountId, + operator: T::CrossAccountId, + approve: bool, + ) -> DispatchResultWithPostInfo { + with_weight( + >::set_allowance_for_all(self, &owner, &operator, approve), + >::set_allowance_for_all(), + ) + } + + fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool { + >::allowance_for_all(self, &owner, &operator) + } + fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo { with_weight( >::repair_item(self, token), - >::repair_item(), + >::force_repair_item(), ) } } diff --git a/pallets/refungible/src/erc.rs b/pallets/refungible/src/erc.rs index 4b0b3f0e6f..c65c5f801c 100644 --- a/pallets/refungible/src/erc.rs +++ b/pallets/refungible/src/erc.rs @@ -25,17 +25,21 @@ use core::{ char::{REPLACEMENT_CHARACTER, decode_utf16}, convert::TryInto, }; -use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight}; +use evm_coder::{ + abi::AbiType, ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, + weight, +}; use frame_support::{BoundedBTreeMap, BoundedVec}; use pallet_common::{ - CollectionHandle, CollectionPropertyPermissions, - erc::{CommonEvmHandler, CollectionCall, static_property::key}, + CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations, Error as CommonError, + erc::{CommonEvmHandler, CollectionCall, static_property::key}, + eth, }; use pallet_evm::{account::CrossAccountId, PrecompileHandle}; use pallet_evm_coder_substrate::{call, dispatch_to_evm}; use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _}; -use sp_core::H160; +use sp_core::{H160, Get}; use sp_std::{collections::btree_map::BTreeMap, vec::Vec, vec}; use up_data_structs::{ CollectionId, CollectionPropertiesVec, mapping::TokenAddressMapping, Property, PropertyKey, @@ -58,6 +62,8 @@ impl RefungibleHandle { /// @param isMutable Permission to mutate property. /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable. /// @param tokenOwner Permission to mutate property by token owner if property is mutable. + #[weight(>::set_token_property_permissions(1))] + #[solidity(hide)] fn set_token_property_permission( &mut self, caller: caller, @@ -84,11 +90,38 @@ impl RefungibleHandle { .map_err(dispatch_to_evm::) } + /// @notice Set permissions for token property. + /// @dev Throws error if `msg.sender` is not admin or owner of the collection. + /// @param permissions Permissions for keys. + #[weight(>::set_token_property_permissions(permissions.len() as u32))] + fn set_token_property_permissions( + &mut self, + caller: caller, + permissions: Vec, + ) -> Result<()> { + let caller = T::CrossAccountId::from_eth(caller); + let perms = eth::TokenPropertyPermission::into_property_key_permissions(permissions)?; + + >::set_token_property_permissions(self, &caller, perms) + .map_err(dispatch_to_evm::) + } + + /// @notice Get permissions for token properties. + fn token_property_permissions(&self) -> Result> { + let perms = >::token_property_permission(self.id); + Ok(perms + .into_iter() + .map(eth::TokenPropertyPermission::from) + .collect()) + } + /// @notice Set token property value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. /// @param key Property key. /// @param value Property value. + #[solidity(hide)] + #[weight(>::set_token_properties(1))] fn set_property( &mut self, caller: caller, @@ -101,7 +134,7 @@ impl RefungibleHandle { let key = >::from(key) .try_into() .map_err(|_| "key too long")?; - let value = value.try_into().map_err(|_| "value too long")?; + let value = value.0.try_into().map_err(|_| "value too long")?; let nesting_budget = self .recorder @@ -117,10 +150,46 @@ impl RefungibleHandle { .map_err(dispatch_to_evm::) } + /// @notice Set token properties value. + /// @dev Throws error if `msg.sender` has no permission to edit the property. + /// @param tokenId ID of the token. + /// @param properties settable properties + #[weight(>::set_token_properties(properties.len() as u32))] + fn set_properties( + &mut self, + caller: caller, + token_id: uint256, + properties: Vec, + ) -> Result<()> { + let caller = T::CrossAccountId::from_eth(caller); + let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; + + let nesting_budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + let properties = properties + .into_iter() + .map(eth::Property::try_into) + .collect::>>()?; + + >::set_token_properties( + self, + &caller, + TokenId(token_id), + properties.into_iter(), + false, + &nesting_budget, + ) + .map_err(dispatch_to_evm::) + } + /// @notice Delete token property value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. /// @param key Property key. + #[solidity(hide)] + #[weight(>::delete_token_properties(1))] fn delete_property(&mut self, token_id: uint256, caller: caller, key: string) -> Result<()> { let caller = T::CrossAccountId::from_eth(caller); let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; @@ -136,6 +205,38 @@ impl RefungibleHandle { .map_err(dispatch_to_evm::) } + /// @notice Delete token properties value. + /// @dev Throws error if `msg.sender` has no permission to edit the property. + /// @param tokenId ID of the token. + /// @param keys Properties key. + #[weight(>::delete_token_properties(keys.len() as u32))] + fn delete_properties( + &mut self, + token_id: uint256, + caller: caller, + keys: Vec, + ) -> Result<()> { + let caller = T::CrossAccountId::from_eth(caller); + let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; + let keys = keys + .into_iter() + .map(|k| Ok(>::from(k).try_into().map_err(|_| "key too long")?)) + .collect::>>()?; + + let nesting_budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + >::delete_token_properties( + self, + &caller, + TokenId(token_id), + keys.into_iter(), + &nesting_budget, + ) + .map_err(dispatch_to_evm::) + } + /// @notice Get token property value. /// @dev Throws error if key not found /// @param tokenId ID of the token. @@ -150,7 +251,7 @@ impl RefungibleHandle { let props = >::get((self.id, token_id)); let prop = props.get(&key).ok_or("key not found")?; - Ok(prop.to_vec()) + Ok(prop.to_vec().into()) } } @@ -195,7 +296,10 @@ pub enum ERC721UniqueMintableEvents { } #[solidity_interface(name = ERC721Metadata)] -impl RefungibleHandle { +impl RefungibleHandle +where + T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>, +{ /// @notice A descriptive name for a collection of NFTs in this contract /// @dev real implementation of this function lies in `ERC721UniqueExtensions` #[solidity(hide, rename_selector = "name")] @@ -380,15 +484,23 @@ impl RefungibleHandle { Err("not implemented".into()) } - /// @dev Not implemented + /// @notice Sets or unsets the approval of a given operator. + /// The `operator` is allowed to transfer all token pieces of the `caller` on their behalf. + /// @param operator Operator + /// @param approved Should operator status be granted or revoked? + #[weight(>::set_allowance_for_all())] fn set_approval_for_all( &mut self, - _caller: caller, - _operator: address, - _approved: bool, + caller: caller, + operator: address, + approved: bool, ) -> Result { - // TODO: Not implemetable - Err("not implemented".into()) + let caller = T::CrossAccountId::from_eth(caller); + let operator = T::CrossAccountId::from_eth(operator); + + >::set_allowance_for_all(self, &caller, &operator, approved) + .map_err(dispatch_to_evm::)?; + Ok(()) } /// @dev Not implemented @@ -397,10 +509,18 @@ impl RefungibleHandle { Err("not implemented".into()) } - /// @dev Not implemented - fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result
{ - // TODO: Not implemetable - Err("not implemented".into()) + /// @notice Tells whether the given `owner` approves the `operator`. + #[weight(>::allowance_for_all())] + fn is_approved_for_all(&self, owner: address, operator: address) -> Result { + let owner = T::CrossAccountId::from_eth(owner); + let operator = T::CrossAccountId::from_eth(operator); + + Ok(>::allowance_for_all(self, &owner, &operator)) + } + + /// @notice Returns collection helper contract address + fn collection_helper_address(&self) -> Result
{ + Ok(T::ContractAddress::get()) } } @@ -463,7 +583,7 @@ impl RefungibleHandle { Ok(false) } - /// @notice Function to mint token. + /// @notice Function to mint a token. /// @param to The new owner /// @return uint256 The id of the newly minted token #[weight(>::create_item())] @@ -476,7 +596,7 @@ impl RefungibleHandle { Ok(token_id) } - /// @notice Function to mint token. + /// @notice Function to mint a token. /// @dev `tokenId` should be obtained with `nextTokenId` method, /// unlike standard, you can't specify it manually /// @param to The new owner @@ -507,7 +627,7 @@ impl RefungibleHandle { >::create_item( self, &caller, - CreateItemData:: { + CreateItemData:: { users, properties: CollectionPropertiesVec::default(), }, @@ -593,7 +713,7 @@ impl RefungibleHandle { >::create_item( self, &caller, - CreateItemData:: { users, properties }, + CreateItemData:: { users, properties }, &budget, ) .map_err(dispatch_to_evm::)?; @@ -639,7 +759,10 @@ fn get_token_permission( /// @title Unique extensions for ERC721. #[solidity_interface(name = ERC721UniqueExtensions)] -impl RefungibleHandle { +impl RefungibleHandle +where + T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>, +{ /// @notice A descriptive name for a collection of NFTs in this contract fn name(&self) -> Result { Ok(decode_utf16(self.name.iter().copied()) @@ -652,6 +775,46 @@ impl RefungibleHandle { Ok(string::from_utf8_lossy(&self.token_prefix).into()) } + /// @notice A description for the collection. + fn description(&self) -> Result { + Ok(decode_utf16(self.description.iter().copied()) + .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) + .collect::()) + } + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + fn cross_owner_of(&self, token_id: uint256) -> Result { + Self::token_owner(&self, token_id.try_into()?) + .map(|o| eth::CrossAddress::from_sub_cross_account::(&o)) + .ok_or(Error::Revert("key too large".into())) + } + + /// Returns the token properties. + /// + /// @param tokenId Id for the token. + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + fn properties(&self, token_id: uint256, keys: Vec) -> Result> { + let keys = keys + .into_iter() + .map(|key| { + >::from(key) + .try_into() + .map_err(|_| Error::Revert("key too large".into())) + }) + .collect::>>()?; + + >::token_properties( + &self, + token_id.try_into()?, + if keys.is_empty() { None } else { Some(keys) }, + ) + .into_iter() + .map(eth::Property::try_from) + .collect::>>() + } /// @notice Transfer ownership of an RFT /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` /// is the zero address. Throws if `tokenId` is not a valid RFT. @@ -667,14 +830,72 @@ impl RefungibleHandle { .recorder .weight_calls_budget(>::find_parent()); - let balance = balance(&self, token, &caller)?; - ensure_single_owner(&self, token, balance)?; + let balance = balance(self, token, &caller)?; + ensure_single_owner(self, token, balance)?; + + >::transfer(self, &caller, &to, token, balance, &budget) + .map_err(dispatch_to_evm::)?; + Ok(()) + } + + /// @notice Transfer ownership of an RFT + /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` + /// is the zero address. Throws if `tokenId` is not a valid RFT. + /// Throws if RFT pieces have multiple owners. + /// @param to The new owner + /// @param tokenId The RFT to transfer + #[weight(>::transfer_creating_removing())] + fn transfer_cross( + &mut self, + caller: caller, + to: eth::CrossAddress, + token_id: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let to = to.into_sub_cross_account::()?; + let token = token_id.try_into()?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + let balance = balance(self, token, &caller)?; + ensure_single_owner(self, token, balance)?; >::transfer(self, &caller, &to, token, balance, &budget) .map_err(dispatch_to_evm::)?; Ok(()) } + /// @notice Transfer ownership of an RFT + /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` + /// is the zero address. Throws if `tokenId` is not a valid RFT. + /// Throws if RFT pieces have multiple owners. + /// @param to The new owner + /// @param tokenId The RFT to transfer + #[weight(>::transfer_creating_removing())] + fn transfer_from_cross( + &mut self, + caller: caller, + from: eth::CrossAddress, + to: eth::CrossAddress, + token_id: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let from = from.into_sub_cross_account::()?; + let to = to.into_sub_cross_account::()?; + let token_id = token_id.try_into()?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + let balance = balance(self, token_id, &from)?; + ensure_single_owner(self, token_id, balance)?; + + Pallet::::transfer_from(self, &caller, &from, &to, token_id, balance, &budget) + .map_err(dispatch_to_evm::)?; + Ok(()) + } + /// @notice Burns a specific ERC721 token. /// @dev Throws unless `msg.sender` is the current owner or an authorized /// operator for this RFT. Throws if `from` is not the current owner. Throws @@ -682,6 +903,7 @@ impl RefungibleHandle { /// Throws if RFT pieces have multiple owners. /// @param from The current owner of the RFT /// @param tokenId The RFT to transfer + #[solidity(hide)] #[weight(>::burn_from())] fn burn_from(&mut self, caller: caller, from: address, token_id: uint256) -> Result { let caller = T::CrossAccountId::from_eth(caller); @@ -691,8 +913,37 @@ impl RefungibleHandle { .recorder .weight_calls_budget(>::find_parent()); - let balance = balance(&self, token, &caller)?; - ensure_single_owner(&self, token, balance)?; + let balance = balance(self, token, &from)?; + ensure_single_owner(self, token, balance)?; + + >::burn_from(self, &caller, &from, token, balance, &budget) + .map_err(dispatch_to_evm::)?; + Ok(()) + } + + /// @notice Burns a specific ERC721 token. + /// @dev Throws unless `msg.sender` is the current owner or an authorized + /// operator for this RFT. Throws if `from` is not the current owner. Throws + /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT. + /// Throws if RFT pieces have multiple owners. + /// @param from The current owner of the RFT + /// @param tokenId The RFT to transfer + #[weight(>::burn_from())] + fn burn_from_cross( + &mut self, + caller: caller, + from: eth::CrossAddress, + token_id: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let from = from.into_sub_cross_account::()?; + let token = token_id.try_into()?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + let balance = balance(self, token, &from)?; + ensure_single_owner(self, token, balance)?; >::burn_from(self, &caller, &from, token, balance, &budget) .map_err(dispatch_to_evm::)?; @@ -738,7 +989,7 @@ impl RefungibleHandle { .collect::>() .try_into() .unwrap(); - let create_item_data = CreateItemData:: { + let create_item_data = CreateItemData:: { users, properties: CollectionPropertiesVec::default(), }; @@ -798,7 +1049,7 @@ impl RefungibleHandle { }) .map_err(|e| Error::Revert(alloc::format!("Can't add property: {:?}", e)))?; - let create_item_data = CreateItemData:: { + let create_item_data = CreateItemData:: { users: users.clone(), properties, }; @@ -810,6 +1061,52 @@ impl RefungibleHandle { Ok(true) } + /// @notice Function to mint a token. + /// @param to The new owner crossAccountId + /// @param properties Properties of minted token + /// @return uint256 The id of the newly minted token + #[weight(>::create_item())] + fn mint_cross( + &mut self, + caller: caller, + to: eth::CrossAddress, + properties: Vec, + ) -> Result { + let token_id = >::get(self.id) + .checked_add(1) + .ok_or("item id overflow")?; + + let to = to.into_sub_cross_account::()?; + + let properties = properties + .into_iter() + .map(eth::Property::try_into) + .collect::>>()? + .try_into() + .map_err(|_| Error::Revert(alloc::format!("too many properties")))?; + + let caller = T::CrossAccountId::from_eth(caller); + + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + let users = [(to, 1)] + .into_iter() + .collect::>() + .try_into() + .unwrap(); + >::create_item( + self, + &caller, + CreateItemData:: { users, properties }, + &budget, + ) + .map_err(dispatch_to_evm::)?; + + Ok(token_id.into()) + } + /// Returns EVM address for refungible token /// /// @param token ID of the token diff --git a/pallets/refungible/src/erc_token.rs b/pallets/refungible/src/erc_token.rs index 5bc182e884..4ac4e15a75 100644 --- a/pallets/refungible/src/erc_token.rs +++ b/pallets/refungible/src/erc_token.rs @@ -19,17 +19,14 @@ //! Provides ERC-20 standart support implementation and EVM API for unique extensions for Refungible Pallet. //! Method implementations are mostly doing parameter conversion and calling Nonfungible Pallet methods. -extern crate alloc; - -#[cfg(not(feature = "std"))] -use alloc::format; - use core::{ char::{REPLACEMENT_CHARACTER, decode_utf16}, convert::TryInto, ops::Deref, }; -use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight}; +use evm_coder::{ + abi::AbiType, ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight, +}; use pallet_common::{ CommonWeightInfo, erc::{CommonEvmHandler, PrecompileResult}, @@ -46,6 +43,9 @@ use crate::{ TotalSupply, weights::WeightInfo, }; +/// Refungible token handle contains information about token's collection and id +/// +/// RefungibleTokenHandle doesn't check token's existance upon creation pub struct RefungibleTokenHandle(pub RefungibleHandle, pub TokenId); #[solidity_interface(name = ERC1633)] @@ -197,7 +197,10 @@ impl RefungibleTokenHandle { } #[solidity_interface(name = ERC20UniqueExtensions)] -impl RefungibleTokenHandle { +impl RefungibleTokenHandle +where + T::AccountId: From<[u8; 32]>, +{ /// @dev Function that burns an amount of the token of a given account, /// deducting from the sender's allowance for said account. /// @param from The account whose tokens will be burnt. @@ -216,6 +219,51 @@ impl RefungibleTokenHandle { Ok(true) } + /// @dev Function that burns an amount of the token of a given account, + /// deducting from the sender's allowance for said account. + /// @param from The account whose tokens will be burnt. + /// @param amount The amount that will be burnt. + #[weight(>::burn_from())] + fn burn_from_cross( + &mut self, + caller: caller, + from: pallet_common::eth::CrossAddress, + amount: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let from = from.into_sub_cross_account::()?; + let amount = amount.try_into().map_err(|_| "amount overflow")?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + >::burn_from(self, &caller, &from, self.1, amount, &budget) + .map_err(dispatch_to_evm::)?; + Ok(true) + } + + /// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`. + /// Beware that changing an allowance with this method brings the risk that someone may use both the old + /// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this + /// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: + /// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + /// @param spender The crossaccount which will spend the funds. + /// @param amount The amount of tokens to be spent. + #[weight(>::approve())] + fn approve_cross( + &mut self, + caller: caller, + spender: pallet_common::eth::CrossAddress, + amount: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let spender = spender.into_sub_cross_account::()?; + let amount = amount.try_into().map_err(|_| "amount overflow")?; + + >::set_allowance(self, &caller, &spender, self.1, amount) + .map_err(dispatch_to_evm::)?; + Ok(true) + } /// @dev Function that changes total amount of the tokens. /// Throws if `msg.sender` doesn't owns all of the tokens. /// @param amount New total amount of the tokens. @@ -227,6 +275,53 @@ impl RefungibleTokenHandle { >::repartition(self, &caller, self.1, amount).map_err(dispatch_to_evm::)?; Ok(true) } + + /// @dev Transfer token for a specified address + /// @param to The crossaccount to transfer to. + /// @param amount The amount to be transferred. + #[weight(>::transfer())] + fn transfer_cross( + &mut self, + caller: caller, + to: pallet_common::eth::CrossAddress, + amount: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let to = to.into_sub_cross_account::()?; + let amount = amount.try_into().map_err(|_| "amount overflow")?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + >::transfer(self, &caller, &to, self.1, amount, &budget) + .map_err(dispatch_to_evm::)?; + Ok(true) + } + + /// @dev Transfer tokens from one address to another + /// @param from The address which you want to send tokens from + /// @param to The address which you want to transfer to + /// @param amount the amount of tokens to be transferred + #[weight(>::transfer_from())] + fn transfer_from_cross( + &mut self, + caller: caller, + from: pallet_common::eth::CrossAddress, + to: pallet_common::eth::CrossAddress, + amount: uint256, + ) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + let from = from.into_sub_cross_account::()?; + let to = to.into_sub_cross_account::()?; + let amount = amount.try_into().map_err(|_| "amount overflow")?; + let budget = self + .recorder + .weight_calls_budget(>::find_parent()); + + >::transfer_from(self, &caller, &from, &to, self.1, amount, &budget) + .map_err(dispatch_to_evm::)?; + Ok(true) + } } impl RefungibleTokenHandle { diff --git a/pallets/refungible/src/lib.rs b/pallets/refungible/src/lib.rs index a3fdc56244..0193a1552d 100644 --- a/pallets/refungible/src/lib.rs +++ b/pallets/refungible/src/lib.rs @@ -90,30 +90,24 @@ use crate::erc_token::ERC20Events; use crate::erc::ERC721Events; -use codec::{Encode, Decode, MaxEncodedLen}; use core::ops::Deref; -use derivative::Derivative; use evm_coder::ToLog; -use frame_support::{ - BoundedBTreeMap, BoundedVec, ensure, fail, storage::with_transaction, transactional, - pallet_prelude::ConstU32, -}; +use frame_support::{ensure, fail, storage::with_transaction, transactional}; use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm}; use pallet_evm_coder_substrate::WithRecorder; use pallet_common::{ CommonCollectionOperations, Error as CommonError, eth::collection_id_to_address, - Event as CommonEvent, Pallet as PalletCommon, + Event as CommonEvent, Pallet as PalletCommon, erc::CollectionHelpersEvents, }; use pallet_structure::Pallet as PalletStructure; -use scale_info::TypeInfo; -use sp_core::H160; +use sp_core::{Get, H160}; use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome}; use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap}; use up_data_structs::{ - AccessMode, budget::Budget, CollectionId, CollectionFlags, CollectionPropertiesVec, - CreateCollectionData, CustomDataLimit, mapping::TokenAddressMapping, MAX_ITEMS_PER_BATCH, - MAX_REFUNGIBLE_PIECES, Property, PropertyKey, PropertyKeyPermission, PropertyPermission, - PropertyScope, PropertyValue, TokenId, TrySetProperty, + AccessMode, budget::Budget, CollectionId, CollectionFlags, CreateCollectionData, + mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, Property, PropertyKey, + PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue, TokenId, + TrySetProperty, PropertiesPermissionMap, CreateRefungibleExMultipleOwners, }; pub use pallet::*; @@ -124,27 +118,10 @@ pub mod erc; pub mod erc_token; pub mod weights; -#[derive(Derivative, Clone)] -pub struct CreateItemData { - #[derivative(Debug(format_with = "bounded::map_debug"))] - pub users: BoundedBTreeMap>, - #[derivative(Debug(format_with = "bounded::vec_debug"))] - pub properties: CollectionPropertiesVec, -} +pub type CreateItemData = + CreateRefungibleExMultipleOwners<::CrossAccountId>; pub(crate) type SelfWeightOf = ::WeightInfo; -/// Token data, stored independently from other data used to describe it -/// for the convenience of database access. Notably contains the token metadata. -#[struct_versioning::versioned(version = 2, upper)] -#[derive(Encode, Decode, Default, TypeInfo, MaxEncodedLen)] -#[deprecated(since = "0.2.0", note = "ItemData is no more contains usefull data")] -pub struct ItemData { - pub const_data: BoundedVec, - - #[version(..2)] - pub variable_data: BoundedVec, -} - #[frame_support::pallet] pub mod pallet { use super::*; @@ -152,7 +129,6 @@ pub mod pallet { Blake2_128, Blake2_128Concat, Twox64Concat, pallet_prelude::*, storage::Key, traits::StorageVersion, }; - use frame_system::pallet_prelude::*; use up_data_structs::{CollectionId, TokenId}; use super::weights::WeightInfo; @@ -194,16 +170,6 @@ pub mod pallet { pub type TokensBurnt = StorageMap; - /// Token data, used to partially describe a token. - // TODO: remove - #[pallet::storage] - #[deprecated(since = "0.2.0", note = "ItemData is no more contains usefull data")] - pub type TokenData = StorageNMap< - Key = (Key, Key), - Value = ItemData, - QueryKind = ValueQuery, - >; - /// Amount of pieces a refungible token is split into. #[pallet::storage] #[pallet::getter(fn token_properties)] @@ -274,18 +240,17 @@ pub mod pallet { QueryKind = ValueQuery, >; - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_runtime_upgrade() -> Weight { - let storage_version = StorageVersion::get::>(); - if storage_version < StorageVersion::new(2) { - >::remove_all(None); - } - StorageVersion::new(2).put::>(); - - Weight::zero() - } - } + /// Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet. + #[pallet::storage] + pub type CollectionAllowance = StorageNMap< + Key = ( + Key, + Key, + Key, + ), + Value = bool, + QueryKind = ValueQuery, + >; } pub struct RefungibleHandle(pallet_common::CollectionHandle); @@ -637,6 +602,14 @@ impl Pallet { )); } } + + >::deposit_log( + CollectionHelpersEvents::TokenChanged { + collection_id: collection_id_to_address(collection.id), + token_id: token_id.into(), + } + .to_log(T::ContractAddress::get()), + ); } Ok(()) @@ -893,7 +866,7 @@ impl Pallet { pub fn create_multiple_items( collection: &RefungibleHandle, sender: &T::CrossAccountId, - data: Vec>, + data: Vec>, nesting_budget: &dyn Budget, ) -> DispatchResult { if !collection.is_owner_or_admin(sender) { @@ -1161,6 +1134,12 @@ impl Pallet { } let allowance = >::get((collection.id, token, from, &spender)).checked_sub(amount); + + // Allowance (if any) would be reduced if spender is also wallet operator + if >::get((collection.id, from, spender)) { + return Ok(allowance); + } + if allowance.is_none() { ensure!( collection.ignores_allowance(spender), @@ -1233,7 +1212,7 @@ impl Pallet { pub fn create_item( collection: &RefungibleHandle, sender: &T::CrossAccountId, - data: CreateItemData, + data: CreateItemData, nesting_budget: &dyn Budget, ) -> DispatchResult { Self::create_multiple_items(collection, sender, vec![data], nesting_budget) @@ -1352,6 +1331,10 @@ impl Pallet { >::set_token_property_permissions(collection, sender, property_permissions) } + pub fn token_property_permission(collection_id: CollectionId) -> PropertiesPermissionMap { + >::property_permissions(collection_id) + } + pub fn set_scoped_token_property_permissions( collection: &RefungibleHandle, sender: &T::CrossAccountId, @@ -1388,6 +1371,54 @@ impl Pallet { } } + /// Sets or unsets the approval of a given operator. + /// + /// The `operator` is allowed to transfer all token pieces of the `owner` on their behalf. + /// - `owner`: Token owner + /// - `operator`: Operator + /// - `approve`: Should operator status be granted or revoked? + pub fn set_allowance_for_all( + collection: &RefungibleHandle, + owner: &T::CrossAccountId, + operator: &T::CrossAccountId, + approve: bool, + ) -> DispatchResult { + if collection.permissions.access() == AccessMode::AllowList { + collection.check_allowlist(owner)?; + collection.check_allowlist(operator)?; + } + + >::ensure_correct_receiver(operator)?; + + // ========= + + >::insert((collection.id, owner, operator), approve); + >::deposit_log( + ERC721Events::ApprovalForAll { + owner: *owner.as_eth(), + operator: *operator.as_eth(), + approved: approve, + } + .to_log(collection_id_to_address(collection.id)), + ); + >::deposit_event(CommonEvent::ApprovedForAll( + collection.id, + owner.clone(), + operator.clone(), + approve, + )); + Ok(()) + } + + /// Tells whether the given `owner` approves the `operator`. + pub fn allowance_for_all( + collection: &RefungibleHandle, + owner: &T::CrossAccountId, + operator: &T::CrossAccountId, + ) -> bool { + >::get((collection.id, owner, operator)) + } + pub fn repair_item(collection: &RefungibleHandle, token: TokenId) -> DispatchResult { >::mutate((collection.id, token), |properties| { properties.recompute_consumed_space(); diff --git a/pallets/refungible/src/stubs/UniqueRefungible.raw b/pallets/refungible/src/stubs/UniqueRefungible.raw index c0925d1e31..fc608a8332 100644 Binary files a/pallets/refungible/src/stubs/UniqueRefungible.raw and b/pallets/refungible/src/stubs/UniqueRefungible.raw differ diff --git a/pallets/refungible/src/stubs/UniqueRefungible.sol b/pallets/refungible/src/stubs/UniqueRefungible.sol index 7471a4c9f5..db5ae5bc30 100644 --- a/pallets/refungible/src/stubs/UniqueRefungible.sol +++ b/pallets/refungible/src/stubs/UniqueRefungible.sol @@ -18,59 +18,96 @@ contract ERC165 is Dummy { } /// @title A contract that allows to set and delete token properties and change token property permissions. -/// @dev the ERC-165 identifier for this interface is 0x41369377 +/// @dev the ERC-165 identifier for this interface is 0xde0695c2 contract TokenProperties is Dummy, ERC165 { + // /// @notice Set permissions for token property. + // /// @dev Throws error if `msg.sender` is not admin or owner of the collection. + // /// @param key Property key. + // /// @param isMutable Permission to mutate property. + // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable. + // /// @param tokenOwner Permission to mutate property by token owner if property is mutable. + // /// @dev EVM selector for this function is: 0x222d97fa, + // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool) + // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) public { + // require(false, stub_error); + // key; + // isMutable; + // collectionAdmin; + // tokenOwner; + // dummy = 0; + // } + /// @notice Set permissions for token property. /// @dev Throws error if `msg.sender` is not admin or owner of the collection. - /// @param key Property key. - /// @param isMutable Permission to mutate property. - /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable. - /// @param tokenOwner Permission to mutate property by token owner if property is mutable. - /// @dev EVM selector for this function is: 0x222d97fa, - /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool) - function setTokenPropertyPermission( - string memory key, - bool isMutable, - bool collectionAdmin, - bool tokenOwner - ) public { + /// @param permissions Permissions for keys. + /// @dev EVM selector for this function is: 0xbd92983a, + /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[]) + function setTokenPropertyPermissions(TokenPropertyPermission[] memory permissions) public { require(false, stub_error); - key; - isMutable; - collectionAdmin; - tokenOwner; + permissions; dummy = 0; } - /// @notice Set token property value. + /// @notice Get permissions for token properties. + /// @dev EVM selector for this function is: 0xf23d7790, + /// or in textual repr: tokenPropertyPermissions() + function tokenPropertyPermissions() public view returns (TokenPropertyPermission[] memory) { + require(false, stub_error); + dummy; + return new TokenPropertyPermission[](0); + } + + // /// @notice Set token property value. + // /// @dev Throws error if `msg.sender` has no permission to edit the property. + // /// @param tokenId ID of the token. + // /// @param key Property key. + // /// @param value Property value. + // /// @dev EVM selector for this function is: 0x1752d67b, + // /// or in textual repr: setProperty(uint256,string,bytes) + // function setProperty(uint256 tokenId, string memory key, bytes memory value) public { + // require(false, stub_error); + // tokenId; + // key; + // value; + // dummy = 0; + // } + + /// @notice Set token properties value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. - /// @param key Property key. - /// @param value Property value. - /// @dev EVM selector for this function is: 0x1752d67b, - /// or in textual repr: setProperty(uint256,string,bytes) - function setProperty( - uint256 tokenId, - string memory key, - bytes memory value - ) public { + /// @param properties settable properties + /// @dev EVM selector for this function is: 0x14ed3a6e, + /// or in textual repr: setProperties(uint256,(string,bytes)[]) + function setProperties(uint256 tokenId, Property[] memory properties) public { require(false, stub_error); tokenId; - key; - value; + properties; dummy = 0; } - /// @notice Delete token property value. + // /// @notice Delete token property value. + // /// @dev Throws error if `msg.sender` has no permission to edit the property. + // /// @param tokenId ID of the token. + // /// @param key Property key. + // /// @dev EVM selector for this function is: 0x066111d1, + // /// or in textual repr: deleteProperty(uint256,string) + // function deleteProperty(uint256 tokenId, string memory key) public { + // require(false, stub_error); + // tokenId; + // key; + // dummy = 0; + // } + + /// @notice Delete token properties value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. - /// @param key Property key. - /// @dev EVM selector for this function is: 0x066111d1, - /// or in textual repr: deleteProperty(uint256,string) - function deleteProperty(uint256 tokenId, string memory key) public { + /// @param keys Properties key. + /// @dev EVM selector for this function is: 0xc472d371, + /// or in textual repr: deleteProperties(uint256,string[]) + function deleteProperties(uint256 tokenId, string[] memory keys) public { require(false, stub_error); tokenId; - key; + keys; dummy = 0; } @@ -90,30 +127,84 @@ contract TokenProperties is Dummy, ERC165 { } } +/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue). +struct Property { + string key; + bytes value; +} + +/// Ethereum representation of Token Property Permissions. +struct TokenPropertyPermission { + /// Token property key. + string key; + /// Token property permissions. + PropertyPermission[] permissions; +} + +/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value. +struct PropertyPermission { + /// TokenPermission field. + TokenPermissionField code; + /// TokenPermission value. + bool value; +} + +/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration. +enum TokenPermissionField { + /// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`] + Mutable, + /// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`] + TokenOwner, + /// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`] + CollectionAdmin +} + /// @title A contract that allows you to work with collections. -/// @dev the ERC-165 identifier for this interface is 0x62e22290 +/// @dev the ERC-165 identifier for this interface is 0x2a14cfd1 contract Collection is Dummy, ERC165 { - /// Set collection property. + // /// Set collection property. + // /// + // /// @param key Property key. + // /// @param value Propery value. + // /// @dev EVM selector for this function is: 0x2f073f66, + // /// or in textual repr: setCollectionProperty(string,bytes) + // function setCollectionProperty(string memory key, bytes memory value) public { + // require(false, stub_error); + // key; + // value; + // dummy = 0; + // } + + /// Set collection properties. /// - /// @param key Property key. - /// @param value Propery value. - /// @dev EVM selector for this function is: 0x2f073f66, - /// or in textual repr: setCollectionProperty(string,bytes) - function setCollectionProperty(string memory key, bytes memory value) public { + /// @param properties Vector of properties key/value pair. + /// @dev EVM selector for this function is: 0x50b26b2a, + /// or in textual repr: setCollectionProperties((string,bytes)[]) + function setCollectionProperties(Property[] memory properties) public { require(false, stub_error); - key; - value; + properties; dummy = 0; } - /// Delete collection property. + // /// Delete collection property. + // /// + // /// @param key Property key. + // /// @dev EVM selector for this function is: 0x7b7debce, + // /// or in textual repr: deleteCollectionProperty(string) + // function deleteCollectionProperty(string memory key) public { + // require(false, stub_error); + // key; + // dummy = 0; + // } + + /// Delete collection properties. /// - /// @param key Property key. - /// @dev EVM selector for this function is: 0x7b7debce, - /// or in textual repr: deleteCollectionProperty(string) - function deleteCollectionProperty(string memory key) public { + /// @param keys Properties keys. + /// @dev EVM selector for this function is: 0xee206ee3, + /// or in textual repr: deleteCollectionProperties(string[]) + function deleteCollectionProperties(string[] memory keys) public { require(false, stub_error); - key; + keys; dummy = 0; } @@ -132,14 +223,40 @@ contract Collection is Dummy, ERC165 { return hex""; } + /// Get collection properties. + /// + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0x285fb8e6, + /// or in textual repr: collectionProperties(string[]) + function collectionProperties(string[] memory keys) public view returns (Property[] memory) { + require(false, stub_error); + keys; + dummy; + return new Property[](0); + } + + // /// Set the sponsor of the collection. + // /// + // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. + // /// + // /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. + // /// @dev EVM selector for this function is: 0x7623402e, + // /// or in textual repr: setCollectionSponsor(address) + // function setCollectionSponsor(address sponsor) public { + // require(false, stub_error); + // sponsor; + // dummy = 0; + // } + /// Set the sponsor of the collection. /// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. /// - /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. - /// @dev EVM selector for this function is: 0x7623402e, - /// or in textual repr: setCollectionSponsor(address) - function setCollectionSponsor(address sponsor) public { + /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract. + /// @dev EVM selector for this function is: 0x84a1d5a8, + /// or in textual repr: setCollectionSponsorCross((address,uint256)) + function setCollectionSponsorCross(CrossAddress memory sponsor) public { require(false, stub_error); sponsor; dummy = 0; @@ -177,44 +294,31 @@ contract Collection is Dummy, ERC165 { /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x6ec0a9f1, /// or in textual repr: collectionSponsor() - function collectionSponsor() public view returns (Tuple17 memory) { + function collectionSponsor() public view returns (CrossAddress memory) { require(false, stub_error); dummy; - return Tuple17(0x0000000000000000000000000000000000000000, 0); + return CrossAddress(0x0000000000000000000000000000000000000000, 0); } - /// Set limits for the collection. - /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "accountTokenOwnershipLimit", - /// "sponsoredDataSize", - /// "sponsoredDataRateLimit", - /// "tokenLimit", - /// "sponsorTransferTimeout", - /// "sponsorApproveTimeout" - /// @param value Value of the limit. - /// @dev EVM selector for this function is: 0x6a3841db, - /// or in textual repr: setCollectionLimit(string,uint32) - function setCollectionLimit(string memory limit, uint32 value) public { + /// Get current collection limits. + /// + /// @return Array of collection limits + /// @dev EVM selector for this function is: 0xf63bc572, + /// or in textual repr: collectionLimits() + function collectionLimits() public view returns (CollectionLimit[] memory) { require(false, stub_error); - limit; - value; - dummy = 0; + dummy; + return new CollectionLimit[](0); } /// Set limits for the collection. /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "ownerCanTransfer", - /// "ownerCanDestroy", - /// "transfersEnabled" - /// @param value Value of the limit. - /// @dev EVM selector for this function is: 0x993b7fba, - /// or in textual repr: setCollectionLimit(string,bool) - function setCollectionLimit(string memory limit, bool value) public { + /// @param limit Some limit. + /// @dev EVM selector for this function is: 0x2316ee74, + /// or in textual repr: setCollectionLimit((uint8,(bool,uint256))) + function setCollectionLimit(CollectionLimit memory limit) public { require(false, stub_error); limit; - value; dummy = 0; } @@ -228,26 +332,46 @@ contract Collection is Dummy, ERC165 { } /// Add collection admin. - /// @param newAdmin Address of the added administrator. - /// @dev EVM selector for this function is: 0x92e462c7, - /// or in textual repr: addCollectionAdmin(address) - function addCollectionAdmin(address newAdmin) public { + /// @param newAdmin Cross account administrator address. + /// @dev EVM selector for this function is: 0x859aa7d6, + /// or in textual repr: addCollectionAdminCross((address,uint256)) + function addCollectionAdminCross(CrossAddress memory newAdmin) public { require(false, stub_error); newAdmin; dummy = 0; } /// Remove collection admin. - /// - /// @param admin Address of the removed administrator. - /// @dev EVM selector for this function is: 0xfafd7b42, - /// or in textual repr: removeCollectionAdmin(address) - function removeCollectionAdmin(address admin) public { + /// @param admin Cross account administrator address. + /// @dev EVM selector for this function is: 0x6c0cd173, + /// or in textual repr: removeCollectionAdminCross((address,uint256)) + function removeCollectionAdminCross(CrossAddress memory admin) public { require(false, stub_error); admin; dummy = 0; } + // /// Add collection admin. + // /// @param newAdmin Address of the added administrator. + // /// @dev EVM selector for this function is: 0x92e462c7, + // /// or in textual repr: addCollectionAdmin(address) + // function addCollectionAdmin(address newAdmin) public { + // require(false, stub_error); + // newAdmin; + // dummy = 0; + // } + + // /// Remove collection admin. + // /// + // /// @param admin Address of the removed administrator. + // /// @dev EVM selector for this function is: 0xfafd7b42, + // /// or in textual repr: removeCollectionAdmin(address) + // function removeCollectionAdmin(address admin) public { + // require(false, stub_error); + // admin; + // dummy = 0; + // } + /// Toggle accessibility of collection nesting. /// /// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled' @@ -272,6 +396,24 @@ contract Collection is Dummy, ERC165 { dummy = 0; } + /// Returns nesting for a collection + /// @dev EVM selector for this function is: 0x22d25bfe, + /// or in textual repr: collectionNestingRestrictedCollectionIds() + function collectionNestingRestrictedCollectionIds() public view returns (CollectionNesting memory) { + require(false, stub_error); + dummy; + return CollectionNesting(false, new uint256[](0)); + } + + /// Returns permissions for a collection + /// @dev EVM selector for this function is: 0x5b2eaf4b, + /// or in textual repr: collectionNestingPermissions() + function collectionNestingPermissions() public view returns (CollectionNestingPermission[] memory) { + require(false, stub_error); + dummy; + return new CollectionNestingPermission[](0); + } + /// Set the collection access method. /// @param mode Access mode /// 0 for Normal @@ -287,32 +429,54 @@ contract Collection is Dummy, ERC165 { /// Checks that user allowed to operate with collection. /// /// @param user User address to check. - /// @dev EVM selector for this function is: 0xd63a8e11, - /// or in textual repr: allowed(address) - function allowed(address user) public view returns (bool) { + /// @dev EVM selector for this function is: 0x91b6df49, + /// or in textual repr: allowlistedCross((address,uint256)) + function allowlistedCross(CrossAddress memory user) public view returns (bool) { require(false, stub_error); user; dummy; return false; } - /// Add the user to the allowed list. + // /// Add the user to the allowed list. + // /// + // /// @param user Address of a trusted user. + // /// @dev EVM selector for this function is: 0x67844fe6, + // /// or in textual repr: addToCollectionAllowList(address) + // function addToCollectionAllowList(address user) public { + // require(false, stub_error); + // user; + // dummy = 0; + // } + + /// Add user to allowed list. /// - /// @param user Address of a trusted user. - /// @dev EVM selector for this function is: 0x67844fe6, - /// or in textual repr: addToCollectionAllowList(address) - function addToCollectionAllowList(address user) public { + /// @param user User cross account address. + /// @dev EVM selector for this function is: 0xa0184a3a, + /// or in textual repr: addToCollectionAllowListCross((address,uint256)) + function addToCollectionAllowListCross(CrossAddress memory user) public { require(false, stub_error); user; dummy = 0; } - /// Remove the user from the allowed list. + // /// Remove the user from the allowed list. + // /// + // /// @param user Address of a removed user. + // /// @dev EVM selector for this function is: 0x85c51acb, + // /// or in textual repr: removeFromCollectionAllowList(address) + // function removeFromCollectionAllowList(address user) public { + // require(false, stub_error); + // user; + // dummy = 0; + // } + + /// Remove user from allowed list. /// - /// @param user Address of a removed user. - /// @dev EVM selector for this function is: 0x85c51acb, - /// or in textual repr: removeFromCollectionAllowList(address) - function removeFromCollectionAllowList(address user) public { + /// @param user User cross account address. + /// @dev EVM selector for this function is: 0x09ba452a, + /// or in textual repr: removeFromCollectionAllowListCross((address,uint256)) + function removeFromCollectionAllowListCross(CrossAddress memory user) public { require(false, stub_error); user; dummy = 0; @@ -329,13 +493,26 @@ contract Collection is Dummy, ERC165 { dummy = 0; } + // /// Check that account is the owner or admin of the collection + // /// + // /// @param user account to verify + // /// @return "true" if account is the owner or admin + // /// @dev EVM selector for this function is: 0x9811b0c7, + // /// or in textual repr: isOwnerOrAdmin(address) + // function isOwnerOrAdmin(address user) public view returns (bool) { + // require(false, stub_error); + // user; + // dummy; + // return false; + // } + /// Check that account is the owner or admin of the collection /// - /// @param user account to verify + /// @param user User cross account to verify /// @return "true" if account is the owner or admin - /// @dev EVM selector for this function is: 0x9811b0c7, - /// or in textual repr: isOwnerOrAdmin(address) - function isOwnerOrAdmin(address user) public view returns (bool) { + /// @dev EVM selector for this function is: 0x3e75a905, + /// or in textual repr: isOwnerOrAdminCross((address,uint256)) + function isOwnerOrAdminCross(CrossAddress memory user) public view returns (bool) { require(false, stub_error); user; dummy; @@ -359,29 +536,107 @@ contract Collection is Dummy, ERC165 { /// If address is canonical then substrate mirror is zero and vice versa. /// @dev EVM selector for this function is: 0xdf727d3b, /// or in textual repr: collectionOwner() - function collectionOwner() public view returns (Tuple17 memory) { + function collectionOwner() public view returns (CrossAddress memory) { require(false, stub_error); dummy; - return Tuple17(0x0000000000000000000000000000000000000000, 0); + return CrossAddress(0x0000000000000000000000000000000000000000, 0); + } + + // /// Changes collection owner to another account + // /// + // /// @dev Owner can be changed only by current owner + // /// @param newOwner new owner account + // /// @dev EVM selector for this function is: 0x4f53e226, + // /// or in textual repr: changeCollectionOwner(address) + // function changeCollectionOwner(address newOwner) public { + // require(false, stub_error); + // newOwner; + // dummy = 0; + // } + + /// Get collection administrators + /// + /// @return Vector of tuples with admins address and his substrate mirror. + /// If address is canonical then substrate mirror is zero and vice versa. + /// @dev EVM selector for this function is: 0x5813216b, + /// or in textual repr: collectionAdmins() + function collectionAdmins() public view returns (CrossAddress[] memory) { + require(false, stub_error); + dummy; + return new CrossAddress[](0); } /// Changes collection owner to another account /// /// @dev Owner can be changed only by current owner - /// @param newOwner new owner account - /// @dev EVM selector for this function is: 0x4f53e226, - /// or in textual repr: changeCollectionOwner(address) - function changeCollectionOwner(address newOwner) public { + /// @param newOwner new owner cross account + /// @dev EVM selector for this function is: 0x6496c497, + /// or in textual repr: changeCollectionOwnerCross((address,uint256)) + function changeCollectionOwnerCross(CrossAddress memory newOwner) public { require(false, stub_error); newOwner; dummy = 0; } } -/// @dev anonymous struct -struct Tuple17 { - address field_0; - uint256 field_1; +/// Cross account struct +struct CrossAddress { + address eth; + uint256 sub; +} + +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field. +struct CollectionNestingPermission { + CollectionPermissionField field; + bool value; +} + +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration. +enum CollectionPermissionField { + /// Owner of token can nest tokens under it. + TokenOwner, + /// Admin of token collection can nest tokens under token. + CollectionAdmin +} + +/// Nested collections. +struct CollectionNesting { + bool token_owner; + uint256[] ids; +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM. +struct CollectionLimit { + CollectionLimitField field; + OptionUint value; +} + +/// Ethereum representation of Optional value with uint256. +struct OptionUint { + bool status; + uint256 value; +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM. +enum CollectionLimitField { + /// How many tokens can a user have on one account. + AccountTokenOwnership, + /// How many bytes of data are available for sponsorship. + SponsoredDataSize, + /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`] + SponsoredDataRateLimit, + /// How many tokens can be mined into this collection. + TokenLimit, + /// Timeouts for transfer sponsoring. + SponsorTransferTimeout, + /// Timeout for sponsoring an approval in passed blocks. + SponsorApproveTimeout, + /// Whether the collection owner of the collection can send tokens (which belong to other users). + OwnerCanTransfer, + /// Can the collection owner burn other people's tokens. + OwnerCanDestroy, + /// Is it possible to send tokens from this collection between users. + TransferEnabled } /// @dev the ERC-165 identifier for this interface is 0x5b5e139f @@ -457,7 +712,7 @@ contract ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents { return false; } - /// @notice Function to mint token. + /// @notice Function to mint a token. /// @param to The new owner /// @return uint256 The id of the newly minted token /// @dev EVM selector for this function is: 0x6a627842, @@ -469,7 +724,7 @@ contract ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents { return 0; } - // /// @notice Function to mint token. + // /// @notice Function to mint a token. // /// @dev `tokenId` should be obtained with `nextTokenId` method, // /// unlike standard, you can't specify it manually // /// @param to The new owner @@ -526,7 +781,7 @@ contract ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents { } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0xef1eaacb +/// @dev the ERC-165 identifier for this interface is 0xabf30dc2 contract ERC721UniqueExtensions is Dummy, ERC165 { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev EVM selector for this function is: 0x06fdde03, @@ -546,6 +801,42 @@ contract ERC721UniqueExtensions is Dummy, ERC165 { return ""; } + /// @notice A description for the collection. + /// @dev EVM selector for this function is: 0x7284e416, + /// or in textual repr: description() + function description() public view returns (string memory) { + require(false, stub_error); + dummy; + return ""; + } + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + /// @dev EVM selector for this function is: 0x2b29dace, + /// or in textual repr: crossOwnerOf(uint256) + function crossOwnerOf(uint256 tokenId) public view returns (CrossAddress memory) { + require(false, stub_error); + tokenId; + dummy; + return CrossAddress(0x0000000000000000000000000000000000000000, 0); + } + + /// Returns the token properties. + /// + /// @param tokenId Id for the token. + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0xe07ede7e, + /// or in textual repr: properties(uint256,string[]) + function properties(uint256 tokenId, string[] memory keys) public view returns (Property[] memory) { + require(false, stub_error); + tokenId; + keys; + dummy; + return new Property[](0); + } + /// @notice Transfer ownership of an RFT /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` /// is the zero address. Throws if `tokenId` is not a valid RFT. @@ -561,6 +852,57 @@ contract ERC721UniqueExtensions is Dummy, ERC165 { dummy = 0; } + /// @notice Transfer ownership of an RFT + /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` + /// is the zero address. Throws if `tokenId` is not a valid RFT. + /// Throws if RFT pieces have multiple owners. + /// @param to The new owner + /// @param tokenId The RFT to transfer + /// @dev EVM selector for this function is: 0x2ada85ff, + /// or in textual repr: transferCross((address,uint256),uint256) + function transferCross(CrossAddress memory to, uint256 tokenId) public { + require(false, stub_error); + to; + tokenId; + dummy = 0; + } + + /// @notice Transfer ownership of an RFT + /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` + /// is the zero address. Throws if `tokenId` is not a valid RFT. + /// Throws if RFT pieces have multiple owners. + /// @param to The new owner + /// @param tokenId The RFT to transfer + /// @dev EVM selector for this function is: 0xd5cf430b, + /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256) + function transferFromCross( + CrossAddress memory from, + CrossAddress memory to, + uint256 tokenId + ) public { + require(false, stub_error); + from; + to; + tokenId; + dummy = 0; + } + + // /// @notice Burns a specific ERC721 token. + // /// @dev Throws unless `msg.sender` is the current owner or an authorized + // /// operator for this RFT. Throws if `from` is not the current owner. Throws + // /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT. + // /// Throws if RFT pieces have multiple owners. + // /// @param from The current owner of the RFT + // /// @param tokenId The RFT to transfer + // /// @dev EVM selector for this function is: 0x79cc6790, + // /// or in textual repr: burnFrom(address,uint256) + // function burnFrom(address from, uint256 tokenId) public { + // require(false, stub_error); + // from; + // tokenId; + // dummy = 0; + // } + /// @notice Burns a specific ERC721 token. /// @dev Throws unless `msg.sender` is the current owner or an authorized /// operator for this RFT. Throws if `from` is not the current owner. Throws @@ -568,9 +910,9 @@ contract ERC721UniqueExtensions is Dummy, ERC165 { /// Throws if RFT pieces have multiple owners. /// @param from The current owner of the RFT /// @param tokenId The RFT to transfer - /// @dev EVM selector for this function is: 0x79cc6790, - /// or in textual repr: burnFrom(address,uint256) - function burnFrom(address from, uint256 tokenId) public { + /// @dev EVM selector for this function is: 0xbb2f5a58, + /// or in textual repr: burnFromCross((address,uint256),uint256) + function burnFromCross(CrossAddress memory from, uint256 tokenId) public { require(false, stub_error); from; tokenId; @@ -608,7 +950,7 @@ contract ERC721UniqueExtensions is Dummy, ERC165 { // /// @param tokens array of pairs of token ID and token URI for minted tokens // /// @dev EVM selector for this function is: 0x36543006, // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[]) - // function mintBulkWithTokenURI(address to, Tuple6[] memory tokens) public returns (bool) { + // function mintBulkWithTokenURI(address to, Tuple14[] memory tokens) public returns (bool) { // require(false, stub_error); // to; // tokens; @@ -616,6 +958,20 @@ contract ERC721UniqueExtensions is Dummy, ERC165 { // return false; // } + /// @notice Function to mint a token. + /// @param to The new owner crossAccountId + /// @param properties Properties of minted token + /// @return uint256 The id of the newly minted token + /// @dev EVM selector for this function is: 0xb904db03, + /// or in textual repr: mintCross((address,uint256),(string,bytes)[]) + function mintCross(CrossAddress memory to, Property[] memory properties) public returns (uint256) { + require(false, stub_error); + to; + properties; + dummy = 0; + return 0; + } + /// Returns EVM address for refungible token /// /// @param token ID of the token @@ -630,7 +986,7 @@ contract ERC721UniqueExtensions is Dummy, ERC165 { } /// @dev anonymous struct -struct Tuple6 { +struct Tuple14 { uint256 field_0; string field_1; } @@ -684,7 +1040,7 @@ contract ERC721Events { /// @title ERC-721 Non-Fungible Token Standard /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md -/// @dev the ERC-165 identifier for this interface is 0x58800161 +/// @dev the ERC-165 identifier for this interface is 0x4016cd87 contract ERC721 is Dummy, ERC165, ERC721Events { /// @notice Count all RFTs assigned to an owner /// @dev RFTs assigned to the zero address are considered invalid, and this @@ -782,7 +1138,10 @@ contract ERC721 is Dummy, ERC165, ERC721Events { dummy = 0; } - /// @dev Not implemented + /// @notice Sets or unsets the approval of a given operator. + /// The `operator` is allowed to transfer all token pieces of the `caller` on their behalf. + /// @param operator Operator + /// @param approved Should operator status be granted or revoked? /// @dev EVM selector for this function is: 0xa22cb465, /// or in textual repr: setApprovalForAll(address,bool) function setApprovalForAll(address operator, bool approved) public { @@ -802,14 +1161,23 @@ contract ERC721 is Dummy, ERC165, ERC721Events { return 0x0000000000000000000000000000000000000000; } - /// @dev Not implemented + /// @notice Tells whether the given `owner` approves the `operator`. /// @dev EVM selector for this function is: 0xe985e9c5, /// or in textual repr: isApprovedForAll(address,address) - function isApprovedForAll(address owner, address operator) public view returns (address) { + function isApprovedForAll(address owner, address operator) public view returns (bool) { require(false, stub_error); owner; operator; dummy; + return false; + } + + /// @notice Returns collection helper contract address + /// @dev EVM selector for this function is: 0x1896cce6, + /// or in textual repr: collectionHelperAddress() + function collectionHelperAddress() public view returns (address) { + require(false, stub_error); + dummy; return 0x0000000000000000000000000000000000000000; } } diff --git a/pallets/refungible/src/stubs/UniqueRefungibleToken.raw b/pallets/refungible/src/stubs/UniqueRefungibleToken.raw index a0b8de43a9..bbf34dfd55 100644 Binary files a/pallets/refungible/src/stubs/UniqueRefungibleToken.raw and b/pallets/refungible/src/stubs/UniqueRefungibleToken.raw differ diff --git a/pallets/refungible/src/stubs/UniqueRefungibleToken.sol b/pallets/refungible/src/stubs/UniqueRefungibleToken.sol index d777f067dd..93861abc6f 100644 --- a/pallets/refungible/src/stubs/UniqueRefungibleToken.sol +++ b/pallets/refungible/src/stubs/UniqueRefungibleToken.sol @@ -36,7 +36,7 @@ contract ERC1633 is Dummy, ERC165 { } } -/// @dev the ERC-165 identifier for this interface is 0xab8deb37 +/// @dev the ERC-165 identifier for this interface is 0xe17a7d2b contract ERC20UniqueExtensions is Dummy, ERC165 { /// @dev Function that burns an amount of the token of a given account, /// deducting from the sender's allowance for said account. @@ -52,6 +52,37 @@ contract ERC20UniqueExtensions is Dummy, ERC165 { return false; } + /// @dev Function that burns an amount of the token of a given account, + /// deducting from the sender's allowance for said account. + /// @param from The account whose tokens will be burnt. + /// @param amount The amount that will be burnt. + /// @dev EVM selector for this function is: 0xbb2f5a58, + /// or in textual repr: burnFromCross((address,uint256),uint256) + function burnFromCross(CrossAddress memory from, uint256 amount) public returns (bool) { + require(false, stub_error); + from; + amount; + dummy = 0; + return false; + } + + /// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`. + /// Beware that changing an allowance with this method brings the risk that someone may use both the old + /// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this + /// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: + /// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + /// @param spender The crossaccount which will spend the funds. + /// @param amount The amount of tokens to be spent. + /// @dev EVM selector for this function is: 0x0ecd0ab0, + /// or in textual repr: approveCross((address,uint256),uint256) + function approveCross(CrossAddress memory spender, uint256 amount) public returns (bool) { + require(false, stub_error); + spender; + amount; + dummy = 0; + return false; + } + /// @dev Function that changes total amount of the tokens. /// Throws if `msg.sender` doesn't owns all of the tokens. /// @param amount New total amount of the tokens. @@ -63,6 +94,44 @@ contract ERC20UniqueExtensions is Dummy, ERC165 { dummy = 0; return false; } + + /// @dev Transfer token for a specified address + /// @param to The crossaccount to transfer to. + /// @param amount The amount to be transferred. + /// @dev EVM selector for this function is: 0x2ada85ff, + /// or in textual repr: transferCross((address,uint256),uint256) + function transferCross(CrossAddress memory to, uint256 amount) public returns (bool) { + require(false, stub_error); + to; + amount; + dummy = 0; + return false; + } + + /// @dev Transfer tokens from one address to another + /// @param from The address which you want to send tokens from + /// @param to The address which you want to transfer to + /// @param amount the amount of tokens to be transferred + /// @dev EVM selector for this function is: 0xd5cf430b, + /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256) + function transferFromCross( + CrossAddress memory from, + CrossAddress memory to, + uint256 amount + ) public returns (bool) { + require(false, stub_error); + from; + to; + amount; + dummy = 0; + return false; + } +} + +/// Cross account struct +struct CrossAddress { + address eth; + uint256 sub; } /// @dev inlined interface diff --git a/pallets/refungible/src/weights.rs b/pallets/refungible/src/weights.rs index da8bcf8635..ab39da5c15 100644 --- a/pallets/refungible/src/weights.rs +++ b/pallets/refungible/src/weights.rs @@ -3,7 +3,7 @@ //! Autogenerated weights for pallet_refungible //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-08-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-11-25, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 // Executed Command: @@ -26,6 +26,7 @@ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] #![allow(clippy::unnecessary_cast)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; @@ -54,6 +55,8 @@ pub trait WeightInfo { fn delete_token_properties(b: u32, ) -> Weight; fn repartition_item() -> Weight; fn token_owner() -> Weight; + fn set_allowance_for_all() -> Weight; + fn allowance_for_all() -> Weight; fn repair_item() -> Weight; } @@ -260,6 +263,16 @@ impl WeightInfo for SubstrateWeight { Weight::from_ref_time(9_431_000) .saturating_add(T::DbWeight::get().reads(2 as u64)) } + // Storage: Refungible WalletOperator (r:0 w:1) + fn set_allowance_for_all() -> Weight { + Weight::from_ref_time(16_150_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: Refungible WalletOperator (r:1 w:0) + fn allowance_for_all() -> Weight { + Weight::from_ref_time(5_901_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + } // Storage: Refungible TokenProperties (r:1 w:1) fn repair_item() -> Weight { Weight::from_ref_time(5_489_000 as u64) @@ -470,6 +483,16 @@ impl WeightInfo for () { Weight::from_ref_time(9_431_000) .saturating_add(RocksDbWeight::get().reads(2 as u64)) } + // Storage: Refungible WalletOperator (r:0 w:1) + fn set_allowance_for_all() -> Weight { + Weight::from_ref_time(16_150_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + // Storage: Refungible WalletOperator (r:1 w:0) + fn allowance_for_all() -> Weight { + Weight::from_ref_time(5_901_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + } // Storage: Refungible TokenProperties (r:1 w:1) fn repair_item() -> Weight { Weight::from_ref_time(5_489_000 as u64) diff --git a/pallets/scheduler/Cargo.toml b/pallets/scheduler-v2/Cargo.toml similarity index 54% rename from pallets/scheduler/Cargo.toml rename to pallets/scheduler-v2/Cargo.toml index 5e9cff8247..af5a272df5 100644 --- a/pallets/scheduler/Cargo.toml +++ b/pallets/scheduler-v2/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "pallet-unique-scheduler" -version = "0.1.1" +name = "pallet-unique-scheduler-v2" +version = "0.1.0" authors = ["Unique Network "] edition = "2021" license = "GPLv3" @@ -10,44 +10,43 @@ description = "Unique Scheduler pallet" readme = "README.md" [dependencies] -serde = { version = "1.0.130", default-features = false } -codec = { package = "parity-scale-codec", version = "3.1.2", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } - -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.30' } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } - -up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30" } -log = { version = "0.4.16", default-features = false } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = [ + "derive", +] } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } [dev-dependencies] -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -substrate-test-utils = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +pallet-preimage = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +substrate-test-utils = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } [features] default = ["std"] +runtime-benchmarks = [ + "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] std = [ "codec/std", - "sp-runtime/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", - "up-sponsorship/std", + "log/std", + "scale-info/std", "sp-io/std", + "sp-runtime/std", "sp-std/std", "sp-core/std", - "log/std", -] -runtime-benchmarks = [ - "frame-benchmarking", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/scheduler-v2/src/benchmarking.rs b/pallets/scheduler-v2/src/benchmarking.rs new file mode 100644 index 0000000000..0c4313e190 --- /dev/null +++ b/pallets/scheduler-v2/src/benchmarking.rs @@ -0,0 +1,374 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +// Original license: +// This file is part of Substrate. + +// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Scheduler pallet benchmarking. + +use super::*; +use frame_benchmarking::{account, benchmarks}; +use frame_support::{ + ensure, + traits::{schedule::Priority, PreimageRecipient}, +}; +use frame_system::RawOrigin; +use sp_std::{prelude::*, vec}; +use sp_io::hashing::blake2_256; + +use crate::{Pallet as Scheduler, ScheduledCall, EncodedCall}; +use frame_system::Call as SystemCall; + +const SEED: u32 = 0; + +const BLOCK_NUMBER: u32 = 2; + +/// Add `n` items to the schedule. +/// +/// For `resolved`: +/// - ` +/// - `None`: aborted (hash without preimage) +/// - `Some(true)`: hash resolves into call if possible, plain call otherwise +/// - `Some(false)`: plain call +fn fill_schedule(when: T::BlockNumber, n: u32) -> Result<(), &'static str> { + let t = DispatchTime::At(when); + let origin: ::PalletsOrigin = frame_system::RawOrigin::Root.into(); + for i in 0..n { + let call = make_call::(None); + let period = Some(((i + 100).into(), 100)); + let name = u32_to_name(i); + Scheduler::::do_schedule_named(name, t, period, 0, origin.clone(), call)?; + } + ensure!( + Agenda::::get(when).agenda.len() == n as usize, + "didn't fill schedule" + ); + Ok(()) +} + +/// Generate a name for a scheduled task from an unsigned integer. +fn u32_to_name(i: u32) -> TaskName { + i.using_encoded(blake2_256) +} + +/// A utility for creating simple scheduled tasks. +/// +/// # Arguments +/// * `periodic` - makes the task periodic. +/// Sets the task's period and repetition count to `100`. +/// * `named` - gives a name to the task: `u32_to_name(0)`. +/// * `signed` - determines the origin of the task. +/// If true, it will have the Signed origin. Otherwise it will have the Root origin. +/// See [`make_origin`] for details. +/// * maybe_lookup_len - sets optional lookup length. It is used to benchmark task fetching from the `Preimages` store. +/// * priority - the task's priority. +fn make_task( + periodic: bool, + named: bool, + signed: bool, + maybe_lookup_len: Option, + priority: Priority, +) -> ScheduledOf { + let call = make_call::(maybe_lookup_len); + let maybe_periodic = match periodic { + true => Some((100u32.into(), 100)), + false => None, + }; + let maybe_id = match named { + true => Some(u32_to_name(0)), + false => None, + }; + let origin = make_origin::(signed); + Scheduled { + maybe_id, + priority, + call, + maybe_periodic, + origin, + _phantom: PhantomData, + } +} + +/// Creates a `SystemCall::remark` scheduled call with a given `len` in bytes. +/// Returns `None` if the call is too large to encode. +fn bounded(len: u32) -> Option> { + let call = <::RuntimeCall>::from(SystemCall::remark { + remark: vec![0; len as usize], + }); + ScheduledCall::new(call).ok() +} + +/// Creates a scheduled call and maximizes its size. +/// +/// If the `maybe_lookup_len` is not supplied, the task will create the maximal `Inline` scheduled call. +/// +/// Otherwise, the function will take the length value from the `maybe_lookup_len` +/// and find a minimal length value that ensures that the scheduled call will require a Preimage lookup. +fn make_call(maybe_lookup_len: Option) -> ScheduledCall { + let bound = EncodedCall::bound() as u32; + let mut len = match maybe_lookup_len { + Some(len) => { + len.min(>::MaxSize::get() - 2) + .max(bound) - 3 + } + None => bound.saturating_sub(4), + }; + + loop { + let c = match bounded::(len) { + Some(x) => x, + None => { + len -= 1; + continue; + } + }; + if c.lookup_needed() == maybe_lookup_len.is_some() { + break c; + } + if maybe_lookup_len.is_some() { + len += 1; + } else { + if len > 0 { + len -= 1; + } else { + break c; + } + } + } +} + +/// Creates an origin for a scheduled call. +/// +/// If `signed` is true, it creates the Signed origin from a default account `account("origin", 0, SEED)`. +/// Otherwise, it creates the Root origin. +fn make_origin(signed: bool) -> ::PalletsOrigin { + match signed { + true => frame_system::RawOrigin::Signed(account("origin", 0, SEED)).into(), + false => frame_system::RawOrigin::Root.into(), + } +} + +/// Creates a dummy `WeightCounter` with the maximum possible weight limit. +fn dummy_counter() -> WeightCounter { + WeightCounter { + used: Weight::zero(), + limit: Weight::MAX, + } +} + +benchmarks! { + // `service_agendas` when no work is done. + // (multiple agendas - scheduled tasks in several blocks) + service_agendas_base { + let now = T::BlockNumber::from(BLOCK_NUMBER); + IncompleteSince::::put(now - One::one()); + }: { + Scheduler::::service_agendas(&mut dummy_counter(), now, 0); + } verify { + assert_eq!(IncompleteSince::::get(), Some(now - One::one())); + } + + // `service_agenda` when no work is done. + // (only one agenda - scheduled tasks in a single block) + service_agenda_base { + let now = BLOCK_NUMBER.into(); + let s in 0 .. T::MaxScheduledPerBlock::get(); + fill_schedule::(now, s)?; + let mut executed = 0; + }: { + Scheduler::::service_agenda(&mut dummy_counter(), &mut executed, now, now, 0); + } verify { + assert_eq!(executed, 0); + } + + // `service_task` when the task is a non-periodic, non-named, non-fetched call which is not + // dispatched (e.g. due to being overweight). + service_task_base { + let now = BLOCK_NUMBER.into(); + let task = make_task::(false, false, false, None, 0); + // prevent any tasks from actually being executed as we only want the surrounding weight. + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + }: { + let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); + } verify { + //assert_eq!(result, Ok(())); + } + + // TODO uncomment if we will use the Preimages + // // `service_task` when the task is a non-periodic, non-named, fetched call (with a known + // // preimage length) and which is not dispatched (e.g. due to being overweight). + // service_task_fetched { + // let s in (EncodedCall::bound() as u32) .. (>::MaxSize::get()); + // let now = BLOCK_NUMBER.into(); + // let task = make_task::(false, false, false, Some(s), 0); + // // prevent any tasks from actually being executed as we only want the surrounding weight. + // let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + // }: { + // let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); + // } verify { + // } + + // `service_task` when the task is a non-periodic, named, non-fetched call which is not + // dispatched (e.g. due to being overweight). + service_task_named { + let now = BLOCK_NUMBER.into(); + let task = make_task::(false, true, false, None, 0); + // prevent any tasks from actually being executed as we only want the surrounding weight. + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + }: { + let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); + } verify { + } + + // `service_task` when the task is a periodic, non-named, non-fetched call which is not + // dispatched (e.g. due to being overweight). + service_task_periodic { + let now = BLOCK_NUMBER.into(); + let task = make_task::(true, false, false, None, 0); + // prevent any tasks from actually being executed as we only want the surrounding weight. + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + }: { + let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); + } verify { + } + + // `execute_dispatch` when the origin is `Signed`, not counting the dispatable's weight. + execute_dispatch_signed { + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX }; + let origin = make_origin::(true); + let call = T::Preimages::realize(&make_call::(None)).unwrap().0; + }: { + assert!(Scheduler::::execute_dispatch(&mut counter, origin, call).is_ok()); + } + verify { + } + + // `execute_dispatch` when the origin is not `Signed`, not counting the dispatable's weight. + execute_dispatch_unsigned { + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX }; + let origin = make_origin::(false); + let call = T::Preimages::realize(&make_call::(None)).unwrap().0; + }: { + assert!(Scheduler::::execute_dispatch(&mut counter, origin, call).is_ok()); + } + verify { + } + + schedule { + let s in 0 .. (T::MaxScheduledPerBlock::get() - 1); + let when = BLOCK_NUMBER.into(); + let periodic = Some((T::BlockNumber::one(), 100)); + let priority = Some(0); + // Essentially a no-op call. + let call = Box::new(SystemCall::set_storage { items: vec![] }.into()); + + fill_schedule::(when, s)?; + }: _(RawOrigin::Root, when, periodic, priority, call) + verify { + ensure!( + Agenda::::get(when).agenda.len() == (s + 1) as usize, + "didn't add to schedule" + ); + } + + cancel { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + + fill_schedule::(when, s)?; + assert_eq!(Agenda::::get(when).agenda.len(), s as usize); + }: _(RawOrigin::Root, when, 0) + verify { + ensure!( + Lookup::::get(u32_to_name(0)).is_none(), + "didn't remove from lookup" + ); + // Removed schedule is NONE + ensure!( + Agenda::::get(when).agenda[0].is_none(), + "didn't remove from schedule" + ); + } + + schedule_named { + let s in 0 .. (T::MaxScheduledPerBlock::get() - 1); + let id = u32_to_name(s); + let when = BLOCK_NUMBER.into(); + let periodic = Some((T::BlockNumber::one(), 100)); + let priority = Some(0); + // Essentially a no-op call. + let call = Box::new(SystemCall::set_storage { items: vec![] }.into()); + + fill_schedule::(when, s)?; + }: _(RawOrigin::Root, id, when, periodic, priority, call) + verify { + ensure!( + Agenda::::get(when).agenda.len() == (s + 1) as usize, + "didn't add to schedule" + ); + } + + cancel_named { + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + + fill_schedule::(when, s)?; + }: _(RawOrigin::Root, u32_to_name(0)) + verify { + ensure!( + Lookup::::get(u32_to_name(0)).is_none(), + "didn't remove from lookup" + ); + // Removed schedule is NONE + ensure!( + Agenda::::get(when).agenda[0].is_none(), + "didn't remove from schedule" + ); + } + + change_named_priority { + let origin: RawOrigin = frame_system::RawOrigin::Root; + let s in 1 .. T::MaxScheduledPerBlock::get(); + let when = BLOCK_NUMBER.into(); + let idx = s - 1; + let id = u32_to_name(idx); + let priority = 42; + fill_schedule::(when, s)?; + }: _(origin, id, priority) + verify { + ensure!( + Agenda::::get(when).agenda[idx as usize].clone().unwrap().priority == priority, + "didn't change the priority" + ); + } + + impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/pallets/scheduler-v2/src/lib.rs b/pallets/scheduler-v2/src/lib.rs new file mode 100644 index 0000000000..b82a2fd003 --- /dev/null +++ b/pallets/scheduler-v2/src/lib.rs @@ -0,0 +1,1337 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +// Original license: +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Scheduler +//! A Pallet for scheduling dispatches. +//! +//! - [`Config`] +//! - [`Call`] +//! - [`Pallet`] +//! +//! ## Overview +//! +//! This Pallet exposes capabilities for scheduling dispatches to occur at a +//! specified block number or at a specified period. These scheduled dispatches +//! may be named or anonymous and may be canceled. +//! +//! **NOTE:** The scheduled calls will be dispatched with the default filter +//! for the origin: namely `frame_system::Config::BaseCallFilter` for all origin +//! except root which will get no filter. And not the filter contained in origin +//! use to call `fn schedule`. +//! +//! If a call is scheduled using proxy or whatever mecanism which adds filter, +//! then those filter will not be used when dispatching the schedule call. +//! +//! ## Interface +//! +//! ### Dispatchable Functions +//! +//! * `schedule` - schedule a dispatch, which may be periodic, to occur at a specified block and +//! with a specified priority. +//! * `cancel` - cancel a scheduled dispatch, specified by block number and index. +//! * `schedule_named` - augments the `schedule` interface with an additional `Vec` parameter +//! that can be used for identification. +//! * `cancel_named` - the named complement to the cancel function. + +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] +#![deny(missing_docs)] + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; +pub mod weights; + +use codec::{Codec, Decode, Encode, MaxEncodedLen}; +use frame_support::{ + dispatch::{ + DispatchError, DispatchResult, Dispatchable, GetDispatchInfo, Parameter, PostDispatchInfo, + }, + traits::{ + schedule::{self, DispatchTime, LOWEST_PRIORITY}, + EnsureOrigin, Get, IsType, OriginTrait, PrivilegeCmp, StorageVersion, PreimageRecipient, + ConstU32, UnfilteredDispatchable, + }, + weights::Weight, + unsigned::TransactionValidityError, +}; + +use frame_system::{self as system}; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::{BadOrigin, One, Saturating, Zero, Hash}, + BoundedVec, RuntimeDebug, DispatchErrorWithPostInfo, +}; +use sp_core::H160; +use sp_std::{cmp::Ordering, marker::PhantomData, prelude::*}; +pub use weights::WeightInfo; + +pub use pallet::*; + +/// Just a simple index for naming period tasks. +pub type PeriodicIndex = u32; +/// The location of a scheduled task that can be used to remove it. +pub type TaskAddress = (BlockNumber, u32); + +/// A an encoded bounded `Call`. Its encoding must be at most 128 bytes. +pub type EncodedCall = BoundedVec>; + +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(T))] +/// A scheduled call is stored as is or as a preimage hash to lookup. +/// This enum represents both variants. +pub enum ScheduledCall { + /// A an encoded bounded `Call`. Its encoding must be at most 128 bytes. + Inline(EncodedCall), + + /// A Blake2-256 hash of the call together with an upper limit for its size. + PreimageLookup { + /// A call hash to lookup + hash: T::Hash, + + /// The length of the decoded call + unbounded_len: u32, + }, +} + +impl ScheduledCall { + /// Convert an otherwise unbounded or large value into a type ready for placing in storage. + /// + /// NOTE: Once this API is used, you should use either `drop` or `realize`. + pub fn new(call: ::RuntimeCall) -> Result { + let encoded = call.encode(); + let len = encoded.len(); + + match EncodedCall::try_from(encoded.clone()) { + Ok(bounded) => Ok(Self::Inline(bounded)), + Err(_) => { + let hash = ::Hashing::hash_of(&encoded); + ::Preimages::note_preimage( + encoded + .try_into() + .map_err(|_| >::TooBigScheduledCall)?, + ); + + Ok(Self::PreimageLookup { + hash, + unbounded_len: len as u32, + }) + } + } + } + + /// The maximum length of the lookup that is needed to peek `Self`. + pub fn lookup_len(&self) -> Option { + match self { + Self::Inline(..) => None, + Self::PreimageLookup { unbounded_len, .. } => Some(*unbounded_len), + } + } + + /// Returns whether the image will require a lookup to be peeked. + pub fn lookup_needed(&self) -> bool { + match self { + Self::Inline(_) => false, + Self::PreimageLookup { .. } => true, + } + } + + // Decodes a runtime call + fn decode(mut data: &[u8]) -> Result<::RuntimeCall, DispatchError> { + ::RuntimeCall::decode(&mut data) + .map_err(|_| >::ScheduledCallCorrupted.into()) + } +} + +/// Weight Info for the Preimages fetches. +pub trait SchedulerPreimagesWeightInfo { + /// Get the weight of a task fetches with a given decoded length. + fn service_task_fetched(call_length: u32) -> Weight; +} + +impl SchedulerPreimagesWeightInfo for () { + fn service_task_fetched(_call_length: u32) -> Weight { + W::service_task_base() + } +} + +/// A scheduler's interface for managing preimages to hashes +/// and looking up preimages from their hash on-chain. +pub trait SchedulerPreimages: + PreimageRecipient + SchedulerPreimagesWeightInfo +{ + /// No longer request that the data for decoding the given `call` is available. + fn drop(call: &ScheduledCall); + + /// Convert the given `call` instance back into its original instance, also returning the + /// exact size of its encoded form if it needed to be looked-up from a stored preimage. + /// + /// NOTE: This does not remove any data needed for realization. If you will no longer use the + /// `call`, use `realize` instead or use `drop` afterwards. + fn peek( + call: &ScheduledCall, + ) -> Result<(::RuntimeCall, Option), DispatchError>; + + /// Convert the given scheduled `call` value back into its original instance. If successful, + /// `drop` any data backing it. This will not break the realisability of independently + /// created instances of `ScheduledCall` which happen to have identical data. + fn realize( + call: &ScheduledCall, + ) -> Result<(::RuntimeCall, Option), DispatchError>; +} + +impl + SchedulerPreimagesWeightInfo> + SchedulerPreimages for PP +{ + fn drop(call: &ScheduledCall) { + match call { + ScheduledCall::Inline(_) => {} + ScheduledCall::PreimageLookup { hash, .. } => Self::unrequest_preimage(hash), + } + } + + fn peek( + call: &ScheduledCall, + ) -> Result<(::RuntimeCall, Option), DispatchError> { + match call { + ScheduledCall::Inline(data) => Ok((ScheduledCall::::decode(data)?, None)), + ScheduledCall::PreimageLookup { + hash, + unbounded_len, + } => { + let (preimage, len) = Self::get_preimage(hash) + .ok_or(>::PreimageNotFound) + .map(|preimage| (preimage, *unbounded_len))?; + + Ok((ScheduledCall::::decode(preimage.as_slice())?, Some(len))) + } + } + } + + fn realize( + call: &ScheduledCall, + ) -> Result<(::RuntimeCall, Option), DispatchError> { + let r = Self::peek(call)?; + Self::drop(call); + Ok(r) + } +} + +/// Scheduler's supported origins. +pub enum ScheduledEnsureOriginSuccess { + /// A scheduled transaction has the Root origin. + Root, + + /// A specific account has signed a scheduled transaction. + Signed(AccountId), +} + +/// An identifier of a scheduled task. +pub type TaskName = [u8; 32]; + +/// Information regarding an item to be executed in the future. +#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] +#[derive(Clone, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub struct Scheduled { + /// The unique identity for this task, if there is one. + maybe_id: Option, + + /// This task's priority. + priority: schedule::Priority, + + /// The call to be dispatched. + call: Call, + + /// If the call is periodic, then this points to the information concerning that. + maybe_periodic: Option>, + + /// The origin with which to dispatch the call. + origin: PalletsOrigin, + _phantom: PhantomData, +} + +/// Information regarding an item to be executed in the future. +pub type ScheduledOf = Scheduled< + TaskName, + ScheduledCall, + ::BlockNumber, + ::PalletsOrigin, + ::AccountId, +>; + +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo)] +#[scale_info(skip_type_params(T))] +/// A structure for storing scheduled tasks in a block. +/// The `BlockAgenda` tracks the available free space for a new task in a block.4 +/// +/// The agenda's maximum amount of tasks is `T::MaxScheduledPerBlock`. +pub struct BlockAgenda { + agenda: BoundedVec>, T::MaxScheduledPerBlock>, + free_places: u32, +} + +impl BlockAgenda { + /// Tries to push a new scheduled task into the block's agenda. + /// If there is a free place, the new task will take it, + /// and the `BlockAgenda` will record that the number of free places has decreased. + /// + /// An error containing the scheduled task will be returned if there are no free places. + /// + /// The complexity of the check for the *existence* of a free place is O(1). + /// The complexity of *finding* the free slot is O(n). + fn try_push(&mut self, scheduled: ScheduledOf) -> Result> { + if self.free_places == 0 { + return Err(scheduled); + } + + self.free_places = self.free_places.saturating_sub(1); + + if (self.agenda.len() as u32) < T::MaxScheduledPerBlock::get() { + // will always succeed due to the above check. + let _ = self.agenda.try_push(Some(scheduled)); + Ok((self.agenda.len() - 1) as u32) + } else { + match self.agenda.iter().position(|i| i.is_none()) { + Some(hole_index) => { + self.agenda[hole_index] = Some(scheduled); + Ok(hole_index as u32) + } + None => unreachable!("free_places was greater than 0; qed"), + } + } + } + + /// Sets a slot by the given index and the slot value. + /// + /// ### Panics + /// If the index is out of range, the function will panic. + fn set_slot(&mut self, index: u32, slot: Option>) { + self.agenda[index as usize] = slot; + } + + /// Returns an iterator containing references to the agenda's slots. + fn iter(&self) -> impl Iterator>> + '_ { + self.agenda.iter() + } + + /// Returns an immutable reference to a scheduled task if there is one under the given index. + /// + /// The function returns `None` if: + /// * The `index` is out of range + /// * No scheduled task occupies the agenda slot under the given index. + fn get(&self, index: u32) -> Option<&ScheduledOf> { + match self.agenda.get(index as usize) { + Some(Some(scheduled)) => Some(scheduled), + _ => None, + } + } + + /// Returns a mutable reference to a scheduled task if there is one under the given index. + /// + /// The function returns `None` if: + /// * The `index` is out of range + /// * No scheduled task occupies the agenda slot under the given index. + fn get_mut(&mut self, index: u32) -> Option<&mut ScheduledOf> { + match self.agenda.get_mut(index as usize) { + Some(Some(scheduled)) => Some(scheduled), + _ => None, + } + } + + /// Take a scheduled task by the given index. + /// + /// If there is a task under the index, the function will: + /// * Free the corresponding agenda slot. + /// * Decrease the number of free places. + /// * Return the scheduled task. + /// + /// The function returns `None` if there is no task under the index. + fn take(&mut self, index: u32) -> Option> { + let removed = self.agenda.get_mut(index as usize)?.take(); + + if removed.is_some() { + self.free_places = self.free_places.saturating_add(1); + } + + removed + } +} + +impl Default for BlockAgenda { + fn default() -> Self { + let agenda = Default::default(); + let free_places = T::MaxScheduledPerBlock::get(); + + Self { + agenda, + free_places, + } + } +} +/// A structure for tracking the used weight +/// and checking if it does not exceed the weight limit. +struct WeightCounter { + used: Weight, + limit: Weight, +} + +impl WeightCounter { + /// Checks if the weight `w` can be accommodated by the counter. + /// + /// If there is room for the additional weight `w`, + /// the function will update the used weight and return true. + fn check_accrue(&mut self, w: Weight) -> bool { + let test = self.used.saturating_add(w); + if test.any_gt(self.limit) { + false + } else { + self.used = test; + true + } + } + + /// Checks if the weight `w` can be accommodated by the counter. + fn can_accrue(&mut self, w: Weight) -> bool { + self.used.saturating_add(w).all_lte(self.limit) + } +} + +pub(crate) struct MarginalWeightInfo(sp_std::marker::PhantomData); + +impl MarginalWeightInfo { + /// Return the weight of servicing a single task. + fn service_task(maybe_lookup_len: Option, named: bool, periodic: bool) -> Weight { + let base = T::WeightInfo::service_task_base(); + let mut total = match maybe_lookup_len { + None => base, + Some(l) => T::Preimages::service_task_fetched(l as u32), + }; + if named { + total.saturating_accrue(T::WeightInfo::service_task_named().saturating_sub(base)); + } + if periodic { + total.saturating_accrue(T::WeightInfo::service_task_periodic().saturating_sub(base)); + } + total + } +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::{dispatch::PostDispatchInfo, pallet_prelude::*}; + use system::pallet_prelude::*; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The aggregated origin which the dispatch will take. + type RuntimeOrigin: OriginTrait + + From + + IsType<::RuntimeOrigin> + + Clone; + + /// The caller origin, overarching type of all pallets origins. + type PalletsOrigin: From> + + Codec + + Clone + + Eq + + TypeInfo + + MaxEncodedLen; + + /// The aggregated call type. + type RuntimeCall: Parameter + + Dispatchable< + RuntimeOrigin = ::RuntimeOrigin, + PostInfo = PostDispatchInfo, + > + UnfilteredDispatchable::RuntimeOrigin> + + GetDispatchInfo + + From>; + + /// The maximum weight that may be scheduled per block for any dispatchables. + #[pallet::constant] + type MaximumWeight: Get; + + /// Required origin to schedule or cancel calls. + type ScheduleOrigin: EnsureOrigin< + ::RuntimeOrigin, + Success = ScheduledEnsureOriginSuccess, + >; + + /// Compare the privileges of origins. + /// + /// This will be used when canceling a task, to ensure that the origin that tries + /// to cancel has greater or equal privileges as the origin that created the scheduled task. + /// + /// For simplicity the [`EqualPrivilegeOnly`](frame_support::traits::EqualPrivilegeOnly) can + /// be used. This will only check if two given origins are equal. + type OriginPrivilegeCmp: PrivilegeCmp; + + /// The maximum number of scheduled calls in the queue for a single block. + #[pallet::constant] + type MaxScheduledPerBlock: Get; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + + /// The preimage provider with which we look up call hashes to get the call. + type Preimages: SchedulerPreimages; + + /// The helper type used for custom transaction fee logic. + type CallExecutor: DispatchCall; + + /// Required origin to set/change calls' priority. + type PrioritySetOrigin: EnsureOrigin<::RuntimeOrigin>; + } + + /// It contains the block number from which we should service tasks. + /// It's used for delaying the servicing of future blocks' agendas if we had overweight tasks. + #[pallet::storage] + pub type IncompleteSince = StorageValue<_, T::BlockNumber>; + + /// Items to be executed, indexed by the block number that they should be executed on. + #[pallet::storage] + pub type Agenda = + StorageMap<_, Twox64Concat, T::BlockNumber, BlockAgenda, ValueQuery>; + + /// Lookup from a name to the block number and index of the task. + #[pallet::storage] + pub(crate) type Lookup = + StorageMap<_, Twox64Concat, TaskName, TaskAddress>; + + /// Events type. + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Scheduled some task. + Scheduled { + /// The block number in which the scheduled task should be executed. + when: T::BlockNumber, + + /// The index of the block's agenda slot. + index: u32, + }, + /// Canceled some task. + Canceled { + /// The block number in which the canceled task has been. + when: T::BlockNumber, + + /// The index of the block's agenda slot that had become available. + index: u32, + }, + /// Dispatched some task. + Dispatched { + /// The task's address - the block number and the block's agenda index. + task: TaskAddress, + + /// The task's name if it is not anonymous. + id: Option<[u8; 32]>, + + /// The task's execution result. + result: DispatchResult, + }, + /// Scheduled task's priority has changed + PriorityChanged { + /// The task's address - the block number and the block's agenda index. + task: TaskAddress, + + /// The new priority of the task. + priority: schedule::Priority, + }, + /// The call for the provided hash was not found so the task has been aborted. + CallUnavailable { + /// The task's address - the block number and the block's agenda index. + task: TaskAddress, + + /// The task's name if it is not anonymous. + id: Option<[u8; 32]>, + }, + /// The given task can never be executed since it is overweight. + PermanentlyOverweight { + /// The task's address - the block number and the block's agenda index. + task: TaskAddress, + + /// The task's name if it is not anonymous. + id: Option<[u8; 32]>, + }, + } + + #[pallet::error] + pub enum Error { + /// Failed to schedule a call + FailedToSchedule, + /// There is no place for a new task in the agenda + AgendaIsExhausted, + /// Scheduled call is corrupted + ScheduledCallCorrupted, + /// Scheduled call preimage is not found + PreimageNotFound, + /// Scheduled call is too big + TooBigScheduledCall, + /// Cannot find the scheduled call. + NotFound, + /// Given target block number is in the past. + TargetBlockNumberInPast, + /// Attempt to use a non-named function on a named task. + Named, + } + + #[pallet::hooks] + impl Hooks> for Pallet { + /// Execute the scheduled calls + fn on_initialize(now: T::BlockNumber) -> Weight { + let mut weight_counter = WeightCounter { + used: Weight::zero(), + limit: T::MaximumWeight::get(), + }; + Self::service_agendas(&mut weight_counter, now, u32::max_value()); + weight_counter.used + } + } + + #[pallet::call] + impl Pallet { + /// Anonymously schedule a task. + /// + /// Only `T::ScheduleOrigin` is allowed to schedule a task. + /// Only `T::PrioritySetOrigin` is allowed to set the task's priority. + #[pallet::call_index(0)] + #[pallet::weight(::WeightInfo::schedule(T::MaxScheduledPerBlock::get()))] + pub fn schedule( + origin: OriginFor, + when: T::BlockNumber, + maybe_periodic: Option>, + priority: Option, + call: Box<::RuntimeCall>, + ) -> DispatchResult { + T::ScheduleOrigin::ensure_origin(origin.clone())?; + + if priority.is_some() { + T::PrioritySetOrigin::ensure_origin(origin.clone())?; + } + + let origin = ::RuntimeOrigin::from(origin); + Self::do_schedule( + DispatchTime::At(when), + maybe_periodic, + priority.unwrap_or(LOWEST_PRIORITY), + origin.caller().clone(), + >::new(*call)?, + )?; + Ok(()) + } + + /// Cancel an anonymously scheduled task. + /// + /// The `T::OriginPrivilegeCmp` decides whether the given origin is allowed to cancel the task or not. + #[pallet::call_index(1)] + #[pallet::weight(::WeightInfo::cancel(T::MaxScheduledPerBlock::get()))] + pub fn cancel(origin: OriginFor, when: T::BlockNumber, index: u32) -> DispatchResult { + T::ScheduleOrigin::ensure_origin(origin.clone())?; + let origin = ::RuntimeOrigin::from(origin); + Self::do_cancel(Some(origin.caller().clone()), (when, index))?; + Ok(()) + } + + /// Schedule a named task. + /// + /// Only `T::ScheduleOrigin` is allowed to schedule a task. + /// Only `T::PrioritySetOrigin` is allowed to set the task's priority. + #[pallet::call_index(2)] + #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] + pub fn schedule_named( + origin: OriginFor, + id: TaskName, + when: T::BlockNumber, + maybe_periodic: Option>, + priority: Option, + call: Box<::RuntimeCall>, + ) -> DispatchResult { + T::ScheduleOrigin::ensure_origin(origin.clone())?; + + if priority.is_some() { + T::PrioritySetOrigin::ensure_origin(origin.clone())?; + } + + let origin = ::RuntimeOrigin::from(origin); + Self::do_schedule_named( + id, + DispatchTime::At(when), + maybe_periodic, + priority.unwrap_or(LOWEST_PRIORITY), + origin.caller().clone(), + >::new(*call)?, + )?; + Ok(()) + } + + /// Cancel a named scheduled task. + /// + /// The `T::OriginPrivilegeCmp` decides whether the given origin is allowed to cancel the task or not. + #[pallet::call_index(3)] + #[pallet::weight(::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get()))] + pub fn cancel_named(origin: OriginFor, id: TaskName) -> DispatchResult { + T::ScheduleOrigin::ensure_origin(origin.clone())?; + let origin = ::RuntimeOrigin::from(origin); + Self::do_cancel_named(Some(origin.caller().clone()), id)?; + Ok(()) + } + + /// Anonymously schedule a task after a delay. + /// + /// # + /// Same as [`schedule`]. + /// # + #[pallet::call_index(4)] + #[pallet::weight(::WeightInfo::schedule(T::MaxScheduledPerBlock::get()))] + pub fn schedule_after( + origin: OriginFor, + after: T::BlockNumber, + maybe_periodic: Option>, + priority: Option, + call: Box<::RuntimeCall>, + ) -> DispatchResult { + T::ScheduleOrigin::ensure_origin(origin.clone())?; + + if priority.is_some() { + T::PrioritySetOrigin::ensure_origin(origin.clone())?; + } + + let origin = ::RuntimeOrigin::from(origin); + Self::do_schedule( + DispatchTime::After(after), + maybe_periodic, + priority.unwrap_or(LOWEST_PRIORITY), + origin.caller().clone(), + >::new(*call)?, + )?; + Ok(()) + } + + /// Schedule a named task after a delay. + /// + /// Only `T::ScheduleOrigin` is allowed to schedule a task. + /// Only `T::PrioritySetOrigin` is allowed to set the task's priority. + /// + /// # + /// Same as [`schedule_named`](Self::schedule_named). + /// # + #[pallet::call_index(5)] + #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] + pub fn schedule_named_after( + origin: OriginFor, + id: TaskName, + after: T::BlockNumber, + maybe_periodic: Option>, + priority: Option, + call: Box<::RuntimeCall>, + ) -> DispatchResult { + T::ScheduleOrigin::ensure_origin(origin.clone())?; + + if priority.is_some() { + T::PrioritySetOrigin::ensure_origin(origin.clone())?; + } + + let origin = ::RuntimeOrigin::from(origin); + Self::do_schedule_named( + id, + DispatchTime::After(after), + maybe_periodic, + priority.unwrap_or(LOWEST_PRIORITY), + origin.caller().clone(), + >::new(*call)?, + )?; + Ok(()) + } + + /// Change a named task's priority. + /// + /// Only the `T::PrioritySetOrigin` is allowed to change the task's priority. + #[pallet::call_index(6)] + #[pallet::weight(::WeightInfo::change_named_priority(T::MaxScheduledPerBlock::get()))] + pub fn change_named_priority( + origin: OriginFor, + id: TaskName, + priority: schedule::Priority, + ) -> DispatchResult { + T::PrioritySetOrigin::ensure_origin(origin.clone())?; + let origin = ::RuntimeOrigin::from(origin); + Self::do_change_named_priority(origin.caller().clone(), id, priority) + } + } +} + +impl Pallet { + /// Converts the `DispatchTime` to the `BlockNumber`. + /// + /// Returns an error if the block number is in the past. + fn resolve_time(when: DispatchTime) -> Result { + let now = frame_system::Pallet::::block_number(); + + let when = match when { + DispatchTime::At(x) => x, + // The current block has already completed it's scheduled tasks, so + // Schedule the task at lest one block after this current block. + DispatchTime::After(x) => now.saturating_add(x).saturating_add(One::one()), + }; + + if when <= now { + return Err(Error::::TargetBlockNumberInPast.into()); + } + + Ok(when) + } + + /// Places the mandatory task. + /// + /// It will try to place the task into the block pointed by the `when` parameter. + /// + /// If the block has no room for a task, + /// the function will search for a future block that can accommodate the task. + fn mandatory_place_task(when: T::BlockNumber, what: ScheduledOf) { + Self::place_task(when, what, true).expect("mandatory place task always succeeds; qed"); + } + + /// Tries to place a task `what` into the given block `when`. + /// + /// Returns an error if the block has no room for the task. + fn try_place_task( + when: T::BlockNumber, + what: ScheduledOf, + ) -> Result, DispatchError> { + Self::place_task(when, what, false) + } + + /// If `is_mandatory` is true, the function behaves like [`mandatory_place_task`](Self::mandatory_place_task); + /// otherwise it acts like [`try_place_task`](Self::try_place_task). + /// + /// The function also updates the `Lookup` storage. + fn place_task( + mut when: T::BlockNumber, + what: ScheduledOf, + is_mandatory: bool, + ) -> Result, DispatchError> { + let maybe_name = what.maybe_id; + let index = Self::push_to_agenda(&mut when, what, is_mandatory)?; + let address = (when, index); + if let Some(name) = maybe_name { + Lookup::::insert(name, address) + } + Self::deposit_event(Event::Scheduled { + when: address.0, + index: address.1, + }); + Ok(address) + } + + /// Pushes the scheduled task into the block's agenda. + /// + /// If `is_mandatory` is true, it searches for a block with a free slot for the given task. + /// + /// If `is_mandatory` is false and there is no free slot, the function returns an error. + fn push_to_agenda( + when: &mut T::BlockNumber, + mut what: ScheduledOf, + is_mandatory: bool, + ) -> Result { + let mut agenda; + + let index = loop { + agenda = Agenda::::get(*when); + + match agenda.try_push(what) { + Ok(index) => break index, + Err(returned_what) if is_mandatory => { + what = returned_what; + when.saturating_inc(); + } + Err(_) => return Err(>::AgendaIsExhausted.into()), + } + }; + + Agenda::::insert(when, agenda); + Ok(index) + } + + fn do_schedule( + when: DispatchTime, + maybe_periodic: Option>, + priority: schedule::Priority, + origin: T::PalletsOrigin, + call: ScheduledCall, + ) -> Result, DispatchError> { + let when = Self::resolve_time(when)?; + + // sanitize maybe_periodic + let maybe_periodic = maybe_periodic + .filter(|p| p.1 > 1 && !p.0.is_zero()) + // Remove one from the number of repetitions since we will schedule one now. + .map(|(p, c)| (p, c - 1)); + let task = Scheduled { + maybe_id: None, + priority, + call, + maybe_periodic, + origin, + _phantom: PhantomData, + }; + Self::try_place_task(when, task) + } + + fn do_cancel( + origin: Option, + (when, index): TaskAddress, + ) -> Result<(), DispatchError> { + let scheduled = Agenda::::try_mutate( + when, + |agenda| -> Result>, DispatchError> { + let scheduled = match agenda.get(index) { + Some(scheduled) => scheduled, + None => return Ok(None), + }; + + if let Some(ref o) = origin { + if matches!( + T::OriginPrivilegeCmp::cmp_privilege(o, &scheduled.origin), + Some(Ordering::Less) | None + ) { + return Err(BadOrigin.into()); + } + } + + Ok(agenda.take(index)) + }, + )?; + if let Some(s) = scheduled { + T::Preimages::drop(&s.call); + + if let Some(id) = s.maybe_id { + Lookup::::remove(id); + } + Self::deposit_event(Event::Canceled { when, index }); + Ok(()) + } else { + Err(Error::::NotFound.into()) + } + } + + fn do_schedule_named( + id: TaskName, + when: DispatchTime, + maybe_periodic: Option>, + priority: schedule::Priority, + origin: T::PalletsOrigin, + call: ScheduledCall, + ) -> Result, DispatchError> { + // ensure id it is unique + if Lookup::::contains_key(&id) { + return Err(Error::::FailedToSchedule.into()); + } + + let when = Self::resolve_time(when)?; + + // sanitize maybe_periodic + let maybe_periodic = maybe_periodic + .filter(|p| p.1 > 1 && !p.0.is_zero()) + // Remove one from the number of repetitions since we will schedule one now. + .map(|(p, c)| (p, c - 1)); + + let task = Scheduled { + maybe_id: Some(id), + priority, + call, + maybe_periodic, + origin, + _phantom: Default::default(), + }; + Self::try_place_task(when, task) + } + + fn do_cancel_named(origin: Option, id: TaskName) -> DispatchResult { + Lookup::::try_mutate_exists(id, |lookup| -> DispatchResult { + if let Some((when, index)) = lookup.take() { + Agenda::::try_mutate(when, |agenda| -> DispatchResult { + let scheduled = match agenda.get(index) { + Some(scheduled) => scheduled, + None => return Ok(()), + }; + + if let Some(ref o) = origin { + if matches!( + T::OriginPrivilegeCmp::cmp_privilege(o, &scheduled.origin), + Some(Ordering::Less) | None + ) { + return Err(BadOrigin.into()); + } + T::Preimages::drop(&scheduled.call); + } + + agenda.take(index); + + Ok(()) + })?; + Self::deposit_event(Event::Canceled { when, index }); + Ok(()) + } else { + Err(Error::::NotFound.into()) + } + }) + } + + fn do_change_named_priority( + origin: T::PalletsOrigin, + id: TaskName, + priority: schedule::Priority, + ) -> DispatchResult { + match Lookup::::get(id) { + Some((when, index)) => Agenda::::try_mutate(when, |agenda| { + let scheduled = match agenda.get_mut(index) { + Some(scheduled) => scheduled, + None => return Ok(()), + }; + + if matches!( + T::OriginPrivilegeCmp::cmp_privilege(&origin, &scheduled.origin), + Some(Ordering::Less) | None + ) { + return Err(BadOrigin.into()); + } + + scheduled.priority = priority; + Self::deposit_event(Event::PriorityChanged { + task: (when, index), + priority, + }); + + Ok(()) + }), + None => Err(Error::::NotFound.into()), + } + } +} + +enum ServiceTaskError { + /// Could not be executed due to missing preimage. + Unavailable, + /// Could not be executed due to weight limitations. + Overweight, +} +use ServiceTaskError::*; + +/// A Scheduler-Runtime interface for finer payment handling. +pub trait DispatchCall { + /// Resolve the call dispatch, including any post-dispatch operations. + fn dispatch_call( + signer: Option, + function: ::RuntimeCall, + ) -> Result< + Result>, + TransactionValidityError, + >; +} + +impl Pallet { + /// Service up to `max` agendas queue starting from earliest incompletely executed agenda. + fn service_agendas(weight: &mut WeightCounter, now: T::BlockNumber, max: u32) { + if !weight.check_accrue(T::WeightInfo::service_agendas_base()) { + return; + } + + let mut incomplete_since = now + One::one(); + let mut when = IncompleteSince::::take().unwrap_or(now); + let mut executed = 0; + + let max_items = T::MaxScheduledPerBlock::get(); + let mut count_down = max; + let service_agenda_base_weight = T::WeightInfo::service_agenda_base(max_items); + while count_down > 0 && when <= now && weight.can_accrue(service_agenda_base_weight) { + if !Self::service_agenda(weight, &mut executed, now, when, u32::max_value()) { + incomplete_since = incomplete_since.min(when); + } + when.saturating_inc(); + count_down.saturating_dec(); + } + incomplete_since = incomplete_since.min(when); + if incomplete_since <= now { + IncompleteSince::::put(incomplete_since); + } + } + + /// Returns `true` if the agenda was fully completed, `false` if it should be revisited at a + /// later block. + fn service_agenda( + weight: &mut WeightCounter, + executed: &mut u32, + now: T::BlockNumber, + when: T::BlockNumber, + max: u32, + ) -> bool { + let mut agenda = Agenda::::get(when); + let mut ordered = agenda + .iter() + .enumerate() + .filter_map(|(index, maybe_item)| { + maybe_item + .as_ref() + .map(|item| (index as u32, item.priority)) + }) + .collect::>(); + ordered.sort_by_key(|k| k.1); + let within_limit = + weight.check_accrue(T::WeightInfo::service_agenda_base(ordered.len() as u32)); + debug_assert!( + within_limit, + "weight limit should have been checked in advance" + ); + + // Items which we know can be executed and have postponed for execution in a later block. + let mut postponed = (ordered.len() as u32).saturating_sub(max); + // Items which we don't know can ever be executed. + let mut dropped = 0; + + for (agenda_index, _) in ordered.into_iter().take(max as usize) { + let task = match agenda.take(agenda_index).take() { + None => continue, + Some(t) => t, + }; + let base_weight = MarginalWeightInfo::::service_task( + task.call.lookup_len().map(|x| x as usize), + task.maybe_id.is_some(), + task.maybe_periodic.is_some(), + ); + if !weight.can_accrue(base_weight) { + postponed += 1; + break; + } + let result = Self::service_task(weight, now, when, agenda_index, *executed == 0, task); + match result { + Err((Unavailable, slot)) => { + dropped += 1; + agenda.set_slot(agenda_index, slot); + } + Err((Overweight, slot)) => { + postponed += 1; + agenda.set_slot(agenda_index, slot); + } + Ok(()) => { + *executed += 1; + } + }; + } + if postponed > 0 || dropped > 0 { + Agenda::::insert(when, agenda); + } else { + Agenda::::remove(when); + } + postponed == 0 + } + + /// Service (i.e. execute) the given task, being careful not to overflow the `weight` counter. + /// + /// This involves: + /// - removing and potentially replacing the `Lookup` entry for the task. + /// - realizing the task's call which can include a preimage lookup. + /// - Rescheduling the task for execution in a later agenda if periodic. + fn service_task( + weight: &mut WeightCounter, + now: T::BlockNumber, + when: T::BlockNumber, + agenda_index: u32, + is_first: bool, + mut task: ScheduledOf, + ) -> Result<(), (ServiceTaskError, Option>)> { + let (call, lookup_len) = match T::Preimages::peek(&task.call) { + Ok(c) => c, + Err(_) => { + if let Some(ref id) = task.maybe_id { + Lookup::::remove(id); + } + + return Err((Unavailable, Some(task))); + } + }; + + weight.check_accrue(MarginalWeightInfo::::service_task( + lookup_len.map(|x| x as usize), + task.maybe_id.is_some(), + task.maybe_periodic.is_some(), + )); + + match Self::execute_dispatch(weight, task.origin.clone(), call) { + Err(Unavailable) => { + debug_assert!(false, "Checked to exist with `peek`"); + + if let Some(ref id) = task.maybe_id { + Lookup::::remove(id); + } + + Self::deposit_event(Event::CallUnavailable { + task: (when, agenda_index), + id: task.maybe_id, + }); + Err((Unavailable, Some(task))) + } + Err(Overweight) if is_first && !Self::is_runtime_upgraded() => { + T::Preimages::drop(&task.call); + + if let Some(ref id) = task.maybe_id { + Lookup::::remove(id); + } + + Self::deposit_event(Event::PermanentlyOverweight { + task: (when, agenda_index), + id: task.maybe_id, + }); + Err((Unavailable, Some(task))) + } + Err(Overweight) => { + // Preserve Lookup -- the task will be postponed. + Err((Overweight, Some(task))) + } + Ok(result) => { + Self::deposit_event(Event::Dispatched { + task: (when, agenda_index), + id: task.maybe_id, + result, + }); + + let is_canceled = task + .maybe_id + .as_ref() + .map(|id| !Lookup::::contains_key(id)) + .unwrap_or(false); + + match &task.maybe_periodic { + &Some((period, count)) if !is_canceled => { + if count > 1 { + task.maybe_periodic = Some((period, count - 1)); + } else { + task.maybe_periodic = None; + } + let wake = now.saturating_add(period); + Self::mandatory_place_task(wake, task); + } + _ => { + if let Some(ref id) = task.maybe_id { + Lookup::::remove(id); + } + + T::Preimages::drop(&task.call) + } + } + Ok(()) + } + } + } + + fn is_runtime_upgraded() -> bool { + let last = system::LastRuntimeUpgrade::::get(); + let current = T::Version::get(); + + last.map(|v| v.was_upgraded(¤t)).unwrap_or(true) + } + + /// Make a dispatch to the given `call` from the given `origin`, ensuring that the `weight` + /// counter does not exceed its limit and that it is counted accurately (e.g. accounted using + /// post info if available). + /// + /// NOTE: Only the weight for this function will be counted (origin lookup, dispatch and the + /// call itself). + fn execute_dispatch( + weight: &mut WeightCounter, + origin: T::PalletsOrigin, + call: ::RuntimeCall, + ) -> Result { + let dispatch_origin: ::RuntimeOrigin = origin.into(); + let base_weight = match dispatch_origin.clone().as_signed() { + Some(_) => T::WeightInfo::execute_dispatch_signed(), + _ => T::WeightInfo::execute_dispatch_unsigned(), + }; + let call_weight = call.get_dispatch_info().weight; + // We only allow a scheduled call if it cannot push the weight past the limit. + let max_weight = base_weight.saturating_add(call_weight); + + if !weight.can_accrue(max_weight) { + return Err(Overweight); + } + + let ensured_origin = T::ScheduleOrigin::ensure_origin(dispatch_origin.into()); + + let r = match ensured_origin { + Ok(ScheduledEnsureOriginSuccess::Root) => { + Ok(call.dispatch_bypass_filter(frame_system::RawOrigin::Root.into())) + } + Ok(ScheduledEnsureOriginSuccess::Signed(sender)) => { + // Execute transaction via chain default pipeline + // That means dispatch will be processed like any user's extrinsic e.g. transaction fees will be taken + T::CallExecutor::dispatch_call(Some(sender), call) + } + Err(e) => Ok(Err(e.into())), + }; + + let (maybe_actual_call_weight, result) = match r { + Ok(result) => match result { + Ok(post_info) => (post_info.actual_weight, Ok(())), + Err(error_and_info) => ( + error_and_info.post_info.actual_weight, + Err(error_and_info.error), + ), + }, + Err(_) => { + log::error!( + target: "runtime::scheduler", + "Warning: Scheduler has failed to execute a post-dispatch transaction. \ + This block might have become invalid."); + (None, Err(DispatchError::CannotLookup)) + } + }; + let call_weight = maybe_actual_call_weight.unwrap_or(call_weight); + weight.check_accrue(base_weight); + weight.check_accrue(call_weight); + Ok(result) + } +} diff --git a/pallets/scheduler-v2/src/mock.rs b/pallets/scheduler-v2/src/mock.rs new file mode 100644 index 0000000000..cce1575307 --- /dev/null +++ b/pallets/scheduler-v2/src/mock.rs @@ -0,0 +1,288 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +// Original license: +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Scheduler test environment. + +use super::*; + +use crate as scheduler; +use frame_support::{ + ord_parameter_types, parameter_types, + traits::{ConstU32, ConstU64, Contains, EqualPrivilegeOnly, OnFinalize, OnInitialize}, + weights::constants::RocksDbWeight, +}; +use frame_system::{EnsureRoot, RawOrigin}; +use sp_core::H256; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, +}; + +// Logger module to track execution. +#[frame_support::pallet] +pub mod logger { + use super::{OriginCaller, OriginTrait}; + use frame_support::{pallet_prelude::*, parameter_types}; + use frame_system::pallet_prelude::*; + + parameter_types! { + static Log: Vec<(OriginCaller, u32)> = Vec::new(); + } + pub fn log() -> Vec<(OriginCaller, u32)> { + Log::get().clone() + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + Logged(u32, Weight), + } + + #[pallet::call] + impl Pallet + where + ::RuntimeOrigin: OriginTrait, + { + #[pallet::call_index(0)] + #[pallet::weight(*weight)] + pub fn log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { + Self::deposit_event(Event::Logged(i, weight)); + Log::mutate(|log| { + log.push((origin.caller().clone(), i)); + }); + Ok(()) + } + + #[pallet::call_index(1)] + #[pallet::weight(*weight)] + pub fn log_without_filter(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { + Self::deposit_event(Event::Logged(i, weight)); + Log::mutate(|log| { + log.push((origin.caller().clone(), i)); + }); + Ok(()) + } + } +} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Logger: logger::{Pallet, Call, Event}, + Scheduler: scheduler::{Pallet, Call, Storage, Event}, + } +); + +// Scheduler must dispatch with root and no filter, this tests base filter is indeed not used. +pub struct BaseFilter; +impl Contains for BaseFilter { + fn contains(call: &RuntimeCall) -> bool { + !matches!(call, RuntimeCall::Logger(LoggerCall::log { .. })) + } +} + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max( + Weight::from_ref_time(2_000_000_000_000).set_proof_size(u64::MAX) + ); +} +impl system::Config for Test { + type BaseCallFilter = BaseFilter; + type BlockWeights = BlockWeights; + type BlockLength = (); + type DbWeight = RocksDbWeight; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} +impl logger::Config for Test { + type RuntimeEvent = RuntimeEvent; +} +ord_parameter_types! { + pub const One: u64 = 1; +} + +pub struct TestWeightInfo; +impl WeightInfo for TestWeightInfo { + fn service_agendas_base() -> Weight { + Weight::from_ref_time(0b0000_0001) + } + fn service_agenda_base(i: u32) -> Weight { + Weight::from_ref_time((i << 8) as u64 + 0b0000_0010) + } + fn service_task_base() -> Weight { + Weight::from_ref_time(0b0000_0100) + } + fn service_task_periodic() -> Weight { + Weight::from_ref_time(0b0000_1100) + } + fn service_task_named() -> Weight { + Weight::from_ref_time(0b0001_0100) + } + // fn service_task_fetched(s: u32) -> Weight { + // Weight::from_ref_time((s << 8) as u64 + 0b0010_0100) + // } + fn execute_dispatch_signed() -> Weight { + Weight::from_ref_time(0b0100_0000) + } + fn execute_dispatch_unsigned() -> Weight { + Weight::from_ref_time(0b1000_0000) + } + fn schedule(_s: u32) -> Weight { + Weight::from_ref_time(50) + } + fn cancel(_s: u32) -> Weight { + Weight::from_ref_time(50) + } + fn schedule_named(_s: u32) -> Weight { + Weight::from_ref_time(50) + } + fn cancel_named(_s: u32) -> Weight { + Weight::from_ref_time(50) + } + fn change_named_priority(_s: u32) -> Weight { + Weight::from_ref_time(50) + } +} +parameter_types! { + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * + BlockWeights::get().max_block; +} + +pub struct EnsureSignedOneOrRoot; +impl, O>> + From>> EnsureOrigin + for EnsureSignedOneOrRoot +{ + type Success = ScheduledEnsureOriginSuccess; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + RawOrigin::Root => Ok(ScheduledEnsureOriginSuccess::Root), + RawOrigin::Signed(1) => Ok(ScheduledEnsureOriginSuccess::Signed(1)), + r => Err(O::from(r)), + }) + } +} + +pub struct Executor; +impl DispatchCall for Executor { + fn dispatch_call( + signer: Option, + function: RuntimeCall, + ) -> Result< + Result>, + TransactionValidityError, + > { + let origin = match signer { + Some(who) => RuntimeOrigin::signed(who), + None => RuntimeOrigin::none(), + }; + Ok(function.dispatch(origin)) + } +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type MaximumWeight = MaximumSchedulerWeight; + type ScheduleOrigin = EnsureSignedOneOrRoot; + type MaxScheduledPerBlock = ConstU32<10>; + type WeightInfo = TestWeightInfo; + type OriginPrivilegeCmp = EqualPrivilegeOnly; + type Preimages = (); + type PrioritySetOrigin = EnsureRoot; + type CallExecutor = Executor; +} + +pub type LoggerCall = logger::Call; + +pub type SystemCall = frame_system::Call; + +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = system::GenesisConfig::default() + .build_storage::() + .unwrap(); + t.into() +} + +pub fn run_to_block(n: u64) { + while System::block_number() < n { + Scheduler::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + Scheduler::on_initialize(System::block_number()); + } +} + +pub fn root() -> OriginCaller { + system::RawOrigin::Root.into() +} diff --git a/pallets/scheduler-v2/src/tests.rs b/pallets/scheduler-v2/src/tests.rs new file mode 100644 index 0000000000..9dcf565e74 --- /dev/null +++ b/pallets/scheduler-v2/src/tests.rs @@ -0,0 +1,900 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +// Original license: +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Scheduler tests. + +use super::*; +use crate::mock::{ + logger, new_test_ext, root, run_to_block, LoggerCall, RuntimeCall, Scheduler, Test, *, +}; +use frame_support::{ + assert_noop, assert_ok, + traits::{Contains, OnInitialize}, + assert_err, +}; + +#[test] +fn basic_scheduling_works() { + new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + }); + assert!(!::BaseCallFilter::contains( + &call + )); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + >::new(call).unwrap(), + )); + run_to_block(3); + assert!(logger::log().is_empty()); + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn schedule_after_works() { + new_test_ext().execute_with(|| { + run_to_block(2); + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + }); + assert!(!::BaseCallFilter::contains( + &call + )); + // This will schedule the call 3 blocks after the next block... so block 3 + 3 = 6 + assert_ok!(Scheduler::do_schedule( + DispatchTime::After(3), + None, + 127, + root(), + >::new(call).unwrap(), + )); + run_to_block(5); + assert!(logger::log().is_empty()); + run_to_block(6); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn schedule_after_zero_works() { + new_test_ext().execute_with(|| { + run_to_block(2); + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + }); + assert!(!::BaseCallFilter::contains( + &call + )); + assert_ok!(Scheduler::do_schedule( + DispatchTime::After(0), + None, + 127, + root(), + >::new(call).unwrap(), + )); + // Will trigger on the next block. + run_to_block(3); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn periodic_scheduling_works() { + new_test_ext().execute_with(|| { + // at #4, every 3 blocks, 3 times. + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + Some((3, 3)), + 127, + root(), + >::new(RuntimeCall::Logger(logger::Call::log { + i: 42, + weight: Weight::from_ref_time(10) + })) + .unwrap() + )); + run_to_block(3); + assert!(logger::log().is_empty()); + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(6); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(7); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + run_to_block(9); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]); + run_to_block(10); + assert_eq!( + logger::log(), + vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)] + ); + run_to_block(100); + assert_eq!( + logger::log(), + vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)] + ); + }); +} + +#[test] +fn cancel_named_scheduling_works_with_normal_cancel() { + new_test_ext().execute_with(|| { + // at #4. + Scheduler::do_schedule_named( + [1u8; 32], + DispatchTime::At(4), + None, + 127, + root(), + >::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })) + .unwrap(), + ) + .unwrap(); + let i = Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + >::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })) + .unwrap(), + ) + .unwrap(); + run_to_block(3); + assert!(logger::log().is_empty()); + assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32])); + assert_ok!(Scheduler::do_cancel(None, i)); + run_to_block(100); + assert!(logger::log().is_empty()); + }); +} + +#[test] +fn cancel_named_periodic_scheduling_works() { + new_test_ext().execute_with(|| { + // at #4, every 3 blocks, 3 times. + Scheduler::do_schedule_named( + [1u8; 32], + DispatchTime::At(4), + Some((3, 3)), + 127, + root(), + >::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })) + .unwrap(), + ) + .unwrap(); + // same id results in error. + assert!(Scheduler::do_schedule_named( + [1u8; 32], + DispatchTime::At(4), + None, + 127, + root(), + >::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10) + })) + .unwrap(), + ) + .is_err()); + // different id is ok. + Scheduler::do_schedule_named( + [2u8; 32], + DispatchTime::At(8), + None, + 127, + root(), + >::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })) + .unwrap(), + ) + .unwrap(); + run_to_block(3); + assert!(logger::log().is_empty()); + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(6); + assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32])); + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); + }); +} + +#[test] +fn scheduler_respects_weight_limits() { + let max_weight: Weight = ::MaximumWeight::get(); + new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: max_weight / 3 * 2, + }); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + >::new(call).unwrap(), + )); + let call = RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: max_weight / 3 * 2, + }); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + >::new(call).unwrap(), + )); + // 69 and 42 do not fit together + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + run_to_block(5); + assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); + }); +} + +/// Permanently overweight calls are not deleted but also not executed. +#[test] +fn scheduler_does_not_delete_permanently_overweight_call() { + let max_weight: Weight = ::MaximumWeight::get(); + new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: max_weight, + }); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + >::new(call).unwrap(), + )); + // Never executes. + run_to_block(100); + assert_eq!(logger::log(), vec![]); + + // Assert the `PermanentlyOverweight` event. + assert_eq!( + System::events().last().unwrap().event, + crate::Event::PermanentlyOverweight { + task: (4, 0), + id: None + } + .into(), + ); + // The call is still in the agenda. + assert!(Agenda::::get(4).agenda[0].is_some()); + }); +} + +#[test] +fn scheduler_periodic_tasks_always_find_place() { + let max_weight: Weight = ::MaximumWeight::get(); + let max_per_block = ::MaxScheduledPerBlock::get(); + + new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: (max_weight / 3) * 2, + }); + let call = >::new(call).unwrap(); + + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + Some((4, u32::MAX)), + 127, + root(), + call.clone(), + )); + // Executes 5 times till block 20. + run_to_block(20); + assert_eq!(logger::log().len(), 5); + + // Block 28 will already be full. + for _ in 0..max_per_block { + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(28), + None, + 120, + root(), + call.clone(), + )); + } + + run_to_block(24); + assert_eq!(logger::log().len(), 6); + + // The periodic task should be postponed + assert_eq!(>::get(29).agenda.len(), 1); + + run_to_block(27); // will call on_initialize(28) + assert_eq!(logger::log().len(), 6); + + run_to_block(28); // will call on_initialize(29) + assert_eq!(logger::log().len(), 7); + }); +} + +#[test] +fn scheduler_respects_priority_ordering() { + let max_weight: Weight = ::MaximumWeight::get(); + new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: max_weight / 3, + }); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 1, + root(), + >::new(call).unwrap(), + )); + let call = RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: max_weight / 3, + }); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 0, + root(), + >::new(call).unwrap(), + )); + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]); + }); +} + +#[test] +fn scheduler_respects_priority_ordering_with_soft_deadlines() { + new_test_ext().execute_with(|| { + let max_weight: Weight = ::MaximumWeight::get(); + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: max_weight / 5 * 2, + }); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 255, + root(), + >::new(call).unwrap(), + )); + let call = RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: max_weight / 5 * 2, + }); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + >::new(call).unwrap(), + )); + let call = RuntimeCall::Logger(LoggerCall::log { + i: 2600, + weight: max_weight / 5 * 4, + }); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 126, + root(), + >::new(call).unwrap(), + )); + + // 2600 does not fit with 69 or 42, but has higher priority, so will go through + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 2600u32)]); + // 69 and 42 fit together + run_to_block(5); + assert_eq!( + logger::log(), + vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)] + ); + }); +} + +#[test] +fn on_initialize_weight_is_correct() { + new_test_ext().execute_with(|| { + let call_weight = Weight::from_ref_time(25); + + // Named + let call = RuntimeCall::Logger(LoggerCall::log { + i: 3, + weight: call_weight + Weight::from_ref_time(1), + }); + assert_ok!(Scheduler::do_schedule_named( + [1u8; 32], + DispatchTime::At(3), + None, + 255, + root(), + >::new(call).unwrap(), + )); + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: call_weight + Weight::from_ref_time(2), + }); + // Anon Periodic + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(2), + Some((1000, 3)), + 128, + root(), + >::new(call).unwrap(), + )); + let call = RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: call_weight + Weight::from_ref_time(3), + }); + // Anon + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(2), + None, + 127, + root(), + >::new(call).unwrap(), + )); + // Named Periodic + let call = RuntimeCall::Logger(LoggerCall::log { + i: 2600, + weight: call_weight + Weight::from_ref_time(4), + }); + assert_ok!(Scheduler::do_schedule_named( + [2u8; 32], + DispatchTime::At(1), + Some((1000, 3)), + 126, + root(), + >::new(call).unwrap(), + )); + + // Will include the named periodic only + assert_eq!( + Scheduler::on_initialize(1), + TestWeightInfo::service_agendas_base() + + TestWeightInfo::service_agenda_base(1) + + >::service_task(None, true, true) + + TestWeightInfo::execute_dispatch_unsigned() + + call_weight + Weight::from_ref_time(4) + ); + assert_eq!(IncompleteSince::::get(), None); + assert_eq!(logger::log(), vec![(root(), 2600u32)]); + + // Will include anon and anon periodic + assert_eq!( + Scheduler::on_initialize(2), + TestWeightInfo::service_agendas_base() + + TestWeightInfo::service_agenda_base(2) + + >::service_task(None, false, true) + + TestWeightInfo::execute_dispatch_unsigned() + + call_weight + Weight::from_ref_time(3) + + >::service_task(None, false, false) + + TestWeightInfo::execute_dispatch_unsigned() + + call_weight + Weight::from_ref_time(2) + ); + assert_eq!(IncompleteSince::::get(), None); + assert_eq!( + logger::log(), + vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)] + ); + + // Will include named only + assert_eq!( + Scheduler::on_initialize(3), + TestWeightInfo::service_agendas_base() + + TestWeightInfo::service_agenda_base(1) + + >::service_task(None, true, false) + + TestWeightInfo::execute_dispatch_unsigned() + + call_weight + Weight::from_ref_time(1) + ); + assert_eq!(IncompleteSince::::get(), None); + assert_eq!( + logger::log(), + vec![ + (root(), 2600u32), + (root(), 69u32), + (root(), 42u32), + (root(), 3u32) + ] + ); + + // Will contain none + let actual_weight = Scheduler::on_initialize(4); + assert_eq!( + actual_weight, + TestWeightInfo::service_agendas_base() + TestWeightInfo::service_agenda_base(0) + ); + }); +} + +#[test] +fn root_calls_works() { + new_test_ext().execute_with(|| { + let call = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); + assert_ok!(Scheduler::schedule_named( + RuntimeOrigin::root(), + [1u8; 32], + 4, + None, + Some(127), + call, + )); + assert_ok!(Scheduler::schedule( + RuntimeOrigin::root(), + 4, + None, + Some(127), + call2 + )); + run_to_block(3); + // Scheduled calls are in the agenda. + assert_eq!(Agenda::::get(4).agenda.len(), 2); + assert!(logger::log().is_empty()); + assert_ok!(Scheduler::cancel_named(RuntimeOrigin::root(), [1u8; 32])); + assert_ok!(Scheduler::cancel(RuntimeOrigin::root(), 4, 1)); + // Scheduled calls are made NONE, so should not effect state + run_to_block(100); + assert!(logger::log().is_empty()); + }); +} + +#[test] +fn fails_to_schedule_task_in_the_past() { + new_test_ext().execute_with(|| { + run_to_block(3); + + let call1 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); + let call3 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); + + assert_noop!( + Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 2, None, Some(127), call1), + Error::::TargetBlockNumberInPast, + ); + + assert_noop!( + Scheduler::schedule(RuntimeOrigin::root(), 2, None, Some(127), call2), + Error::::TargetBlockNumberInPast, + ); + + assert_noop!( + Scheduler::schedule(RuntimeOrigin::root(), 3, None, Some(127), call3), + Error::::TargetBlockNumberInPast, + ); + }); +} + +#[test] +fn should_use_origin() { + new_test_ext().execute_with(|| { + let call = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); + assert_ok!(Scheduler::schedule_named( + system::RawOrigin::Signed(1).into(), + [1u8; 32], + 4, + None, + None, + call, + )); + assert_ok!(Scheduler::schedule( + system::RawOrigin::Signed(1).into(), + 4, + None, + None, + call2, + )); + run_to_block(3); + // Scheduled calls are in the agenda. + assert_eq!(Agenda::::get(4).agenda.len(), 2); + assert!(logger::log().is_empty()); + assert_ok!(Scheduler::cancel_named( + system::RawOrigin::Signed(1).into(), + [1u8; 32] + )); + assert_ok!(Scheduler::cancel(system::RawOrigin::Signed(1).into(), 4, 1)); + // Scheduled calls are made NONE, so should not effect state + run_to_block(100); + assert!(logger::log().is_empty()); + }); +} + +#[test] +fn should_check_origin() { + new_test_ext().execute_with(|| { + let call = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); + assert_noop!( + Scheduler::schedule_named( + system::RawOrigin::Signed(2).into(), + [1u8; 32], + 4, + None, + None, + call + ), + BadOrigin + ); + assert_noop!( + Scheduler::schedule(system::RawOrigin::Signed(2).into(), 4, None, None, call2), + BadOrigin + ); + }); +} + +#[test] +fn should_check_origin_for_cancel() { + new_test_ext().execute_with(|| { + let call = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter { + i: 42, + weight: Weight::from_ref_time(10), + })); + assert_ok!(Scheduler::schedule_named( + system::RawOrigin::Signed(1).into(), + [1u8; 32], + 4, + None, + None, + call, + )); + assert_ok!(Scheduler::schedule( + system::RawOrigin::Signed(1).into(), + 4, + None, + None, + call2, + )); + run_to_block(3); + // Scheduled calls are in the agenda. + assert_eq!(Agenda::::get(4).agenda.len(), 2); + assert!(logger::log().is_empty()); + assert_noop!( + Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), [1u8; 32]), + BadOrigin + ); + assert_noop!( + Scheduler::cancel(system::RawOrigin::Signed(2).into(), 4, 1), + BadOrigin + ); + assert_noop!( + Scheduler::cancel_named(system::RawOrigin::Root.into(), [1u8; 32]), + BadOrigin + ); + assert_noop!( + Scheduler::cancel(system::RawOrigin::Root.into(), 4, 1), + BadOrigin + ); + run_to_block(5); + assert_eq!( + logger::log(), + vec![ + (system::RawOrigin::Signed(1).into(), 69u32), + (system::RawOrigin::Signed(1).into(), 42u32) + ] + ); + }); +} + +/// Cancelling a call and then scheduling a second call for the same +/// block results in different addresses. +#[test] +fn schedule_does_not_resuse_addr() { + new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + }); + + // Schedule both calls. + let addr_1 = Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + >::new(call.clone()).unwrap(), + ) + .unwrap(); + // Cancel the call. + assert_ok!(Scheduler::do_cancel(None, addr_1)); + let addr_2 = Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + >::new(call).unwrap(), + ) + .unwrap(); + + // Should not re-use the address. + assert!(addr_1 != addr_2); + }); +} + +#[test] +fn schedule_agenda_overflows() { + let max: u32 = ::MaxScheduledPerBlock::get(); + + new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + }); + let call = >::new(call).unwrap(); + + // Schedule the maximal number allowed per block. + for _ in 0..max { + Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.clone()).unwrap(); + } + + // One more time and it errors. + assert_noop!( + Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call,), + >::AgendaIsExhausted, + ); + + run_to_block(4); + // All scheduled calls are executed. + assert_eq!(logger::log().len() as u32, max); + }); +} + +/// Cancelling and scheduling does not overflow the agenda but fills holes. +#[test] +fn cancel_and_schedule_fills_holes() { + let max: u32 = ::MaxScheduledPerBlock::get(); + assert!( + max > 3, + "This test only makes sense for MaxScheduledPerBlock > 3" + ); + + new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + }); + let call = >::new(call).unwrap(); + let mut addrs = Vec::<_>::default(); + + // Schedule the maximal number allowed per block. + for _ in 0..max { + addrs.push( + Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.clone()) + .unwrap(), + ); + } + // Cancel three of them. + for addr in addrs.into_iter().take(3) { + Scheduler::do_cancel(None, addr).unwrap(); + } + // Schedule three new ones. + for i in 0..3 { + let (_block, index) = + Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.clone()) + .unwrap(); + assert_eq!(i, index); + } + + run_to_block(4); + // Maximum number of calls are executed. + assert_eq!(logger::log().len() as u32, max); + }); +} + +#[test] +fn cannot_schedule_too_big_tasks() { + new_test_ext().execute_with(|| { + let call = Box::new(<::RuntimeCall>::from(SystemCall::remark { + remark: vec![0; EncodedCall::bound() - 4], + })); + + assert_ok!(Scheduler::schedule( + RuntimeOrigin::root(), + 4, + None, + Some(127), + call + )); + + let call = Box::new(<::RuntimeCall>::from(SystemCall::remark { + remark: vec![0; EncodedCall::bound() - 3], + })); + + assert_err!( + Scheduler::schedule(RuntimeOrigin::root(), 4, None, Some(127), call), + >::TooBigScheduledCall + ); + }); +} diff --git a/pallets/scheduler-v2/src/weights.rs b/pallets/scheduler-v2/src/weights.rs new file mode 100644 index 0000000000..1aaa19377d --- /dev/null +++ b/pallets/scheduler-v2/src/weights.rs @@ -0,0 +1,234 @@ +// Template adopted from https://github.com/paritytech/substrate/blob/master/.maintain/frame-weight-template.hbs + +//! Autogenerated weights for pallet_unique_scheduler_v2 +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-10-28, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// target/release/unique-collator +// benchmark +// pallet +// --pallet +// pallet-unique-scheduler-v2 +// --wasm-execution +// compiled +// --extrinsic +// * +// --template +// .maintain/frame-weight-template.hbs +// --steps=50 +// --repeat=80 +// --heap-pages=4096 +// --output=./pallets/scheduler-v2/src/weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] +#![allow(clippy::unnecessary_cast)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_unique_scheduler_v2. +pub trait WeightInfo { + fn service_agendas_base() -> Weight; + fn service_agenda_base(s: u32, ) -> Weight; + fn service_task_base() -> Weight; + fn service_task_named() -> Weight; + fn service_task_periodic() -> Weight; + fn execute_dispatch_signed() -> Weight; + fn execute_dispatch_unsigned() -> Weight; + fn schedule(s: u32, ) -> Weight; + fn cancel(s: u32, ) -> Weight; + fn schedule_named(s: u32, ) -> Weight; + fn cancel_named(s: u32, ) -> Weight; + fn change_named_priority(s: u32, ) -> Weight; +} + +/// Weights for pallet_unique_scheduler_v2 using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: Scheduler IncompleteSince (r:1 w:1) + fn service_agendas_base() -> Weight { + Weight::from_ref_time(5_253_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: Scheduler Agenda (r:1 w:1) + fn service_agenda_base(s: u32, ) -> Weight { + Weight::from_ref_time(3_858_000 as u64) + // Standard Error: 2_617 + .saturating_add(Weight::from_ref_time(579_704 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: System LastRuntimeUpgrade (r:1 w:0) + fn service_task_base() -> Weight { + Weight::from_ref_time(10_536_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + } + // Storage: System LastRuntimeUpgrade (r:1 w:0) + // Storage: Scheduler Lookup (r:0 w:1) + fn service_task_named() -> Weight { + Weight::from_ref_time(12_018_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: System LastRuntimeUpgrade (r:1 w:0) + fn service_task_periodic() -> Weight { + Weight::from_ref_time(10_669_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + } + // Storage: System Account (r:1 w:1) + // Storage: System AllExtrinsicsLen (r:1 w:1) + // Storage: System BlockWeight (r:1 w:1) + // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0) + // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) + fn execute_dispatch_signed() -> Weight { + Weight::from_ref_time(36_083_000 as u64) + .saturating_add(T::DbWeight::get().reads(5 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + } + fn execute_dispatch_unsigned() -> Weight { + Weight::from_ref_time(4_386_000 as u64) + } + // Storage: Scheduler Agenda (r:1 w:1) + fn schedule(s: u32, ) -> Weight { + Weight::from_ref_time(17_257_000 as u64) + // Standard Error: 2_791 + .saturating_add(Weight::from_ref_time(574_832 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn cancel(s: u32, ) -> Weight { + Weight::from_ref_time(19_803_000 as u64) + // Standard Error: 1_177 + .saturating_add(Weight::from_ref_time(475_027 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + } + // Storage: Scheduler Lookup (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn schedule_named(s: u32, ) -> Weight { + Weight::from_ref_time(18_746_000 as u64) + // Standard Error: 2_997 + .saturating_add(Weight::from_ref_time(635_697 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + } + // Storage: Scheduler Lookup (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn cancel_named(s: u32, ) -> Weight { + Weight::from_ref_time(20_983_000 as u64) + // Standard Error: 1_850 + .saturating_add(Weight::from_ref_time(518_812 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + } + // Storage: Scheduler Lookup (r:1 w:0) + // Storage: Scheduler Agenda (r:1 w:1) + fn change_named_priority(s: u32, ) -> Weight { + Weight::from_ref_time(21_591_000 as u64) + // Standard Error: 4_187 + .saturating_add(Weight::from_ref_time(531_231 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: Scheduler IncompleteSince (r:1 w:1) + fn service_agendas_base() -> Weight { + Weight::from_ref_time(5_253_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + // Storage: Scheduler Agenda (r:1 w:1) + fn service_agenda_base(s: u32, ) -> Weight { + Weight::from_ref_time(3_858_000 as u64) + // Standard Error: 2_617 + .saturating_add(Weight::from_ref_time(579_704 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + // Storage: System LastRuntimeUpgrade (r:1 w:0) + fn service_task_base() -> Weight { + Weight::from_ref_time(10_536_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + } + // Storage: System LastRuntimeUpgrade (r:1 w:0) + // Storage: Scheduler Lookup (r:0 w:1) + fn service_task_named() -> Weight { + Weight::from_ref_time(12_018_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + // Storage: System LastRuntimeUpgrade (r:1 w:0) + fn service_task_periodic() -> Weight { + Weight::from_ref_time(10_669_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + } + // Storage: System Account (r:1 w:1) + // Storage: System AllExtrinsicsLen (r:1 w:1) + // Storage: System BlockWeight (r:1 w:1) + // Storage: Configuration WeightToFeeCoefficientOverride (r:1 w:0) + // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) + fn execute_dispatch_signed() -> Weight { + Weight::from_ref_time(36_083_000 as u64) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + } + fn execute_dispatch_unsigned() -> Weight { + Weight::from_ref_time(4_386_000 as u64) + } + // Storage: Scheduler Agenda (r:1 w:1) + fn schedule(s: u32, ) -> Weight { + Weight::from_ref_time(17_257_000 as u64) + // Standard Error: 2_791 + .saturating_add(Weight::from_ref_time(574_832 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + // Storage: Scheduler Agenda (r:1 w:1) + // Storage: Scheduler Lookup (r:0 w:1) + fn cancel(s: u32, ) -> Weight { + Weight::from_ref_time(19_803_000 as u64) + // Standard Error: 1_177 + .saturating_add(Weight::from_ref_time(475_027 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + } + // Storage: Scheduler Lookup (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn schedule_named(s: u32, ) -> Weight { + Weight::from_ref_time(18_746_000 as u64) + // Standard Error: 2_997 + .saturating_add(Weight::from_ref_time(635_697 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + } + // Storage: Scheduler Lookup (r:1 w:1) + // Storage: Scheduler Agenda (r:1 w:1) + fn cancel_named(s: u32, ) -> Weight { + Weight::from_ref_time(20_983_000 as u64) + // Standard Error: 1_850 + .saturating_add(Weight::from_ref_time(518_812 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + } + // Storage: Scheduler Lookup (r:1 w:0) + // Storage: Scheduler Agenda (r:1 w:1) + fn change_named_priority(s: u32, ) -> Weight { + Weight::from_ref_time(21_591_000 as u64) + // Standard Error: 4_187 + .saturating_add(Weight::from_ref_time(531_231 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } +} diff --git a/pallets/scheduler/CHANGELOG.md b/pallets/scheduler/CHANGELOG.md deleted file mode 100644 index 732ab15dc7..0000000000 --- a/pallets/scheduler/CHANGELOG.md +++ /dev/null @@ -1,10 +0,0 @@ - -## [v0.1.1] 2022-08-16 - -### Other changes - -- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a - -- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8 - -- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b \ No newline at end of file diff --git a/pallets/scheduler/README.md b/pallets/scheduler/README.md deleted file mode 100644 index 3d07818b15..0000000000 --- a/pallets/scheduler/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Scheduler -A module for scheduling dispatches. - -- [`scheduler::Trait`](https://docs.rs/pallet-scheduler/latest/pallet_scheduler/trait.Trait.html) -- [`Call`](https://docs.rs/pallet-scheduler/latest/pallet_scheduler/enum.Call.html) -- [`Module`](https://docs.rs/pallet-scheduler/latest/pallet_scheduler/struct.Module.html) - -## Overview - -This module exposes capabilities for scheduling dispatches to occur at a -specified block number or at a specified period. These scheduled dispatches -may be named or anonymous and may be canceled. - -**NOTE:** The scheduled calls will be dispatched with the default filter -for the origin: namely `frame_system::Config::BaseCallFilter` for all origin -except root which will get no filter. And not the filter contained in origin -use to call `fn schedule`. - -If a call is scheduled using proxy or whatever mecanism which adds filter, -then those filter will not be used when dispatching the schedule call. - -## Interface - -### Dispatchable Functions - -* `schedule` - schedule a dispatch, which may be periodic, to occur at a - specified block and with a specified priority. -* `cancel` - cancel a scheduled dispatch, specified by block number and - index. -* `schedule_named` - augments the `schedule` interface with an additional - `Vec` parameter that can be used for identification. -* `cancel_named` - the named complement to the cancel function. - -License: Unlicense diff --git a/pallets/scheduler/src/benchmarking.rs b/pallets/scheduler/src/benchmarking.rs deleted file mode 100644 index eb60ce2791..0000000000 --- a/pallets/scheduler/src/benchmarking.rs +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. -// This file is part of Unique Network. - -// Unique Network is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Unique Network is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Unique Network. If not, see . - -// Original license -// This file is part of Substrate. - -// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Scheduler pallet benchmarking. - -use super::*; -use frame_benchmarking::{benchmarks, account}; -use frame_support::{ - ensure, - traits::{OnInitialize}, -}; -use frame_system::RawOrigin; -use sp_runtime::traits::Hash; -use sp_std::{prelude::*, vec}; - -use crate::Pallet as Scheduler; -use frame_system::Pallet as System; -use frame_support::traits::Currency; - -const BLOCK_NUMBER: u32 = 2; - -/// Add `n` named items to the schedule. -/// -/// For `resolved`: -/// - `None`: aborted (hash without preimage) -/// - `Some(true)`: hash resolves into call if possible, plain call otherwise -/// - `Some(false)`: plain call -fn fill_schedule( - when: T::BlockNumber, - n: u32, - periodic: bool, - resolved: Option, -) -> Result<(), &'static str> { - let t = DispatchTime::At(when); - let caller = account("user", 0, 1); - - // Give the sender account max funds for transfer (their account will never reasonably be killed). - T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); - - for i in 0..n { - let (call, hash) = call_and_hash::(i); - let call_or_hash = match resolved { - Some(_) => call.into(), - None => CallOrHashOf::::Hash(hash), - }; - let period = match periodic { - true => Some(((i + 100).into(), 100)), - false => None, - }; - - let slice_id: [u8; 4] = i.encode().try_into().unwrap(); - let mut id: [u8; 16] = [0; 16]; - id[..4].clone_from_slice(&slice_id); - - let origin = frame_system::RawOrigin::Signed(caller.clone()).into(); - Scheduler::::do_schedule_named(id, t, period, 0, origin, call_or_hash)?; - } - ensure!( - Agenda::::get(when).len() == n as usize, - "didn't fill schedule" - ); - Ok(()) -} - -fn call_and_hash(i: u32) -> (::RuntimeCall, T::Hash) { - // Essentially a no-op call. - let call: ::RuntimeCall = frame_system::Call::remark { remark: i.encode() }.into(); - let hash = T::Hashing::hash_of(&call); - (call, hash) -} - -benchmarks! { - on_initialize_periodic_named_resolved { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, Some(true))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s); - for i in 0..s { - assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); - } - } - - on_initialize_named_resolved { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, Some(true))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s); - assert!(Agenda::::iter().count() == 0); - } - - on_initialize_periodic { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, Some(false))?; - }: { Scheduler::::on_initialize(when); } - verify { - assert_eq!(System::::event_count(), s); - for i in 0..s { - assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); - } - } - - on_initialize_periodic_resolved { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, Some(true))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s ); - for i in 0..s { - assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); - } - } - - on_initialize_aborted { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, None)?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), 0); - } - - on_initialize_named_aborted { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, Some(false))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - } - - on_initialize_named { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, None)?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), 0); - } - - on_initialize { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, Some(false))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s); - assert!(Agenda::::iter().count() == 0); - } - - on_initialize_resolved { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, Some(true))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s); - assert!(Agenda::::iter().count() == 0); - } - - schedule_named { - let caller: T::AccountId = account("user", 0, 1); - let origin: RawOrigin = frame_system::RawOrigin::Signed(caller.clone()); - let s in 0 .. T::MaxScheduledPerBlock::get(); - let slice_id: [u8; 4] = s.encode().try_into().unwrap(); - let mut id: [u8; 16] = [0; 16]; - id[..4].clone_from_slice(&slice_id); - let when = BLOCK_NUMBER.into(); - let periodic = Some((T::BlockNumber::one(), 100)); - let priority = 0; - // Essentially a no-op call. - let inner_call = frame_system::Call::set_storage { items: vec![] }.into(); - let call = Box::new(CallOrHashOf::::Value(inner_call)); - fill_schedule::(when, s, true, Some(false))?; - }: _(origin, id, when, periodic, priority, call) - verify { - ensure!( - Agenda::::get(when).len() == (s + 1) as usize, - "didn't add to schedule" - ); - } - - cancel_named { - let caller: T::AccountId = account("user", 0, 1); - let origin: RawOrigin = frame_system::RawOrigin::Signed(caller.clone()); - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - let id = 0.encode().try_into().unwrap_or([0; MAX_TASK_ID_LENGTH_IN_BYTES as usize]); - fill_schedule::(when, s, true, Some(false))?; - }: _(origin, id) - verify { - ensure!( - Lookup::::get(id).is_none(), - "didn't remove from lookup" - ); - // Removed schedule is NONE - ensure!( - Agenda::::get(when)[0].is_none(), - "didn't remove from schedule" - ); - } - - impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test); -} diff --git a/pallets/scheduler/src/lib.rs b/pallets/scheduler/src/lib.rs deleted file mode 100644 index 57bbf00bfb..0000000000 --- a/pallets/scheduler/src/lib.rs +++ /dev/null @@ -1,722 +0,0 @@ -// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. -// This file is part of Unique Network. - -// Unique Network is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Unique Network is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Unique Network. If not, see . - -// Original license: -// This file is part of Substrate. - -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! # Unique scheduler -//! A Pallet for scheduling dispatches. -//! -//! - [`Config`] -//! - [`Call`] -//! - [`Pallet`] -//! -//! ## Overview -//! -//! This Pallet exposes capabilities for scheduling dispatches to occur at a -//! specified block number or at a specified period. These scheduled dispatches -//! should be named and may be canceled. -//! -//! **NOTE:** The unique scheduler is designed for deferred transaction calls by block number. -//! Any user can book a call of a certain transaction to a specific block number. -//! Also possible to book a call with a certain frequency. -//! -//! Key differences from the original pallet: -//! -//! Schedule Id restricted by 16 bytes. Identificator for booked call. -//! Priority limited by HARD DEADLINE (<= 63). Calls over maximum weight don't include to block. -//! The maximum weight that may be scheduled per block for any dispatchables of less priority than `schedule::HARD_DEADLINE`. -//! Maybe_periodic limit is 100 calls. Reserved for future sponsored transaction support. -//! At 100 calls reserved amount is not so much and this is avoid potential problems with balance locks. -//! Any account allowed to schedule any calls. Account withdraw implemented through default transaction logic. -//! -//! ## Interface -//! -//! ### Dispatchable Functions -//! -//! * `schedule_named` - augments the `schedule` interface with an additional `Vec` parameter -//! that can be used for identification. -//! * `cancel_named` - the named complement to the cancel function. - -// Ensure we're `no_std` when compiling for Wasm. -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; - -pub mod weights; - -use sp_core::H160; -use codec::{Codec, Decode, Encode}; -use frame_system::{self as system, ensure_signed}; -pub use pallet::*; -use scale_info::TypeInfo; -use sp_runtime::{ - traits::{BadOrigin, One, Saturating, Zero}, - RuntimeDebug, DispatchErrorWithPostInfo, -}; -use sp_std::{borrow::Borrow, cmp::Ordering, marker::PhantomData, prelude::*}; - -use frame_support::{ - dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter, GetDispatchInfo}, - traits::{ - schedule::{self, DispatchTime, MaybeHashed}, - NamedReservableCurrency, EnsureOrigin, Get, IsType, OriginTrait, PrivilegeCmp, - StorageVersion, - }, - weights::{Weight}, -}; - -pub use weights::WeightInfo; - -/// Just a simple index for naming period tasks. -pub type PeriodicIndex = u32; -/// The location of a scheduled task that can be used to remove it. -pub type TaskAddress = (BlockNumber, u32); -pub const MAX_TASK_ID_LENGTH_IN_BYTES: u8 = 16; - -type ScheduledId = [u8; MAX_TASK_ID_LENGTH_IN_BYTES as usize]; -pub type CallOrHashOf = - MaybeHashed<::RuntimeCall, ::Hash>; - -/// Information regarding an item to be executed in the future. -#[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] -#[derive(Clone, RuntimeDebug, Encode, Decode, TypeInfo)] -pub struct ScheduledV3 { - /// The unique identity for this task, if there is one. - maybe_id: Option, - /// This task's priority. - priority: schedule::Priority, - /// The call to be dispatched. - call: Call, - /// If the call is periodic, then this points to the information concerning that. - maybe_periodic: Option>, - /// The origin to dispatch the call. - origin: PalletsOrigin, - _phantom: PhantomData, -} - -pub type ScheduledV3Of = ScheduledV3< - CallOrHashOf, - ::BlockNumber, - ::PalletsOrigin, - ::AccountId, ->; - -pub type ScheduledOf = ScheduledV3Of; - -/// The current version of Scheduled struct. -pub type Scheduled = - ScheduledV3; - -#[cfg(feature = "runtime-benchmarks")] -mod preimage_provider { - use frame_support::traits::PreimageRecipient; - pub trait PreimageProviderAndMaybeRecipient: PreimageRecipient {} - impl> PreimageProviderAndMaybeRecipient for T {} -} - -#[cfg(not(feature = "runtime-benchmarks"))] -mod preimage_provider { - use frame_support::traits::PreimageProvider; - pub trait PreimageProviderAndMaybeRecipient: PreimageProvider {} - impl> PreimageProviderAndMaybeRecipient for T {} -} - -pub use preimage_provider::PreimageProviderAndMaybeRecipient; - -pub(crate) trait MarginalWeightInfo: WeightInfo { - fn item(periodic: bool, named: bool, resolved: Option) -> Weight { - match (periodic, named, resolved) { - (_, false, None) => Self::on_initialize_aborted(2) - Self::on_initialize_aborted(1), - (_, true, None) => { - Self::on_initialize_named_aborted(2) - Self::on_initialize_named_aborted(1) - } - (false, false, Some(false)) => Self::on_initialize(2) - Self::on_initialize(1), - (false, true, Some(false)) => { - Self::on_initialize_named(2) - Self::on_initialize_named(1) - } - (true, false, Some(false)) => { - Self::on_initialize_periodic(2) - Self::on_initialize_periodic(1) - } - (true, true, Some(false)) => { - Self::on_initialize_periodic_named_resolved(2) - - Self::on_initialize_periodic_named_resolved(1) - } - (false, false, Some(true)) => Self::on_initialize(2) - Self::on_initialize(1), - (false, true, Some(true)) => { - Self::on_initialize_named_resolved(2) - Self::on_initialize_named_resolved(1) - } - (true, false, Some(true)) => { - Self::on_initialize_periodic_resolved(2) - Self::on_initialize_periodic_resolved(1) - } - (true, true, Some(true)) => { - Self::on_initialize_periodic_named_resolved(2) - - Self::on_initialize_periodic_named_resolved(1) - } - } - } -} -impl MarginalWeightInfo for T {} - -#[frame_support::pallet] -pub mod pallet { - use super::*; - use frame_support::{ - dispatch::PostDispatchInfo, - pallet_prelude::*, - traits::{schedule::LookupError, PreimageProvider}, - }; - use frame_system::pallet_prelude::*; - - /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - #[pallet::storage_version(STORAGE_VERSION)] - #[pallet::without_storage_info] - pub struct Pallet(_); - - /// `system::Config` should always be included in our implied traits. - #[pallet::config] - pub trait Config: frame_system::Config { - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// The aggregated origin which the dispatch will take. - type RuntimeOrigin: OriginTrait - + From - + IsType<::RuntimeOrigin>; - - /// The caller origin, overarching type of all pallets origins. - type PalletsOrigin: From> + Codec + Clone + Eq + TypeInfo; - - type Currency: NamedReservableCurrency; - - /// The aggregated call type. - type RuntimeCall: Parameter - + Dispatchable< - RuntimeOrigin = ::RuntimeOrigin, - PostInfo = PostDispatchInfo, - > + GetDispatchInfo - + From>; - - /// The maximum weight that may be scheduled per block for any dispatchables of less - /// priority than `schedule::HARD_DEADLINE`. - #[pallet::constant] - type MaximumWeight: Get; - - /// Required origin to schedule or cancel calls. - type ScheduleOrigin: EnsureOrigin<::RuntimeOrigin>; - - /// Compare the privileges of origins. - /// - /// This will be used when canceling a task, to ensure that the origin that tries - /// to cancel has greater or equal privileges as the origin that created the scheduled task. - /// - /// For simplicity the [`EqualPrivilegeOnly`](frame_support::traits::EqualPrivilegeOnly) can - /// be used. This will only check if two given origins are equal. - type OriginPrivilegeCmp: PrivilegeCmp; - - /// The maximum number of scheduled calls in the queue for a single block. - /// Not strictly enforced, but used for weight estimation. - #[pallet::constant] - type MaxScheduledPerBlock: Get; - - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; - - /// The preimage provider with which we look up call hashes to get the call. - type PreimageProvider: PreimageProviderAndMaybeRecipient; - - /// If `Some` then the number of blocks to postpone execution for when the item is delayed. - type NoPreimagePostponement: Get>; - - /// Sponsoring function. - // type SponsorshipHandler: SponsorshipHandler::Call>; - - /// The helper type used for custom transaction fee logic. - type CallExecutor: DispatchCall; - } - - /// A Scheduler-Runtime interface for finer payment handling. - pub trait DispatchCall { - /// Reserve (lock) the maximum spendings on a call, calculated from its weight and the repetition count. - fn reserve_balance( - id: ScheduledId, - sponsor: ::AccountId, - call: ::RuntimeCall, - count: u32, - ) -> Result<(), DispatchError>; - - /// Unreserve (unlock) a certain amount from the payer's reserved funds, returning the change. - fn pay_for_call( - id: ScheduledId, - sponsor: ::AccountId, - call: ::RuntimeCall, - ) -> Result; - - /// Resolve the call dispatch, including any post-dispatch operations. - fn dispatch_call( - signer: T::AccountId, - function: ::RuntimeCall, - ) -> Result< - Result>, - TransactionValidityError, - >; - - /// Release unspent reserved funds in case of a schedule cancel. - fn cancel_reserve( - id: ScheduledId, - sponsor: ::AccountId, - ) -> Result; - } - - /// Items to be executed, indexed by the block number that they should be executed on. - #[pallet::storage] - pub type Agenda = - StorageMap<_, Twox64Concat, T::BlockNumber, Vec>>, ValueQuery>; - - /// Lookup from identity to the block number and index of the task. - #[pallet::storage] - pub(crate) type Lookup = - StorageMap<_, Twox64Concat, ScheduledId, TaskAddress>; - - /// Events type. - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// Scheduled some task. - Scheduled { when: T::BlockNumber, index: u32 }, - /// Canceled some task. - Canceled { when: T::BlockNumber, index: u32 }, - /// Dispatched some task. - Dispatched { - task: TaskAddress, - id: Option, - result: DispatchResult, - }, - /// The call for the provided hash was not found so the task has been aborted. - CallLookupFailed { - task: TaskAddress, - id: Option, - error: LookupError, - }, - } - - #[pallet::error] - pub enum Error { - /// Failed to schedule a call - FailedToSchedule, - /// Cannot find the scheduled call. - NotFound, - /// Given target block number is in the past. - TargetBlockNumberInPast, - /// Reschedule failed because it does not change scheduled time. - RescheduleNoChange, - } - - #[pallet::hooks] - impl Hooks> for Pallet { - /// Execute the scheduled calls - fn on_initialize(now: T::BlockNumber) -> Weight { - let limit = T::MaximumWeight::get(); - - let mut queued = Agenda::::take(now) - .into_iter() - .enumerate() - .filter_map(|(index, s)| Some((index as u32, s?))) - .collect::>(); - - if queued.len() as u32 > T::MaxScheduledPerBlock::get() { - log::warn!( - target: "runtime::scheduler", - "Warning: This block has more items queued in Scheduler than \ - expected from the runtime configuration. An update might be needed." - ); - } - - queued.sort_by_key(|(_, s)| s.priority); - - let next = now + One::one(); - - let mut total_weight: Weight = T::WeightInfo::on_initialize(0); - for (order, (index, mut s)) in queued.into_iter().enumerate() { - let named = if let Some(ref id) = s.maybe_id { - Lookup::::remove(id); - true - } else { - false - }; - - let (call, maybe_completed) = s.call.resolved::(); - s.call = call; - - let resolved = if let Some(completed) = maybe_completed { - T::PreimageProvider::unrequest_preimage(&completed); - true - } else { - false - }; - let call = match s.call.as_value().cloned() { - Some(c) => c, - None => { - // Preimage not available - postpone until some block. - total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); - if let Some(delay) = T::NoPreimagePostponement::get() { - let until = now.saturating_add(delay); - if let Some(ref id) = s.maybe_id { - let index = Agenda::::decode_len(until).unwrap_or(0); - Lookup::::insert(id, (until, index as u32)); - } - Agenda::::append(until, Some(s)); - } - continue; - } - }; - - let periodic = s.maybe_periodic.is_some(); - let call_weight = call.get_dispatch_info().weight; - let mut item_weight = T::WeightInfo::item(periodic, named, Some(resolved)); - let origin = <::RuntimeOrigin as From>::from( - s.origin.clone(), - ) - .into(); - if ensure_signed(origin).is_ok() { - // Weights of Signed dispatches expect their signing account to be whitelisted. - item_weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - } - - // We allow a scheduled call if any is true: - // - It's priority is `HARD_DEADLINE` - // - It does not push the weight past the limit. - // - It is the first item in the schedule - let hard_deadline = s.priority <= schedule::HARD_DEADLINE; - let test_weight = total_weight - .saturating_add(call_weight) - .saturating_add(item_weight); - if !hard_deadline && order > 0 && test_weight.all_gt(limit) { - // Cannot be scheduled this block - postpone until next. - total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); - if let Some(ref id) = s.maybe_id { - // NOTE: We could reasonably not do this (in which case there would be one - // block where the named and delayed item could not be referenced by name), - // but we will do it anyway since it should be mostly free in terms of - // weight and it is slightly cleaner. - let index = Agenda::::decode_len(next).unwrap_or(0); - Lookup::::insert(id, (next, index as u32)); - } - Agenda::::append(next, Some(s)); - continue; - } - - let sender = ensure_signed( - <::RuntimeOrigin as From>::from( - s.origin.clone(), - ) - .into(), - ) - .unwrap(); - - // // if call have id it was be reserved - // if s.maybe_id.is_some() { - // let _ = T::CallExecutor::pay_for_call( - // s.maybe_id.unwrap(), - // sender.clone(), - // call.clone(), - // ); - // } - - // Execute transaction via chain default pipeline - // That means dispatch will be processed like any user's extrinsic e.g. transaction fees will be taken - let r = T::CallExecutor::dispatch_call(sender, call.clone()); - - let mut actual_call_weight: Weight = item_weight; - let result: Result<_, DispatchError> = match r { - Ok(o) => match o { - Ok(di) => { - actual_call_weight = di.actual_weight.unwrap_or(item_weight); - Ok(()) - } - Err(err) => Err(err.error), - }, - Err(_) => { - log::error!( - target: "runtime::scheduler", - "Warning: Scheduler has failed to execute a post-dispatch transaction. \ - This block might have become invalid."); - Err(DispatchError::CannotLookup) - } // todo possibly force a skip/return here, do something with the error - }; - - total_weight.saturating_accrue(item_weight); - total_weight.saturating_accrue(actual_call_weight); - - Self::deposit_event(Event::Dispatched { - task: (now, index), - id: s.maybe_id.clone(), - result, - }); - - if let &Some((period, count)) = &s.maybe_periodic { - if count > 1 { - s.maybe_periodic = Some((period, count - 1)); - } else { - s.maybe_periodic = None; - } - let wake = now + period; - // If scheduled is named, place its information in `Lookup` - if let Some(ref id) = s.maybe_id { - let wake_index = Agenda::::decode_len(wake).unwrap_or(0); - Lookup::::insert(id, (wake, wake_index as u32)); - } - Agenda::::append(wake, Some(s)); - } - } - // Total weight should be 0, because the transaction is already paid for - Weight::zero() - } - } - - #[pallet::call] - impl Pallet { - /// Schedule a named task. - #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] - pub fn schedule_named( - origin: OriginFor, - id: ScheduledId, - when: T::BlockNumber, - maybe_periodic: Option>, - priority: schedule::Priority, - call: Box>, - ) -> DispatchResult { - T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::RuntimeOrigin::from(origin); - Self::do_schedule_named( - id, - DispatchTime::At(when), - maybe_periodic, - priority, - origin.caller().clone(), - *call, - )?; - Ok(()) - } - - /// Cancel a named scheduled task. - #[pallet::weight(::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get()))] - pub fn cancel_named(origin: OriginFor, id: ScheduledId) -> DispatchResult { - T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::RuntimeOrigin::from(origin); - Self::do_cancel_named(Some(origin.caller().clone()), id)?; - Ok(()) - } - - /// Schedule a named task after a delay. - /// - /// # - /// Same as [`schedule_named`](Self::schedule_named). - /// # - #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] - pub fn schedule_named_after( - origin: OriginFor, - id: ScheduledId, - after: T::BlockNumber, - maybe_periodic: Option>, - priority: schedule::Priority, - call: Box>, - ) -> DispatchResult { - T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::RuntimeOrigin::from(origin); - Self::do_schedule_named( - id, - DispatchTime::After(after), - maybe_periodic, - priority, - origin.caller().clone(), - *call, - )?; - Ok(()) - } - } -} - -impl Pallet { - #[cfg(feature = "try-runtime")] - pub fn pre_migrate_to_v3() -> Result<(), &'static str> { - Ok(()) - } - - #[cfg(feature = "try-runtime")] - pub fn post_migrate_to_v3() -> Result<(), &'static str> { - use frame_support::dispatch::GetStorageVersion; - - assert!(Self::current_storage_version() == 3); - for k in Agenda::::iter_keys() { - let _ = Agenda::::try_get(k).map_err(|()| "Invalid item in Agenda")?; - } - Ok(()) - } - - /// Helper to migrate scheduler when the pallet origin type has changed. - pub fn migrate_origin + codec::Decode>() { - Agenda::::translate::< - Vec, T::BlockNumber, OldOrigin, T::AccountId>>>, - _, - >(|_, agenda| { - Some( - agenda - .into_iter() - .map(|schedule| { - schedule.map(|schedule| Scheduled { - maybe_id: schedule.maybe_id, - priority: schedule.priority, - call: schedule.call, - maybe_periodic: schedule.maybe_periodic, - origin: schedule.origin.into(), - _phantom: Default::default(), - }) - }) - .collect::>(), - ) - }); - } - - fn resolve_time(when: DispatchTime) -> Result { - let now = frame_system::Pallet::::block_number(); - - let when = match when { - DispatchTime::At(x) => x, - // The current block has already completed it's scheduled tasks, so - // Schedule the task at lest one block after this current block. - DispatchTime::After(x) => now.saturating_add(x).saturating_add(One::one()), - }; - - if when <= now { - return Err(Error::::TargetBlockNumberInPast.into()); - } - - Ok(when) - } - - fn do_schedule_named( - id: ScheduledId, - when: DispatchTime, - maybe_periodic: Option>, - priority: schedule::Priority, - origin: T::PalletsOrigin, - call: CallOrHashOf, - ) -> Result, DispatchError> { - // ensure id it is unique - if Lookup::::contains_key(&id) { - return Err(Error::::FailedToSchedule)?; - } - - let when = Self::resolve_time(when)?; - - call.ensure_requested::(); - - // sanitize maybe_periodic - let maybe_periodic = maybe_periodic - .filter(|p| p.1 > 1 && !p.0.is_zero()) - // Remove one from the number of repetitions since we will schedule one now. - .map(|(p, c)| (p, c - 1)); - - let s = Scheduled { - maybe_id: Some(id.clone()), - priority, - call: call.clone(), - maybe_periodic, - origin: origin.clone(), - _phantom: Default::default(), - }; - - // reserve balance for periodic execution - // let sender = - // ensure_signed(<::Origin as From>::from(origin).into())?; - // let repeats = match maybe_periodic { - // Some(p) => p.1, - // None => 1, - // }; - // let _ = T::CallExecutor::reserve_balance( - // id.clone(), - // sender, - // call.as_value().unwrap().clone(), - // repeats, - // ); - - Agenda::::append(when, Some(s)); - let index = Agenda::::decode_len(when).unwrap_or(1) as u32 - 1; - let address = (when, index); - Lookup::::insert(&id, &address); - Self::deposit_event(Event::Scheduled { when, index }); - - Ok(address) - } - - fn do_cancel_named(origin: Option, id: ScheduledId) -> DispatchResult { - Lookup::::try_mutate_exists(id, |lookup| -> DispatchResult { - if let Some((when, index)) = lookup.take() { - let i = index as usize; - Agenda::::try_mutate(when, |agenda| -> DispatchResult { - if let Some(s) = agenda.get_mut(i) { - if let (Some(ref o), Some(ref s)) = (origin.clone(), s.borrow()) { - if matches!( - T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin), - Some(Ordering::Less) | None - ) { - return Err(BadOrigin.into()); - } - // release balance reserve - // let sender = ensure_signed( - // <::Origin as From>::from( - // origin.unwrap(), - // ) - // .into(), - // )?; - // let _ = T::CallExecutor::cancel_reserve(id, sender); - - s.call.ensure_unrequested::(); - } - *s = None; - } - Ok(()) - })?; - - Self::deposit_event(Event::Canceled { when, index }); - Ok(()) - } else { - Err(Error::::NotFound)? - } - }) - } -} diff --git a/pallets/scheduler/src/weights.rs b/pallets/scheduler/src/weights.rs deleted file mode 100644 index 646ccf74f8..0000000000 --- a/pallets/scheduler/src/weights.rs +++ /dev/null @@ -1,320 +0,0 @@ -// Template adopted from https://github.com/paritytech/substrate/blob/master/.maintain/frame-weight-template.hbs - -//! Autogenerated weights for pallet_unique_scheduler -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-08-15, STEPS: `50`, REPEAT: 80, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 - -// Executed Command: -// target/release/unique-collator -// benchmark -// pallet -// --pallet -// pallet-unique-scheduler -// --wasm-execution -// compiled -// --extrinsic -// * -// --template -// .maintain/frame-weight-template.hbs -// --steps=50 -// --repeat=80 -// --heap-pages=4096 -// --output=./pallets/scheduler/src/weights.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(clippy::unnecessary_cast)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use sp_std::marker::PhantomData; - -/// Weight functions needed for pallet_unique_scheduler. -pub trait WeightInfo { - fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight; - fn on_initialize_named_resolved(s: u32, ) -> Weight; - fn on_initialize_periodic(s: u32, ) -> Weight; - fn on_initialize_periodic_resolved(s: u32, ) -> Weight; - fn on_initialize_aborted(s: u32, ) -> Weight; - fn on_initialize_named_aborted(s: u32, ) -> Weight; - fn on_initialize_named(s: u32, ) -> Weight; - fn on_initialize(s: u32, ) -> Weight; - fn on_initialize_resolved(s: u32, ) -> Weight; - fn schedule_named(s: u32, ) -> Weight; - fn cancel_named(s: u32, ) -> Weight; -} - -/// Weights for pallet_unique_scheduler using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(26_641_000) - // Standard Error: 9_000 - .saturating_add(Weight::from_ref_time(8_547_000).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(T::DbWeight::get().writes(4 as u64)) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(23_941_000) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(5_282_000).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic(s: u32, ) -> Weight { - Weight::from_ref_time(24_858_000) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(8_657_000).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(T::DbWeight::get().writes(4 as u64)) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(25_515_000) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(8_656_000).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(T::DbWeight::get().writes(4 as u64)) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(7_584_000) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_065_000).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(25_552_000) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(5_187_000).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named(s: u32, ) -> Weight { - Weight::from_ref_time(8_980_000) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(2_050_000).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize(s: u32, ) -> Weight { - Weight::from_ref_time(24_482_000) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(5_249_000).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(25_187_000) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(5_216_000).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) - fn schedule_named(s: u32, ) -> Weight { - Weight::from_ref_time(17_316_000) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(82_000).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) - fn cancel_named(s: u32, ) -> Weight { - Weight::from_ref_time(15_652_000) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(436_000).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } -} - -// For backwards compatibility and tests -impl WeightInfo for () { - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(26_641_000) - // Standard Error: 9_000 - .saturating_add(Weight::from_ref_time(8_547_000).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(23_941_000) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(5_282_000).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic(s: u32, ) -> Weight { - Weight::from_ref_time(24_858_000) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(8_657_000).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(25_515_000) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(8_656_000).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(7_584_000) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_065_000).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(25_552_000) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(5_187_000).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named(s: u32, ) -> Weight { - Weight::from_ref_time(8_980_000) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(2_050_000).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize(s: u32, ) -> Weight { - Weight::from_ref_time(24_482_000) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(5_249_000).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: System AllExtrinsicsLen (r:1 w:1) - // Storage: System BlockWeight (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(25_187_000) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(5_216_000).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) - fn schedule_named(s: u32, ) -> Weight { - Weight::from_ref_time(17_316_000) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(82_000).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) - fn cancel_named(s: u32, ) -> Weight { - Weight::from_ref_time(15_652_000) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(436_000).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } -} diff --git a/pallets/structure/Cargo.toml b/pallets/structure/Cargo.toml index 167c9e1962..23f62642aa 100644 --- a/pallets/structure/Cargo.toml +++ b/pallets/structure/Cargo.toml @@ -4,10 +4,10 @@ version = "0.1.2" edition = "2021" [dependencies] -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } pallet-common = { path = "../common", default-features = false } parity-scale-codec = { version = "3.1.2", default-features = false, features = [ "derive", @@ -16,7 +16,7 @@ scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } up-data-structs = { path = "../../primitives/data-structs", default-features = false } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } [features] default = ["std"] diff --git a/pallets/unique/CHANGELOG.md b/pallets/unique/CHANGELOG.md index 1a70f7d02d..76c934c1c8 100644 --- a/pallets/unique/CHANGELOG.md +++ b/pallets/unique/CHANGELOG.md @@ -4,33 +4,40 @@ All notable changes to this project will be documented in this file. +## [v0.2.1] 2022-10-10 + +### Changes + +- Added `destroyCollection` and `createFTCollection` methods to **CollectionHelpers**. + ## [v0.2.0] 2022-09-13 ### Changes -- Change **collectionHelper** method `createRefungibleCollection` to `createRFTCollection`, + +- Change **collectionHelper** method `createRefungibleCollection` to `createRFTCollection`, ## [v0.1.4] 2022-09-05 ### Added -- Methods `force_set_sponsor` , `force_remove_collection_sponsor` to be able to administer sponsorships with other pallets. Added to implement `AppPromotion` pallet logic. +- Methods `force_set_sponsor` , `force_remove_collection_sponsor` to be able to administer sponsorships with other pallets. Added to implement `AppPromotion` pallet logic. ## [v0.1.3] 2022-08-16 ### Other changes -- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a +- build: Upgrade polkadot to v0.9.27 2c498572636f2b34d53b1c51b7283a761a7dc90a -- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8 +- build: Upgrade polkadot to v0.9.26 85515e54c4ca1b82a2630034e55dcc804c643bf8 -- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd31 +- refactor: Remove `#[transactional]` from extrinsics 7fd36cea2f6e00c02c67ccc1de9649ae404efd31 Every extrinsic now runs in transaction implicitly, and `#[transactional]` on pallet dispatchable is now meaningless Upstream-Change: https://github.com/paritytech/substrate/issues/10806 -- refactor: Switch to new prefix removal methods 26734e9567589d75cdd99e404eabf11d5a97d975 +- refactor: Switch to new prefix removal methods 26734e9567589d75cdd99e404eabf11d5a97d975 New methods allows to call `remove_prefix` with limit multiple times in the same block @@ -39,12 +46,12 @@ straightforward Upstream-Change: https://github.com/paritytech/substrate/pull/11490 -- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b +- build: Upgrade polkadot to v0.9.25 cdfb9bdc7b205ff1b5134f034ef9973d769e5e6b ## [v0.1.1] - 2022-07-25 ### Added -- Method for creating `ERC721Metadata` compatible NFT collection. -- Method for creating `ERC721Metadata` compatible ReFungible collection. -- Method for creating ReFungible collection. +- Method for creating `ERC721Metadata` compatible NFT collection. +- Method for creating `ERC721Metadata` compatible ReFungible collection. +- Method for creating ReFungible collection. diff --git a/pallets/unique/Cargo.toml b/pallets/unique/Cargo.toml index 2a4580876f..04cfe1ee5e 100644 --- a/pallets/unique/Cargo.toml +++ b/pallets/unique/Cargo.toml @@ -9,7 +9,7 @@ homepage = 'https://unique.network' license = 'GPLv3' name = 'pallet-unique' repository = 'https://github.com/UniqueNetwork/unique-chain' -version = "0.2.0" +version = "0.2.1" [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] @@ -34,6 +34,7 @@ std = [ ] try-runtime = ["frame-support/try-runtime"] limit-testing = ["up-data-structs/limit-testing"] +stubgen = ["evm-coder/stubgen", "pallet-common/stubgen"] ################################################################################ # Standart Dependencies @@ -60,37 +61,37 @@ version = '3.1.2' default-features = false optional = true git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-support] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-system] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-std] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-runtime] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-core] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-io] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" ################################################################################ # Local Dependencies @@ -99,7 +100,7 @@ up-data-structs = { default-features = false, path = "../../primitives/data-stru scale-info = { version = "2.0.1", default-features = false, features = [ "derive", ] } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } pallet-common = { default-features = false, path = "../common" } evm-coder = { default-features = false, path = '../../crates/evm-coder' } pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' } diff --git a/pallets/unique/src/eth/mod.rs b/pallets/unique/src/eth/mod.rs index b5248d0a37..9b3a4aeb7b 100644 --- a/pallets/unique/src/eth/mod.rs +++ b/pallets/unique/src/eth/mod.rs @@ -18,29 +18,31 @@ use core::marker::PhantomData; use ethereum as _; -use evm_coder::{execution::*, generate_stubgen, solidity_interface, solidity, weight, types::*}; +use evm_coder::{ + abi::AbiType, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight, +}; use frame_support::traits::Get; +use crate::Pallet; + use pallet_common::{ CollectionById, dispatch::CollectionDispatch, - erc::{ - CollectionHelpersEvents, - static_property::{key}, - }, + erc::{CollectionHelpersEvents, static_property::key}, + eth::{map_eth_to_id, collection_id_to_address}, Pallet as PalletCommon, }; -use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder}; use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult}; +use pallet_evm_coder_substrate::{dispatch_to_evm, SubstrateRecorder, WithRecorder}; use sp_std::vec; use up_data_structs::{ - CollectionName, CollectionDescription, CollectionTokenPrefix, CreateCollectionData, - CollectionMode, PropertyValue, CollectionFlags, + CollectionDescription, CollectionMode, CollectionName, CollectionTokenPrefix, + CreateCollectionData, }; -use crate::{Config, SelfWeightOf, weights::WeightInfo}; +use crate::{weights::WeightInfo, Config, SelfWeightOf}; -use sp_std::vec::Vec; use alloc::format; +use sp_std::vec::Vec; /// See [`CollectionHelpersCall`] pub struct EvmCollectionHelpers(SubstrateRecorder); @@ -84,12 +86,12 @@ fn convert_data( Ok((caller, name, description, token_prefix)) } -fn create_refungible_collection_internal< - T: Config + pallet_nonfungible::Config + pallet_refungible::Config, ->( +#[inline(always)] +fn create_collection_internal( caller: caller, value: value, name: string, + collection_mode: CollectionMode, description: string, token_prefix: string, ) -> Result
{ @@ -97,7 +99,7 @@ fn create_refungible_collection_internal< convert_data::(caller, name, description, token_prefix)?; let data = CreateCollectionData { name, - mode: CollectionMode::ReFungible, + mode: collection_mode, description, token_prefix, ..Default::default() @@ -193,7 +195,14 @@ where description: string, token_prefix: string, ) -> Result
{ - self.create_nft_collection(caller, value, name, description, token_prefix) + create_collection_internal::( + caller, + value, + name, + CollectionMode::NFT, + description, + token_prefix, + ) } #[weight(>::create_collection())] @@ -206,7 +215,35 @@ where description: string, token_prefix: string, ) -> Result
{ - create_refungible_collection_internal::(caller, value, name, description, token_prefix) + create_collection_internal::( + caller, + value, + name, + CollectionMode::ReFungible, + description, + token_prefix, + ) + } + + #[weight(>::create_collection())] + #[solidity(rename_selector = "createFTCollection")] + fn create_fungible_collection( + &mut self, + caller: caller, + value: value, + name: string, + decimals: uint8, + description: string, + token_prefix: string, + ) -> Result
{ + create_collection_internal::( + caller, + value, + name, + CollectionMode::Fungible(decimals), + description, + token_prefix, + ) } #[solidity(rename_selector = "makeCollectionERC721MetadataCompatible")] @@ -296,6 +333,16 @@ where Ok(()) } + #[weight(>::destroy_collection())] + fn destroy_collection(&mut self, caller: caller, collection_address: address) -> Result { + let caller = T::CrossAccountId::from_eth(caller); + + let collection_id = pallet_common::eth::map_eth_to_id(&collection_address) + .ok_or("Invalid collection address format")?; + >::destroy_collection_internal(caller, collection_id) + .map_err(pallet_evm_coder_substrate::dispatch_to_evm::) + } + /// Check if a collection exists /// @param collectionAddress Address of the collection in question /// @return bool Does the collection exist? @@ -315,6 +362,25 @@ where .expect("Collection creation price should be convertible to u128"); Ok(price.into()) } + + /// Returns address of a collection. + /// @param collectionId - CollectionId of the collection + /// @return eth mirror address of the collection + fn collection_address(&self, collection_id: uint32) -> Result
{ + Ok(collection_id_to_address(collection_id.into())) + } + + /// Returns collectionId of a collection. + /// @param collectionAddress - Eth address of the collection + /// @return collectionId of the collection + fn collection_id(&self, collection_address: address) -> Result { + map_eth_to_id(&collection_address) + .map(|id| id.0) + .ok_or(Error::Revert(format!( + "failed to convert address {} into collectionId.", + collection_address + ))) + } } /// Implements [`OnMethodCall`], which delegates call to [`EvmCollectionHelpers`] diff --git a/pallets/unique/src/eth/stubs/CollectionHelpers.raw b/pallets/unique/src/eth/stubs/CollectionHelpers.raw index 7d9a32abc1..6f7b0ba82e 100644 Binary files a/pallets/unique/src/eth/stubs/CollectionHelpers.raw and b/pallets/unique/src/eth/stubs/CollectionHelpers.raw differ diff --git a/pallets/unique/src/eth/stubs/CollectionHelpers.sol b/pallets/unique/src/eth/stubs/CollectionHelpers.sol index 12a23169da..c130365b5b 100644 --- a/pallets/unique/src/eth/stubs/CollectionHelpers.sol +++ b/pallets/unique/src/eth/stubs/CollectionHelpers.sol @@ -20,10 +20,13 @@ contract ERC165 is Dummy { /// @dev inlined interface contract CollectionHelpersEvents { event CollectionCreated(address indexed owner, address indexed collectionId); + event CollectionDestroyed(address indexed collectionId); + event CollectionChanged(address indexed collectionId); + event TokenChanged(address indexed collectionId, uint256 tokenId); } /// @title Contract, which allows users to operate with collections -/// @dev the ERC-165 identifier for this interface is 0x58918631 +/// @dev the ERC-165 identifier for this interface is 0xe65011aa contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents { /// Create an NFT collection /// @param name Name of the collection @@ -76,6 +79,23 @@ contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents { return 0x0000000000000000000000000000000000000000; } + /// @dev EVM selector for this function is: 0x7335b79f, + /// or in textual repr: createFTCollection(string,uint8,string,string) + function createFTCollection( + string memory name, + uint8 decimals, + string memory description, + string memory tokenPrefix + ) public payable returns (address) { + require(false, stub_error); + name; + decimals; + description; + tokenPrefix; + dummy = 0; + return 0x0000000000000000000000000000000000000000; + } + /// @dev EVM selector for this function is: 0x85624258, /// or in textual repr: makeCollectionERC721MetadataCompatible(address,string) function makeCollectionERC721MetadataCompatible(address collection, string memory baseUri) public { @@ -85,6 +105,14 @@ contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents { dummy = 0; } + /// @dev EVM selector for this function is: 0x564e321f, + /// or in textual repr: destroyCollection(address) + function destroyCollection(address collectionAddress) public { + require(false, stub_error); + collectionAddress; + dummy = 0; + } + /// Check if a collection exists /// @param collectionAddress Address of the collection in question /// @return bool Does the collection exist? @@ -104,4 +132,28 @@ contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents { dummy; return 0; } + + /// Returns address of a collection. + /// @param collectionId - CollectionId of the collection + /// @return eth mirror address of the collection + /// @dev EVM selector for this function is: 0x2e716683, + /// or in textual repr: collectionAddress(uint32) + function collectionAddress(uint32 collectionId) public view returns (address) { + require(false, stub_error); + collectionId; + dummy; + return 0x0000000000000000000000000000000000000000; + } + + /// Returns collectionId of a collection. + /// @param collectionAddress - Eth address of the collection + /// @return collectionId of the collection + /// @dev EVM selector for this function is: 0xb5cb7498, + /// or in textual repr: collectionId(address) + function collectionId(address collectionAddress) public view returns (uint32) { + require(false, stub_error); + collectionAddress; + dummy; + return 0; + } } diff --git a/pallets/unique/src/lib.rs b/pallets/unique/src/lib.rs index 10642438ae..004cee8cc4 100644 --- a/pallets/unique/src/lib.rs +++ b/pallets/unique/src/lib.rs @@ -74,7 +74,7 @@ extern crate alloc; use frame_support::{ - decl_module, decl_storage, decl_error, decl_event, + decl_module, decl_storage, decl_error, dispatch::DispatchResult, ensure, fail, weights::{Weight}, @@ -82,13 +82,14 @@ use frame_support::{ BoundedVec, }; use scale_info::TypeInfo; -use frame_system::{self as system, ensure_signed}; +use frame_system::{self as system, ensure_signed, ensure_root}; use sp_std::{vec, vec::Vec}; use up_data_structs::{ MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH, + MAX_PROPERTIES_PER_ITEM, MAX_PROPERTY_KEY_LENGTH, MAX_PROPERTY_VALUE_LENGTH, + MAX_COLLECTION_PROPERTIES_SIZE, COLLECTION_ADMINS_LIMIT, MAX_TOKEN_PROPERTIES_SIZE, CreateItemData, CollectionLimits, CollectionPermissions, CollectionId, CollectionMode, TokenId, - SponsorshipState, CreateCollectionData, CreateItemExData, budget, Property, PropertyKey, - PropertyKeyPermission, + CreateCollectionData, CreateItemExData, budget, Property, PropertyKey, PropertyKeyPermission, }; use pallet_evm::account::CrossAccountId; use pallet_common::{ @@ -102,7 +103,7 @@ pub mod benchmarking; pub mod weights; use weights::WeightInfo; -/// Maximum number of levels of depth in the token nesting tree. +/// A maximum number of levels of depth in the token nesting tree. pub const NESTING_BUDGET: u32 = 5; decl_error! { @@ -110,8 +111,6 @@ decl_error! { pub enum Error for Module { /// Decimal_points parameter must be lower than [`up_data_structs::MAX_DECIMAL_POINTS`]. CollectionDecimalPointLimitExceeded, - /// This address is not set as sponsor, use setCollectionSponsor first. - ConfirmUnsetSponsorFail, /// Length of items properties must be greater than 0. EmptyArgument, /// Repertition is only supported by refungible collection. @@ -121,9 +120,6 @@ decl_error! { /// Configuration trait of this pallet. pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo { - /// Overarching event type. - type RuntimeEvent: From> + Into<::RuntimeEvent>; - /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -134,81 +130,6 @@ pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo { type RefungibleExtensionsWeightInfo: RefungibleExtensionsWeightInfo; } -decl_event! { - pub enum Event - where - ::AccountId, - ::CrossAccountId, - { - /// Collection sponsor was removed - /// - /// # Arguments - /// * collection_id: ID of the affected collection. - CollectionSponsorRemoved(CollectionId), - - /// Collection admin was added - /// - /// # Arguments - /// * collection_id: ID of the affected collection. - /// * admin: Admin address. - CollectionAdminAdded(CollectionId, CrossAccountId), - - /// Collection owned was changed - /// - /// # Arguments - /// * collection_id: ID of the affected collection. - /// * owner: New owner address. - CollectionOwnedChanged(CollectionId, AccountId), - - /// Collection sponsor was set - /// - /// # Arguments - /// * collection_id: ID of the affected collection. - /// * owner: New sponsor address. - CollectionSponsorSet(CollectionId, AccountId), - - /// New sponsor was confirm - /// - /// # Arguments - /// * collection_id: ID of the affected collection. - /// * sponsor: New sponsor address. - SponsorshipConfirmed(CollectionId, AccountId), - - /// Collection admin was removed - /// - /// # Arguments - /// * collection_id: ID of the affected collection. - /// * admin: Removed admin address. - CollectionAdminRemoved(CollectionId, CrossAccountId), - - /// Address was removed from the allow list - /// - /// # Arguments - /// * collection_id: ID of the affected collection. - /// * user: Address of the removed account. - AllowListAddressRemoved(CollectionId, CrossAccountId), - - /// Address was added to the allow list - /// - /// # Arguments - /// * collection_id: ID of the affected collection. - /// * user: Address of the added account. - AllowListAddressAdded(CollectionId, CrossAccountId), - - /// Collection limits were set - /// - /// # Arguments - /// * collection_id: ID of the affected collection. - CollectionLimitSet(CollectionId), - - /// Collection permissions were set - /// - /// # Arguments - /// * collection_id: ID of the affected collection. - CollectionPermissionSet(CollectionId), - } -} - type SelfWeightOf = ::WeightInfo; // # Used definitions @@ -277,7 +198,44 @@ decl_module! { { type Error = Error; - pub fn deposit_event() = default; + #[doc = "A maximum number of levels of depth in the token nesting tree."] + const NESTING_BUDGET: u32 = NESTING_BUDGET; + + #[doc = "Maximal length of a collection name."] + const MAX_COLLECTION_NAME_LENGTH: u32 = MAX_COLLECTION_NAME_LENGTH; + + #[doc = "Maximal length of a collection description."] + const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = MAX_COLLECTION_DESCRIPTION_LENGTH; + + #[doc = "Maximal length of a token prefix."] + const MAX_TOKEN_PREFIX_LENGTH: u32 = MAX_TOKEN_PREFIX_LENGTH; + + #[doc = "Maximum admins per collection."] + const COLLECTION_ADMINS_LIMIT: u32 = COLLECTION_ADMINS_LIMIT; + + #[doc = "Maximal length of a property key."] + const MAX_PROPERTY_KEY_LENGTH: u32 = MAX_PROPERTY_KEY_LENGTH; + + #[doc = "Maximal length of a property value."] + const MAX_PROPERTY_VALUE_LENGTH: u32 = MAX_PROPERTY_VALUE_LENGTH; + + #[doc = "A maximum number of token properties."] + const MAX_PROPERTIES_PER_ITEM: u32 = MAX_PROPERTIES_PER_ITEM; + + #[doc = "Maximum size for all collection properties."] + const MAX_COLLECTION_PROPERTIES_SIZE: u32 = MAX_COLLECTION_PROPERTIES_SIZE; + + #[doc = "Maximum size of all token properties."] + const MAX_TOKEN_PROPERTIES_SIZE: u32 = MAX_TOKEN_PROPERTIES_SIZE; + + #[doc = "Default NFT collection limit."] + const NFT_DEFAULT_COLLECTION_LIMITS: CollectionLimits = CollectionLimits::with_default_limits(CollectionMode::NFT); + + #[doc = "Default RFT collection limit."] + const RFT_DEFAULT_COLLECTION_LIMITS: CollectionLimits = CollectionLimits::with_default_limits(CollectionMode::ReFungible); + + #[doc = "Default FT collection limit."] + const FT_DEFAULT_COLLECTION_LIMITS: CollectionLimits = CollectionLimits::with_default_limits(CollectionMode::Fungible(0)); fn on_initialize(_now: T::BlockNumber) -> Weight { Weight::zero() @@ -362,25 +320,8 @@ decl_module! { #[weight = >::destroy_collection()] pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult { let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); - let collection = >::try_get(collection_id)?; - collection.check_is_internal()?; - // ========= - - T::CollectionDispatch::destroy(sender, collection)?; - - // TODO: basket cleanup should be moved elsewhere - // Maybe runtime dispatch.rs should perform it? - - let _ = >::clear_prefix(collection_id, u32::MAX, None); - let _ = >::clear_prefix(collection_id, u32::MAX, None); - let _ = >::clear_prefix((collection_id,), u32::MAX, None); - - let _ = >::clear_prefix(collection_id, u32::MAX, None); - let _ = >::clear_prefix(collection_id, u32::MAX, None); - let _ = >::clear_prefix((collection_id,), u32::MAX, None); - - Ok(()) + Self::destroy_collection_internal(sender, collection_id) } /// Add an address to allow list. @@ -408,11 +349,6 @@ decl_module! { true, )?; - Self::deposit_event(Event::::AllowListAddressAdded( - collection_id, - address - )); - Ok(()) } @@ -441,11 +377,6 @@ decl_module! { false, )?; - >::deposit_event(Event::::AllowListAddressRemoved( - collection_id, - address - )); - Ok(()) } @@ -461,20 +392,10 @@ decl_module! { /// * `new_owner`: ID of the account that will become the owner. #[weight = >::change_collection_owner()] pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult { - let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); - + let new_owner = T::CrossAccountId::from_sub(new_owner); let mut target_collection = >::try_get(collection_id)?; - target_collection.check_is_internal()?; - target_collection.check_is_owner(&sender)?; - - target_collection.owner = new_owner.clone(); - >::deposit_event(Event::::CollectionOwnedChanged( - collection_id, - new_owner - )); - - target_collection.save() + target_collection.change_owner(sender, new_owner.clone()) } /// Add an admin to a collection. @@ -497,13 +418,6 @@ decl_module! { pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult { let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); let collection = >::try_get(collection_id)?; - collection.check_is_internal()?; - - >::deposit_event(Event::::CollectionAdminAdded( - collection_id, - new_admin_id.clone() - )); - >::toggle_admin(&collection, &sender, &new_admin_id, true) } @@ -525,13 +439,6 @@ decl_module! { pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult { let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); let collection = >::try_get(collection_id)?; - collection.check_is_internal()?; - - >::deposit_event(Event::::CollectionAdminRemoved( - collection_id, - account_id.clone() - )); - >::toggle_admin(&collection, &sender, &account_id, false) } @@ -551,19 +458,8 @@ decl_module! { #[weight = >::set_collection_sponsor()] pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult { let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); - let mut target_collection = >::try_get(collection_id)?; - target_collection.check_is_owner_or_admin(&sender)?; - target_collection.check_is_internal()?; - - target_collection.set_sponsor(new_sponsor.clone())?; - - >::deposit_event(Event::::CollectionSponsorSet( - collection_id, - new_sponsor - )); - - target_collection.save() + target_collection.set_sponsor(&sender, new_sponsor.clone()) } /// Confirm own sponsorship of a collection, becoming the sponsor. @@ -582,20 +478,8 @@ decl_module! { #[weight = >::confirm_sponsorship()] pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult { let sender = ensure_signed(origin)?; - let mut target_collection = >::try_get(collection_id)?; - target_collection.check_is_internal()?; - ensure!( - target_collection.confirm_sponsorship(&sender)?, - Error::::ConfirmUnsetSponsorFail - ); - - >::deposit_event(Event::::SponsorshipConfirmed( - collection_id, - sender - )); - - target_collection.save() + target_collection.confirm_sponsorship(&sender) } /// Remove a collection's a sponsor, making everyone pay for their own transactions. @@ -610,17 +494,8 @@ decl_module! { #[weight = >::remove_collection_sponsor()] pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult { let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); - let mut target_collection = >::try_get(collection_id)?; - target_collection.check_is_internal()?; - target_collection.check_is_owner(&sender)?; - - target_collection.sponsorship = SponsorshipState::Disabled; - - >::deposit_event(Event::::CollectionSponsorRemoved( - collection_id - )); - target_collection.save() + target_collection.remove_sponsor(&sender) } /// Mint an item within a collection. @@ -1028,17 +903,7 @@ decl_module! { ) -> DispatchResult { let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); let mut target_collection = >::try_get(collection_id)?; - target_collection.check_is_internal()?; - target_collection.check_is_owner_or_admin(&sender)?; - let old_limit = &target_collection.limits; - - target_collection.limits = >::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?; - - >::deposit_event(Event::::CollectionLimitSet( - collection_id - )); - - target_collection.save() + >::update_limits(&sender, &mut target_collection, new_limit) } /// Set specific permissions of a collection. Empty, or None fields mean chain default. @@ -1061,17 +926,11 @@ decl_module! { ) -> DispatchResult { let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); let mut target_collection = >::try_get(collection_id)?; - target_collection.check_is_internal()?; - target_collection.check_is_owner_or_admin(&sender)?; - let old_limit = &target_collection.permissions; - - target_collection.permissions = >::clamp_permissions(target_collection.mode.clone(), &old_limit, new_permission)?; - - >::deposit_event(Event::::CollectionPermissionSet( - collection_id - )); - - target_collection.save() + >::update_permissions( + &sender, + &mut target_collection, + new_permission + ) } /// Re-partition a refungible token, while owning all of its parts/pieces. @@ -1102,18 +961,55 @@ decl_module! { }) } - /// Repairs a broken item + /// Sets or unsets the approval of a given operator. + /// + /// The `operator` is allowed to transfer all tokens of the `owner` on their behalf. + /// + /// # Arguments + /// + /// * `owner`: Token owner + /// * `operator`: Operator + /// * `approve`: Should operator status be granted or revoked? + #[weight = T::CommonWeightInfo::set_allowance_for_all()] + pub fn set_allowance_for_all( + origin, + collection_id: CollectionId, + operator: T::CrossAccountId, + approve: bool, + ) -> DispatchResultWithPostInfo { + let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); + dispatch_tx::(collection_id, |d| { + d.set_allowance_for_all(sender, operator, approve) + }) + } + + /// Repairs a collection if the data was somehow corrupted. + /// + /// # Arguments + /// + /// * `collection_id`: ID of the collection to repair. + #[weight = >::force_repair_collection()] + pub fn force_repair_collection( + origin, + collection_id: CollectionId, + ) -> DispatchResult { + ensure_root(origin)?; + >::repair_collection(collection_id) + } + + /// Repairs a token if the data was somehow corrupted. /// /// # Arguments /// /// * `collection_id`: ID of the collection the item belongs to. /// * `item_id`: ID of the item. - #[weight = T::CommonWeightInfo::repair_item()] - pub fn repair_item( - _origin, + #[weight = T::CommonWeightInfo::force_repair_item()] + pub fn force_repair_item( + origin, collection_id: CollectionId, item_id: TokenId, ) -> DispatchResultWithPostInfo { + ensure_root(origin)?; dispatch_tx::(collection_id, |d| { d.repair_item(item_id) }) @@ -1133,22 +1029,7 @@ impl Pallet { /// * `collection_id`: ID of the modified collection. pub fn force_set_sponsor(sponsor: T::AccountId, collection_id: CollectionId) -> DispatchResult { let mut target_collection = >::try_get(collection_id)?; - target_collection.check_is_internal()?; - target_collection.set_sponsor(sponsor.clone())?; - - Self::deposit_event(Event::::CollectionSponsorSet( - collection_id, - sponsor.clone(), - )); - - ensure!( - target_collection.confirm_sponsorship(&sponsor)?, - Error::::ConfirmUnsetSponsorFail - ); - - Self::deposit_event(Event::::SponsorshipConfirmed(collection_id, sponsor)); - - target_collection.save() + target_collection.force_set_sponsor(sponsor.clone()) } /// Force remove `sponsor` for `collection`. @@ -1161,11 +1042,30 @@ impl Pallet { /// * `collection_id`: ID of the modified collection. pub fn force_remove_collection_sponsor(collection_id: CollectionId) -> DispatchResult { let mut target_collection = >::try_get(collection_id)?; - target_collection.check_is_internal()?; - target_collection.sponsorship = SponsorshipState::Disabled; + target_collection.force_remove_sponsor() + } + + #[inline(always)] + pub(crate) fn destroy_collection_internal( + sender: T::CrossAccountId, + collection_id: CollectionId, + ) -> DispatchResult { + let collection = >::try_get(collection_id)?; + collection.check_is_internal()?; + + T::CollectionDispatch::destroy(sender, collection)?; + + // TODO: basket cleanup should be moved elsewhere + // Maybe runtime dispatch.rs should perform it? + + let _ = >::clear_prefix(collection_id, u32::MAX, None); + let _ = >::clear_prefix(collection_id, u32::MAX, None); + let _ = >::clear_prefix((collection_id,), u32::MAX, None); - Self::deposit_event(Event::::CollectionSponsorRemoved(collection_id)); + let _ = >::clear_prefix(collection_id, u32::MAX, None); + let _ = >::clear_prefix(collection_id, u32::MAX, None); + let _ = >::clear_prefix((collection_id,), u32::MAX, None); - target_collection.save() + Ok(()) } } diff --git a/pallets/unique/src/weights.rs b/pallets/unique/src/weights.rs index 5a141355e2..92285ae784 100644 --- a/pallets/unique/src/weights.rs +++ b/pallets/unique/src/weights.rs @@ -45,6 +45,7 @@ pub trait WeightInfo { fn remove_collection_sponsor() -> Weight; fn set_transfers_enabled_flag() -> Weight; fn set_collection_limits() -> Weight; + fn force_repair_collection() -> Weight; } /// Weights for pallet_unique using the Substrate node and recommended hardware. @@ -139,6 +140,12 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } + // Storage: Common CollectionProperties (r:1 w:1) + fn force_repair_collection() -> Weight { + Weight::from_ref_time(5_701_000 as u64) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } } // For backwards compatibility and tests @@ -232,4 +239,10 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } + // Storage: Common CollectionProperties (r:1 w:1) + fn force_repair_collection() -> Weight { + Weight::from_ref_time(5_701_000 as u64) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } } diff --git a/primitives/app_promotion_rpc/Cargo.toml b/primitives/app_promotion_rpc/Cargo.toml index 13189ea573..d7ee769a77 100644 --- a/primitives/app_promotion_rpc/Cargo.toml +++ b/primitives/app_promotion_rpc/Cargo.toml @@ -10,11 +10,11 @@ up-data-structs = { default-features = false, path = '../data-structs' } codec = { package = "parity-scale-codec", version = "3.1.2", default-features = false, features = [ "derive", ] } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } [features] default = ["std"] diff --git a/primitives/common/Cargo.toml b/primitives/common/Cargo.toml index 08dcd7ab3a..34b6fe288a 100644 --- a/primitives/common/Cargo.toml +++ b/primitives/common/Cargo.toml @@ -6,7 +6,7 @@ homepage = 'https://unique.network' license = 'All Rights Reserved' name = 'up-common' repository = 'https://github.com/UniqueNetwork/unique-chain' -version = "0.9.30" +version.workspace = true [features] default = ['std'] @@ -17,40 +17,46 @@ std = [ 'sp-core/std', 'sp-consensus-aura/std', 'fp-rpc/std', + 'cumulus-primitives-core/std', 'pallet-evm/std', ] [dependencies.sp-std] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-support] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-runtime] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-core] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-consensus-aura] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.fp-rpc] default-features = false git = "https://github.com/uniquenetwork/frontier" -branch = "unique-polkadot-v0.9.30" +branch = "unique-polkadot-v0.9.36" + +[dependencies.cumulus-primitives-core] +default-features = false +git = "https://github.com/paritytech/cumulus" +branch = "polkadot-v0.9.36" [dependencies.pallet-evm] default-features = false git = "https://github.com/uniquenetwork/frontier" -branch = "unique-polkadot-v0.9.30" +branch = "unique-polkadot-v0.9.36" diff --git a/primitives/common/src/constants.rs b/primitives/common/src/constants.rs index 5ff5c661e9..3890ffab77 100644 --- a/primitives/common/src/constants.rs +++ b/primitives/common/src/constants.rs @@ -17,8 +17,9 @@ use sp_runtime::Perbill; use frame_support::{ parameter_types, - weights::{Weight, constants::WEIGHT_PER_SECOND}, + weights::{Weight, constants::WEIGHT_REF_TIME_PER_SECOND}, }; +use cumulus_primitives_core::relay_chain::v2::MAX_POV_SIZE; use crate::types::{BlockNumber, Balance}; pub const MILLISECS_PER_BLOCK: u64 = 12000; @@ -42,10 +43,10 @@ pub const CENTIUNIQUE: Balance = 10 * MILLIUNIQUE; pub const UNIQUE: Balance = 100 * CENTIUNIQUE; // Targeting 0.1 UNQ per transfer -pub const WEIGHT_TO_FEE_COEFF: u32 = /**/207_163_598/**/; +pub const WEIGHT_TO_FEE_COEFF: u64 = /**/77_083_524_944_487_510/**/; // Targeting 0.15 UNQ per transfer via ETH -pub const MIN_GAS_PRICE: u64 = /**/1_019_483_274_941/**/; +pub const MIN_GAS_PRICE: u64 = /**/1_014_919_313_914/**/; /// We assume that ~10% of the block weight is consumed by `on_initalize` handlers. /// This is used to limit the maximal weight of a single extrinsic. @@ -54,8 +55,10 @@ pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); /// by Operational extrinsics. pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); /// We allow for 2 seconds of compute with a 6 second average block time. -pub const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND.saturating_div(2); +pub const MAXIMUM_BLOCK_WEIGHT: Weight = + Weight::from_ref_time(WEIGHT_REF_TIME_PER_SECOND.saturating_div(2)) + .set_proof_size(MAX_POV_SIZE as u64); parameter_types! { - pub const TransactionByteFee: Balance = 501 * MICROUNIQUE; + pub const TransactionByteFee: Balance = 501 * MICROUNIQUE / 2; } diff --git a/primitives/common/src/types.rs b/primitives/common/src/types.rs index 93bfebed0a..a7a78d1f3e 100644 --- a/primitives/common/src/types.rs +++ b/primitives/common/src/types.rs @@ -29,6 +29,14 @@ pub mod opaque { pub use super::{BlockNumber, Signature, AccountId, Balance, Index, Hash, AuraId}; + #[derive(Debug, Clone)] + pub enum RuntimeId { + Unique, + Quartz, + Opal, + Unknown(sp_std::vec::Vec), + } + /// Opaque block header type. pub type Header = generic::Header; diff --git a/primitives/data-structs/CHANGELOG.md b/primitives/data-structs/CHANGELOG.md index 03bded8ed1..f6c8e098fa 100644 --- a/primitives/data-structs/CHANGELOG.md +++ b/primitives/data-structs/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. + ## [v0.2.2] 2022-08-16 ### Other changes @@ -28,12 +29,19 @@ rejected at runtime level) refungible mint extrinsics, by passing multiple users into `RefungibleMultipleItems` call. ## [v0.2.0] - 2022-08-01 + ### Deprecated + - `CreateReFungibleData::const_data` ## [v0.1.2] - 2022-07-25 + ### Added + - Type aliases `CollectionName`, `CollectionDescription`, `CollectionTokenPrefix` + ## [v0.1.1] - 2022-07-22 + ### Added -- Аields with properties to `CreateReFungibleData` and `CreateRefungibleExData`. \ No newline at end of file + +- Fields with properties to `CreateReFungibleData` and `CreateRefungibleExData`. diff --git a/primitives/data-structs/Cargo.toml b/primitives/data-structs/Cargo.toml index 5c01ad43fe..f3a4ef208b 100644 --- a/primitives/data-structs/Cargo.toml +++ b/primitives/data-structs/Cargo.toml @@ -10,38 +10,40 @@ version = "0.2.2" [dependencies] scale-info = { version = "2.0.1", default-features = false, features = [ - "derive", + "derive", ] } codec = { package = "parity-scale-codec", version = "3.1.2", default-features = false, features = [ - 'derive', + 'derive', ] } serde = { version = "1.0.130", features = [ - 'derive', + 'derive', ], default-features = false, optional = true } -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } derivative = { version = "2.2.0", features = ["use_core"] } struct-versioning = { path = "../../crates/struct-versioning" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } rmrk-traits = { default-features = false, path = "../rmrk-traits" } -bondrewd = { version = "0.1.14", features = ["derive"], default-features = false } +bondrewd = { version = "0.1.14", features = [ + "derive", +], default-features = false } [features] default = ["std"] std = [ - "serde1", - "serde/std", - "codec/std", - "frame-system/std", - "frame-support/std", - "sp-runtime/std", - "sp-core/std", - "sp-std/std", - "pallet-evm/std", - "rmrk-traits/std", + "serde1", + "serde/std", + "codec/std", + "frame-system/std", + "frame-support/std", + "sp-runtime/std", + "sp-core/std", + "sp-std/std", + "pallet-evm/std", + "rmrk-traits/std", ] serde1 = ["serde/alloc"] limit-testing = [] diff --git a/primitives/data-structs/src/lib.rs b/primitives/data-structs/src/lib.rs index 8b45fc698c..b7c452b295 100644 --- a/primitives/data-structs/src/lib.rs +++ b/primitives/data-structs/src/lib.rs @@ -120,22 +120,22 @@ pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768; // TODO: not used. Delete? pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT; -/// Maximum length for collection name. +/// Maximal length of a collection name. pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64; -/// Maximum length for collection description. +/// Maximal length of a collection description. pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256; -/// Maximal token prefix length. +/// Maximal length of a token prefix. pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16; -/// Maximal lenght of property key. +/// Maximal length of a property key. pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256; -/// Maximal lenght of property value. +/// Maximal length of a property value. pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768; -/// Maximum properties that can be assigned to token. +/// A maximum number of token properties. pub const MAX_PROPERTIES_PER_ITEM: u32 = 64; /// Maximal lenght of extended property value. @@ -144,7 +144,7 @@ pub const MAX_AUX_PROPERTY_VALUE_LENGTH: u32 = 2048; /// Maximum size for all collection properties. pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960; -/// Maximum size for all token properties. +/// Maximum size of all token properties. pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768; /// How much items can be created per single @@ -609,6 +609,24 @@ pub struct CollectionLimits { } impl CollectionLimits { + pub fn with_default_limits(collection_type: CollectionMode) -> Self { + CollectionLimits { + account_token_ownership_limit: Some(ACCOUNT_TOKEN_OWNERSHIP_LIMIT), + sponsored_data_size: Some(CUSTOM_DATA_LIMIT), + sponsored_data_rate_limit: Some(SponsoringRateLimit::SponsoringDisabled), + token_limit: Some(COLLECTION_TOKEN_LIMIT), + sponsor_transfer_timeout: match collection_type { + CollectionMode::NFT => Some(NFT_SPONSOR_TRANSFER_TIMEOUT), + CollectionMode::ReFungible => Some(REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT), + CollectionMode::Fungible(_) => Some(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT), + }, + sponsor_approve_timeout: Some(SPONSOR_APPROVE_TIMEOUT), + owner_can_transfer: Some(false), + owner_can_destroy: Some(true), + transfers_enabled: Some(true), + } + } + /// Get effective value for [`account_token_ownership_limit`](self.account_token_ownership_limit). pub fn account_token_ownership_limit(&self) -> u32 { self.account_token_ownership_limit @@ -962,12 +980,15 @@ impl TypeInfo for PhantomType { use scale_info::{ Type, Path, build::{FieldsBuilder, UnnamedFields}, + form::MetaForm, type_params, }; Type::builder() .path(Path::new("up_data_structs", "PhantomType")) .type_params(type_params!(T)) - .composite(>::default().field(|b| b.ty::<[T; 0]>())) + .composite( + >::default().field(|b| b.ty::<[T; 0]>()), + ) } } impl MaxEncodedLen for PhantomType { @@ -989,7 +1010,7 @@ pub type PropertyKey = BoundedBytes>; pub type PropertyValue = BoundedBytes>; /// Property permission. -#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)] +#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone, Default)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pub struct PropertyPermission { /// Permission to change the property and property permission. diff --git a/primitives/pov-estimate-rpc/Cargo.toml b/primitives/pov-estimate-rpc/Cargo.toml new file mode 100644 index 0000000000..f66cd3860c --- /dev/null +++ b/primitives/pov-estimate-rpc/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "up-pov-estimate-rpc" +version = "0.1.0" +license = "GPLv3" +edition = "2021" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.1.2", default-features = false, features = [ + "derive", +] } +serde = { version = "1.0.130", features = ["derive"], default-features = false, optional = true } +scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } + +[features] +default = ["std"] +std = [ + "codec/std", + "serde/std", + "scale-info/std", + "sp-core/std", + "sp-std/std", + "sp-api/std", + "sp-runtime/std", +] diff --git a/primitives/pov-estimate-rpc/src/lib.rs b/primitives/pov-estimate-rpc/src/lib.rs new file mode 100644 index 0000000000..c33145ce9c --- /dev/null +++ b/primitives/pov-estimate-rpc/src/lib.rs @@ -0,0 +1,49 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] + +use scale_info::TypeInfo; +use sp_std::vec::Vec; + +#[cfg(feature = "std")] +use serde::Serialize; + +use sp_runtime::ApplyExtrinsicResult; +use sp_core::Bytes; + +#[cfg_attr(feature = "std", derive(Serialize))] +#[derive(Debug, TypeInfo)] +pub struct PovInfo { + pub proof_size: u64, + pub compact_proof_size: u64, + pub compressed_proof_size: u64, + pub results: Vec, + pub key_values: Vec, +} + +#[cfg_attr(feature = "std", derive(Serialize))] +#[derive(Debug, TypeInfo)] +pub struct TrieKeyValue { + pub key: Vec, + pub value: Vec, +} + +sp_api::decl_runtime_apis! { + pub trait PovEstimateApi { + fn pov_estimate(uxt: Bytes) -> ApplyExtrinsicResult; + } +} diff --git a/primitives/rmrk-rpc/Cargo.toml b/primitives/rmrk-rpc/Cargo.toml index 874fccdc61..97bd63362a 100644 --- a/primitives/rmrk-rpc/Cargo.toml +++ b/primitives/rmrk-rpc/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive", ] } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } serde = { version = "1.0.130", default-features = false, features = ["derive"] } rmrk-traits = { default-features = false, path = "../rmrk-traits" } diff --git a/primitives/rpc/Cargo.toml b/primitives/rpc/Cargo.toml index 43b647aeff..f5080196c2 100644 --- a/primitives/rpc/Cargo.toml +++ b/primitives/rpc/Cargo.toml @@ -10,11 +10,11 @@ up-data-structs = { default-features = false, path = '../data-structs' } codec = { package = "parity-scale-codec", version = "3.1.2", default-features = false, features = [ "derive", ] } -sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } [features] default = ["std"] diff --git a/primitives/rpc/src/lib.rs b/primitives/rpc/src/lib.rs index 21bf5fefcc..359c6e91ff 100644 --- a/primitives/rpc/src/lib.rs +++ b/primitives/rpc/src/lib.rs @@ -132,5 +132,8 @@ sp_api::decl_runtime_apis! { fn total_pieces(collection_id: CollectionId, token_id: TokenId) -> Result>; fn token_owners(collection: CollectionId, token: TokenId) -> Result>; + + /// Get whether an operator is approved by a given owner. + fn allowance_for_all(collection: CollectionId, owner: CrossAccountId, operator: CrossAccountId) -> Result; } } diff --git a/runtime/common/config/ethereum.rs b/runtime/common/config/ethereum.rs index 4130ba98bf..d18dc539f3 100644 --- a/runtime/common/config/ethereum.rs +++ b/runtime/common/config/ethereum.rs @@ -1,14 +1,16 @@ use sp_core::{U256, H160}; use frame_support::{ - weights::{Weight, constants::WEIGHT_PER_SECOND}, + weights::{Weight, constants::WEIGHT_REF_TIME_PER_SECOND}, traits::{FindAuthor}, parameter_types, ConsensusEngineId, }; use sp_runtime::{RuntimeAppPublic, Perbill}; use crate::{ runtime_common::{ - dispatch::CollectionDispatchT, ethereum::sponsoring::EvmSponsorshipHandler, - config::sponsoring::DefaultSponsoringRateLimit, DealWithFees, + config::sponsoring::DefaultSponsoringRateLimit, + DealWithFees, + dispatch::CollectionDispatchT, + ethereum::{precompiles::UniquePrecompiles, sponsoring::EvmSponsorshipHandler}, }, Runtime, Aura, Balances, RuntimeEvent, ChainId, }; @@ -17,19 +19,15 @@ use up_common::constants::*; pub type CrossAccountId = pallet_evm::account::BasicCrossAccountId; -impl pallet_evm::account::Config for Runtime { - type CrossAccountId = CrossAccountId; - type EvmAddressMapping = pallet_evm::HashedAddressMapping; - type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated; -} - // Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case // (contract, which only writes a lot of data), // approximating on top of our real store write weight parameter_types! { - pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND.ref_time() / ::DbWeight::get().write; + pub const WritesPerSecond: u64 = WEIGHT_REF_TIME_PER_SECOND / ::DbWeight::get().write; pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000; - pub const WeightPerGas: u64 = WEIGHT_PER_SECOND.ref_time() / GasPerSecond::get(); + pub const WeightTimePerGas: u64 = WEIGHT_REF_TIME_PER_SECOND / GasPerSecond::get(); + + pub const WeightPerGas: Weight = Weight::from_ref_time(WeightTimePerGas::get()); } /// Limiting EVM execution to 50% of block for substrate users and management tasks @@ -37,17 +35,8 @@ parameter_types! { /// scheduled fairly const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50); parameter_types! { - pub BlockGasLimit: U256 = U256::from((NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get()).ref_time()); -} - -pub enum FixedGasWeightMapping {} -impl pallet_evm::GasWeightMapping for FixedGasWeightMapping { - fn gas_to_weight(gas: u64) -> Weight { - Weight::from_ref_time(gas).saturating_mul(WeightPerGas::get()) - } - fn weight_to_gas(weight: Weight) -> u64 { - (weight / WeightPerGas::get()).ref_time() - } + pub BlockGasLimit: U256 = U256::from((NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightTimePerGas::get()).ref_time()); + pub PrecompilesValue: UniquePrecompiles = UniquePrecompiles::<_>::new(); } pub struct EthereumFindAuthor(core::marker::PhantomData); @@ -65,15 +54,19 @@ impl> FindAuthor for EthereumFindAuthor { } impl pallet_evm::Config for Runtime { + type CrossAccountId = CrossAccountId; + type EvmAddressMapping = pallet_evm::HashedAddressMapping; + type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated; type BlockGasLimit = BlockGasLimit; type FeeCalculator = pallet_configuration::FeeCalculator; - type GasWeightMapping = FixedGasWeightMapping; + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; type CallOrigin = EnsureAddressTruncated; type WithdrawOrigin = EnsureAddressTruncated; type AddressMapping = HashedAddressMapping; - type PrecompilesType = (); - type PrecompilesValue = (); + type PrecompilesType = UniquePrecompiles; + type PrecompilesValue = PrecompilesValue; type Currency = Balances; type RuntimeEvent = RuntimeEvent; type OnMethodCall = ( diff --git a/runtime/common/config/mod.rs b/runtime/common/config/mod.rs index ebebc43c32..7a34bb10c8 100644 --- a/runtime/common/config/mod.rs +++ b/runtime/common/config/mod.rs @@ -21,3 +21,6 @@ pub mod parachain; pub mod sponsoring; pub mod substrate; pub mod xcm; + +#[cfg(feature = "pallet-test-utils")] +pub mod test_pallets; diff --git a/runtime/common/config/orml.rs b/runtime/common/config/orml.rs index 28b96b0b16..1d5d991190 100644 --- a/runtime/common/config/orml.rs +++ b/runtime/common/config/orml.rs @@ -95,6 +95,18 @@ impl Convert for AccountIdToMultiLocation { } } +pub struct CurrencyHooks; +impl orml_traits::currency::MutationHooks for CurrencyHooks { + type OnDust = orml_tokens::TransferDust; + type OnSlash = (); + type PreTransfer = (); + type PostTransfer = (); + type PreDeposit = (); + type PostDeposit = (); + type OnNewTokenAccount = (); + type OnKilledTokenAccount = (); +} + impl orml_vesting::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = pallet_balances::Pallet; @@ -112,18 +124,13 @@ impl orml_tokens::Config for Runtime { type CurrencyId = CurrencyId; type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; - type OnDust = orml_tokens::TransferDust; - type OnSlash = (); - type OnTransfer = (); - type OnDeposit = (); + type CurrencyHooks = CurrencyHooks; type MaxLocks = MaxLocks; type MaxReserves = MaxReserves; // TODO: Add all module accounts type DustRemovalWhitelist = DustRemovalWhitelist; /// The id type for named reserves. type ReserveIdentifier = (); - type OnNewTokenAccount = (); - type OnKilledTokenAccount = (); } impl orml_xtokens::Config for Runtime { diff --git a/runtime/common/config/pallets/app_promotion.rs b/runtime/common/config/pallets/app_promotion.rs index 5c3dab8aec..2b832340eb 100644 --- a/runtime/common/config/pallets/app_promotion.rs +++ b/runtime/common/config/pallets/app_promotion.rs @@ -22,7 +22,7 @@ use crate::{ use frame_support::{parameter_types, PalletId}; use sp_arithmetic::Perbill; use up_common::{ - constants::{UNIQUE, RELAY_DAYS, DAYS}, + constants::{UNIQUE, DAYS, RELAY_DAYS}, types::Balance, }; diff --git a/runtime/common/config/pallets/mod.rs b/runtime/common/config/pallets/mod.rs index 2dbe5918ab..96fa3c4bb1 100644 --- a/runtime/common/config/pallets/mod.rs +++ b/runtime/common/config/pallets/mod.rs @@ -94,7 +94,6 @@ impl pallet_inflation::Config for Runtime { } impl pallet_unique::Config for Runtime { - type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_unique::weights::SubstrateWeight; type CommonWeightInfo = CommonWeights; type RefungibleExtensionsWeightInfo = CommonWeights; @@ -105,7 +104,7 @@ parameter_types! { pub const DayRelayBlocks: BlockNumber = RELAY_DAYS; } impl pallet_configuration::Config for Runtime { - type DefaultWeightToFeeCoefficient = ConstU32<{ up_common::constants::WEIGHT_TO_FEE_COEFF }>; + type DefaultWeightToFeeCoefficient = ConstU64<{ up_common::constants::WEIGHT_TO_FEE_COEFF }>; type DefaultMinGasPrice = ConstU64<{ up_common::constants::MIN_GAS_PRICE }>; type MaxXcmAllowedLocations = ConstU32<16>; type AppPromotionDailyRate = AppPromotionDailyRate; diff --git a/runtime/common/config/pallets/scheduler.rs b/runtime/common/config/pallets/scheduler.rs index fb5dd293a3..f850a3c800 100644 --- a/runtime/common/config/pallets/scheduler.rs +++ b/runtime/common/config/pallets/scheduler.rs @@ -14,14 +14,20 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -use frame_support::{traits::PrivilegeCmp, weights::Weight, parameter_types}; -use frame_system::EnsureSigned; +use frame_support::{ + traits::{PrivilegeCmp, EnsureOrigin}, + weights::Weight, + parameter_types, +}; +use frame_system::{EnsureRoot, RawOrigin}; use sp_runtime::Perbill; -use sp_std::cmp::Ordering; +use core::cmp::Ordering; +use codec::Decode; use crate::{ runtime_common::{scheduler::SchedulerPaymentExecutor, config::substrate::RuntimeBlockWeights}, - Runtime, Call, Event, Origin, OriginCaller, Balances, + Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, OriginCaller, }; +use pallet_unique_scheduler_v2::ScheduledEnsureOriginSuccess; use up_common::types::AccountId; parameter_types! { @@ -33,27 +39,48 @@ parameter_types! { pub const Preimage: Option = Some(10); } -/// Used the compare the privilege of an origin inside the scheduler. -pub struct OriginPrivilegeCmp; +pub struct EnsureSignedOrRoot(sp_std::marker::PhantomData); +impl, O>> + From>, AccountId: Decode> + EnsureOrigin for EnsureSignedOrRoot +{ + type Success = ScheduledEnsureOriginSuccess; + fn try_origin(o: O) -> Result { + o.into().and_then(|o| match o { + RawOrigin::Root => Ok(ScheduledEnsureOriginSuccess::Root), + RawOrigin::Signed(who) => Ok(ScheduledEnsureOriginSuccess::Signed(who)), + r => Err(O::from(r)), + }) + } +} + +pub struct EqualOrRootOnly; +impl PrivilegeCmp for EqualOrRootOnly { + fn cmp_privilege(left: &OriginCaller, right: &OriginCaller) -> Option { + use RawOrigin::*; + + let left = left.clone().try_into().ok()?; + let right = right.clone().try_into().ok()?; -impl PrivilegeCmp for OriginPrivilegeCmp { - fn cmp_privilege(_left: &OriginCaller, _right: &OriginCaller) -> Option { - Some(Ordering::Equal) + match (left, right) { + (Root, Root) => Some(Ordering::Equal), + (Root, _) => Some(Ordering::Greater), + (_, Root) => Some(Ordering::Less), + lr @ _ => (lr.0 == lr.1).then(|| Ordering::Equal), + } } } -impl pallet_unique_scheduler::Config for Runtime { +impl pallet_unique_scheduler_v2::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeOrigin = RuntimeOrigin; - type Currency = Balances; type PalletsOrigin = OriginCaller; type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; - type ScheduleOrigin = EnsureSigned; + type ScheduleOrigin = EnsureSignedOrRoot; + type OriginPrivilegeCmp = EqualOrRootOnly; type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = (); + type Preimages = (); type CallExecutor = SchedulerPaymentExecutor; - type OriginPrivilegeCmp = OriginPrivilegeCmp; - type PreimageProvider = (); - type NoPreimagePostponement = NoPreimagePostponement; + type PrioritySetOrigin = EnsureRoot; } diff --git a/runtime/common/config/substrate.rs b/runtime/common/config/substrate.rs index 0b4362e391..8dec1d61af 100644 --- a/runtime/common/config/substrate.rs +++ b/runtime/common/config/substrate.rs @@ -28,10 +28,12 @@ use sp_runtime::{ traits::{BlakeTwo256, AccountIdLookup}, Perbill, Permill, Percent, }; +use sp_arithmetic::traits::One; use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, }; +use pallet_transaction_payment::{Multiplier, ConstFeeMultiplier}; use crate::{ runtime_common::DealWithFees, Runtime, RuntimeEvent, RuntimeCall, RuntimeOrigin, PalletInfo, System, Balances, Treasury, SS58Prefix, Version, @@ -152,6 +154,8 @@ parameter_types! { /// This value increases the priority of `Operational` transactions by adding /// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`. pub const OperationalFeeMultiplier: u8 = 5; + + pub FeeMultiplier: Multiplier = Multiplier::one(); } impl pallet_transaction_payment::Config for Runtime { @@ -160,7 +164,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = pallet_configuration::WeightToFee; - type FeeMultiplierUpdate = (); + type FeeMultiplierUpdate = ConstFeeMultiplier; } parameter_types! { diff --git a/runtime/common/config/test_pallets.rs b/runtime/common/config/test_pallets.rs new file mode 100644 index 0000000000..60441349ad --- /dev/null +++ b/runtime/common/config/test_pallets.rs @@ -0,0 +1,22 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +use crate::{Runtime, RuntimeEvent, RuntimeCall}; + +impl pallet_test_utils::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; +} diff --git a/runtime/common/config/xcm/foreignassets.rs b/runtime/common/config/xcm/foreignassets.rs index 4e6a299a02..46f293e08b 100644 --- a/runtime/common/config/xcm/foreignassets.rs +++ b/runtime/common/config/xcm/foreignassets.rs @@ -18,7 +18,7 @@ use frame_support::{ traits::{Contains, Get, fungibles}, parameter_types, }; -use sp_runtime::traits::{Zero, Convert}; +use sp_runtime::traits::Convert; use xcm::v1::{Junction::*, MultiLocation, Junctions::*}; use xcm::latest::MultiAsset; use xcm_builder::{FungiblesAdapter, ConvertedConcreteAssetId}; @@ -38,16 +38,16 @@ parameter_types! { pub CheckingAccount: AccountId = PolkadotXcm::check_account(); } -/// Allow checking in assets that have issuance > 0. -pub struct NonZeroIssuance(PhantomData<(AccountId, ForeignAssets)>); +/// No teleports are allowed +pub struct NoTeleports(PhantomData<(AccountId, ForeignAssets)>); impl Contains<>::AssetId> - for NonZeroIssuance + for NoTeleports where ForeignAssets: fungibles::Inspect, { - fn contains(id: &>::AssetId) -> bool { - !ForeignAssets::total_issuance(*id).is_zero() + fn contains(_id: &>::AssetId) -> bool { + false } } @@ -84,7 +84,7 @@ where Some(AssetIds::ForeignAssetId(foreign_asset_id)) => { ConvertAssetId::convert_ref(AssetIds::ForeignAssetId(foreign_asset_id)) } - _ => ConvertAssetId::convert_ref(AssetIds::ForeignAssetId(0)), + _ => Err(()), } } @@ -132,9 +132,8 @@ pub type FungiblesTransactor = FungiblesAdapter< LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): AccountId, - // We only want to allow teleports of known assets. We use non-zero issuance as an indication - // that this asset is known. - NonZeroIssuance, + // No teleports are allowed + NoTeleports, // The account to use for tracking teleports. CheckingAccount, >; diff --git a/runtime/common/config/xcm/mod.rs b/runtime/common/config/xcm/mod.rs index 199fdac373..26ffcb1a3b 100644 --- a/runtime/common/config/xcm/mod.rs +++ b/runtime/common/config/xcm/mod.rs @@ -186,6 +186,9 @@ impl>> TryPass for DenyExchangeWithUnknownLocation TransferReserveAsset { dest: dst, .. } => { allowed |= allowed_locations.contains(dst); } + InitiateReserveWithdraw { reserve: dst, .. } => { + allowed |= allowed_locations.contains(dst); + } _ => {} }); diff --git a/runtime/common/construct_runtime/mod.rs b/runtime/common/construct_runtime/mod.rs index 98746a66e7..803e880d56 100644 --- a/runtime/common/construct_runtime/mod.rs +++ b/runtime/common/construct_runtime/mod.rs @@ -55,10 +55,10 @@ macro_rules! construct_runtime { // Unique Pallets Inflation: pallet_inflation::{Pallet, Call, Storage} = 60, - Unique: pallet_unique::{Pallet, Call, Storage, Event} = 61, + Unique: pallet_unique::{Pallet, Call, Storage} = 61, // #[runtimes(opal)] - // Scheduler: pallet_unique_scheduler::{Pallet, Call, Storage, Event} = 62, + // Scheduler: pallet_unique_scheduler_v2::{Pallet, Call, Storage, Event} = 62, Configuration: pallet_configuration::{Pallet, Call, Storage} = 63, @@ -73,6 +73,12 @@ macro_rules! construct_runtime { Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69, Structure: pallet_structure::{Pallet, Call, Storage, Event} = 70, + #[runtimes(opal)] + RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event} = 71, + + #[runtimes(opal)] + RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event} = 72, + #[runtimes(opal, quartz)] AppPromotion: pallet_app_promotion::{Pallet, Call, Storage, Event} = 73, @@ -89,6 +95,9 @@ macro_rules! construct_runtime { EvmMigration: pallet_evm_migration::{Pallet, Call, Storage, Event} = 153, Maintenance: pallet_maintenance::{Pallet, Call, Storage, Event} = 154, + + #[runtimes(opal)] + TestUtils: pallet_test_utils = 255, } } } diff --git a/runtime/common/ethereum/mod.rs b/runtime/common/ethereum/mod.rs index 3aed7d9b72..086fadf5e7 100644 --- a/runtime/common/ethereum/mod.rs +++ b/runtime/common/ethereum/mod.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . +pub mod precompiles; pub mod self_contained_call; pub mod sponsoring; pub mod transaction_converter; diff --git a/runtime/common/ethereum/precompiles/mod.rs b/runtime/common/ethereum/precompiles/mod.rs new file mode 100644 index 0000000000..fd882d65a9 --- /dev/null +++ b/runtime/common/ethereum/precompiles/mod.rs @@ -0,0 +1,60 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +use pallet_evm::{Precompile, PrecompileHandle, PrecompileResult, PrecompileSet}; +use sp_core::H160; +use sp_std::marker::PhantomData; + +use pallet_evm_precompile_simple::{ECRecover}; +use sr25519::Sr25519Precompile; + +mod sr25519; +mod utils; + +pub struct UniquePrecompiles(PhantomData); + +impl UniquePrecompiles +where + R: pallet_evm::Config, +{ + pub fn new() -> Self { + Self(Default::default()) + } + pub fn used_addresses() -> [H160; 2] { + [hash(1), hash(20482)] + } +} +impl PrecompileSet for UniquePrecompiles +where + R: pallet_evm::Config, +{ + fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { + match handle.code_address() { + a if a == hash(1) => Some(ECRecover::execute(handle)), + // Sr25519 0x5002 + a if a == hash(20482) => Some(Sr25519Precompile::::execute(handle)), + _ => None, + } + } + + fn is_precompile(&self, address: H160) -> bool { + Self::used_addresses().contains(&address) + } +} + +fn hash(a: u64) -> H160 { + H160::from_low_u64_be(a) +} diff --git a/runtime/common/ethereum/precompiles/sr25519.rs b/runtime/common/ethereum/precompiles/sr25519.rs new file mode 100644 index 0000000000..59c24e9560 --- /dev/null +++ b/runtime/common/ethereum/precompiles/sr25519.rs @@ -0,0 +1,103 @@ +// Copyright 2019-2022 PureStake Inc. +// Copyright 2022 Stake Technologies + +// Astar Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Astar Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Astar Network. If not, see . + +use fp_evm::{Context, ExitSucceed, PrecompileHandle, PrecompileOutput}; +use pallet_evm::Precompile; +use sp_core::{crypto::UncheckedFrom, sr25519, H256}; +use sp_std::marker::PhantomData; +use sp_std::prelude::*; + +use super::utils::{Bytes, EvmDataReader, EvmDataWriter, EvmResult, FunctionModifier, Gasometer}; + +#[precompile_utils_macro::generate_function_selector] +#[derive(Debug, PartialEq)] +pub enum Action { + Verify = "verify(bytes32,bytes,bytes)", +} + +/// A precompile to wrap substrate sr25519 functions. +pub struct Sr25519Precompile(PhantomData); + +impl Precompile for Sr25519Precompile { + fn execute(handle: &mut impl PrecompileHandle) -> EvmResult { + log::trace!(target: "sr25519-precompile", "In sr25519 precompile"); + + let gasometer = Gasometer::new(); + + let (mut input, selector) = EvmDataReader::new_with_selector(&gasometer, handle.input())?; + let input = &mut input; + + gasometer.check_function_modifier( + handle.context(), + handle.is_static(), + FunctionModifier::View, + )?; + + match selector { + // Dispatchables + Action::Verify => Self::verify(input, &gasometer, handle.context()), + } + } +} + +impl Sr25519Precompile { + fn verify( + input: &mut EvmDataReader, + gasometer: &Gasometer, + _: &Context, + ) -> EvmResult { + // Bound check + input.expect_arguments(gasometer, 3)?; + + // Parse arguments + let public: sr25519::Public = + sr25519::Public::unchecked_from(input.read::(gasometer)?).into(); + let signature_bytes: Vec = input.read::(gasometer)?.into(); + let message: Vec = input.read::(gasometer)?.into(); + + // Parse signature + let signature_opt = sr25519::Signature::from_slice(&signature_bytes[..]); + + let signature = if let Some(sig) = signature_opt { + sig + } else { + // Return `false` if signature length is wrong + return Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: EvmDataWriter::new().write(false).build(), + }); + }; + + log::trace!( + target: "sr25519-precompile", + "Verify signature {:?} for public {:?} and message {:?}", + signature, public, message, + ); + + let is_confirmed = sp_io::crypto::sr25519_verify(&signature, &message[..], &public); + + log::trace!( + target: "sr25519-precompile", + "Verified signature {:?} is {:?}", + signature, is_confirmed, + ); + + Ok(PrecompileOutput { + exit_status: ExitSucceed::Returned, + output: EvmDataWriter::new().write(is_confirmed).build(), + }) + } +} diff --git a/runtime/common/ethereum/precompiles/utils/data.rs b/runtime/common/ethereum/precompiles/utils/data.rs new file mode 100644 index 0000000000..dcfe4f5ac6 --- /dev/null +++ b/runtime/common/ethereum/precompiles/utils/data.rs @@ -0,0 +1,486 @@ +// Copyright 2019-2022 PureStake Inc. +// Copyright 2022 Stake Technologies +// This file is part of Utils package, originally developed by Purestake Inc. +// Utils package used in Astar Network in terms of GPLv3. +// +// Utils is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Utils is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Utils. If not, see . + +use super::{EvmResult, Gasometer}; + +use sp_std::borrow::ToOwned; +use core::{any::type_name, ops::Range}; +use sp_core::{H160, H256, U256}; +use sp_std::{convert::TryInto, vec, vec::Vec}; + +/// The `address` type of Solidity. +/// H160 could represent 2 types of data (bytes20 and address) that are not encoded the same way. +/// To avoid issues writing H160 is thus not supported. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct Address(pub H160); + +impl From for Address { + fn from(a: H160) -> Address { + Address(a) + } +} + +impl From
for H160 { + fn from(a: Address) -> H160 { + a.0 + } +} + +/// The `bytes`/`string` type of Solidity. +/// It is different from `Vec` which will be serialized with padding for each `u8` element +/// of the array, while `Bytes` is tightly packed. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Bytes(pub Vec); + +impl From<&[u8]> for Bytes { + fn from(a: &[u8]) -> Self { + Self(a.to_owned()) + } +} + +impl From<&str> for Bytes { + fn from(a: &str) -> Self { + a.as_bytes().into() + } +} + +impl Into> for Bytes { + fn into(self: Self) -> Vec { + self.0 + } +} + +/// Wrapper around an EVM input slice, helping to parse it. +/// Provide functions to parse common types. +#[derive(Clone, Copy, Debug)] +pub struct EvmDataReader<'a> { + input: &'a [u8], + cursor: usize, +} + +impl<'a> EvmDataReader<'a> { + /// Create a new input parser. + pub fn new(input: &'a [u8]) -> Self { + Self { input, cursor: 0 } + } + + /// Create a new input parser from a selector-initial input. + pub fn new_with_selector(gasometer: &Gasometer, input: &'a [u8]) -> EvmResult<(Self, T)> + where + T: num_enum::TryFromPrimitive, + { + if input.len() < 4 { + return Err(gasometer.revert("tried to parse selector out of bounds")); + } + + let mut buffer = [0u8; 4]; + buffer.copy_from_slice(&input[0..4]); + let selector = T::try_from_primitive(u32::from_be_bytes(buffer)).map_err(|_| { + log::trace!( + target: "precompile-utils", + "Failed to match function selector for {}", + type_name::() + ); + gasometer.revert("unknown selector") + })?; + + Ok((Self::new(&input[4..]), selector)) + } + + /// Check the input has at least the correct amount of arguments before the end (32 bytes values). + pub fn expect_arguments(&self, gasometer: &Gasometer, args: usize) -> EvmResult { + if self.input.len() >= self.cursor + args * 32 { + Ok(()) + } else { + Err(gasometer.revert("input doesn't match expected length")) + } + } + + /// Read data from the input. + /// Must be provided a gasometer to generate correct Revert errors. + /// TODO : Benchmark and add cost of parsing to gasometer ? + pub fn read(&mut self, gasometer: &Gasometer) -> EvmResult { + T::read(self, gasometer) + } + + /// Reads a pointer, returning a reader targetting the pointed location. + pub fn read_pointer(&mut self, gasometer: &Gasometer) -> EvmResult { + let offset: usize = self + .read::(gasometer) + .map_err(|_| gasometer.revert("tried to parse array offset out of bounds"))? + .try_into() + .map_err(|_| gasometer.revert("array offset is too large"))?; + + if offset >= self.input.len() { + return Err(gasometer.revert("pointer points out of bounds")); + } + + Ok(Self { + input: &self.input[offset..], + cursor: 0, + }) + } + + /// Move the reading cursor with provided length, and return a range from the previous cursor + /// location to the new one. + /// Checks cursor overflows. + fn move_cursor(&mut self, gasometer: &Gasometer, len: usize) -> EvmResult> { + let start = self.cursor; + let end = self + .cursor + .checked_add(len) + .ok_or_else(|| gasometer.revert("data reading cursor overflow"))?; + + self.cursor = end; + + Ok(start..end) + } +} + +/// Help build an EVM input/output data. +/// +/// Functions takes `self` to allow chaining all calls like +/// `EvmDataWriter::new().write(...).write(...).build()`. +/// While it could be more ergonomic to take &mut self, this would +/// prevent to have a `build` function that don't clone the output. +#[derive(Clone, Debug)] +pub struct EvmDataWriter { + pub(crate) data: Vec, + offset_data: Vec, + selector: Option, +} + +#[derive(Clone, Debug)] +struct OffsetDatum { + // Offset location in the container data. + offset_position: usize, + // Data pointed by the offset that must be inserted at the end of container data. + data: Vec, + // Inside of arrays, the offset is not from the start of array data (length), but from the start + // of the item. This shift allow to correct this. + offset_shift: usize, +} + +impl EvmDataWriter { + /// Creates a new empty output builder (without selector). + pub fn new() -> Self { + Self { + data: vec![], + offset_data: vec![], + selector: None, + } + } + + /// Return the built data. + pub fn build(mut self) -> Vec { + Self::bake_offsets(&mut self.data, self.offset_data); + + if let Some(selector) = self.selector { + let mut output = selector.to_be_bytes().to_vec(); + output.append(&mut self.data); + output + } else { + self.data + } + } + + /// Add offseted data at the end of this writer's data, updating the offsets. + fn bake_offsets(output: &mut Vec, offsets: Vec) { + for mut offset_datum in offsets { + let offset_position = offset_datum.offset_position; + let offset_position_end = offset_position + 32; + + // The offset is the distance between the start of the data and the + // start of the pointed data (start of a struct, length of an array). + // Offsets in inner data are relative to the start of their respective "container". + // However in arrays the "container" is actually the item itself instead of the whole + // array, which is corrected by `offset_shift`. + let free_space_offset = output.len() - offset_datum.offset_shift; + + // Override dummy offset to the offset it will be in the final output. + U256::from(free_space_offset) + .to_big_endian(&mut output[offset_position..offset_position_end]); + + // Append this data at the end of the current output. + output.append(&mut offset_datum.data); + } + } + + /// Write arbitrary bytes. + /// Doesn't handle any alignement checks, prefer using `write` instead if possible. + fn write_raw_bytes(mut self, value: &[u8]) -> Self { + self.data.extend_from_slice(value); + self + } + + /// Write data of requested type. + pub fn write(mut self, value: T) -> Self { + T::write(&mut self, value); + self + } + + /// Writes a pointer to given data. + /// The data will be appended when calling `build`. + /// Initially write a dummy value as offset in this writer's data, which will be replaced by + /// the correct offset once the pointed data is appended. + /// + /// Takes `&mut self` since its goal is to be used inside `EvmData` impl and not in chains. + pub fn write_pointer(&mut self, data: Vec) { + let offset_position = self.data.len(); + H256::write(self, H256::repeat_byte(0xff)); + + self.offset_data.push(OffsetDatum { + offset_position, + data, + offset_shift: 0, + }); + } +} + +impl Default for EvmDataWriter { + fn default() -> Self { + Self::new() + } +} + +/// Data that can be converted from and to EVM data types. +pub trait EvmData: Sized { + fn read(reader: &mut EvmDataReader, gasometer: &Gasometer) -> EvmResult; + fn write(writer: &mut EvmDataWriter, value: Self); +} + +impl EvmData for H256 { + fn read(reader: &mut EvmDataReader, gasometer: &Gasometer) -> EvmResult { + let range = reader.move_cursor(gasometer, 32)?; + + let data = reader + .input + .get(range) + .ok_or_else(|| gasometer.revert("tried to parse H256 out of bounds"))?; + + Ok(H256::from_slice(data)) + } + + fn write(writer: &mut EvmDataWriter, value: Self) { + writer.data.extend_from_slice(value.as_bytes()); + } +} + +impl EvmData for Address { + fn read(reader: &mut EvmDataReader, gasometer: &Gasometer) -> EvmResult { + let range = reader.move_cursor(gasometer, 32)?; + + let data = reader + .input + .get(range) + .ok_or_else(|| gasometer.revert("tried to parse H160 out of bounds"))?; + + Ok(H160::from_slice(&data[12..32]).into()) + } + + fn write(writer: &mut EvmDataWriter, value: Self) { + H256::write(writer, value.0.into()); + } +} + +impl EvmData for U256 { + fn read(reader: &mut EvmDataReader, gasometer: &Gasometer) -> EvmResult { + let range = reader.move_cursor(gasometer, 32)?; + + let data = reader + .input + .get(range) + .ok_or_else(|| gasometer.revert("tried to parse U256 out of bounds"))?; + + Ok(U256::from_big_endian(data)) + } + + fn write(writer: &mut EvmDataWriter, value: Self) { + let mut buffer = [0u8; 32]; + value.to_big_endian(&mut buffer); + writer.data.extend_from_slice(&buffer); + } +} + +macro_rules! impl_evmdata_for_uints { + ($($uint:ty, )*) => { + $( + impl EvmData for $uint { + fn read(reader: &mut EvmDataReader, gasometer: &Gasometer) -> EvmResult { + let range = reader.move_cursor(gasometer, 32)?; + + let data = reader + .input + .get(range) + .ok_or_else(|| gasometer.revert(alloc::format!( + "tried to parse {} out of bounds", core::any::type_name::() + )))?; + + let mut buffer = [0u8; core::mem::size_of::()]; + buffer.copy_from_slice(&data[32 - core::mem::size_of::()..]); + Ok(Self::from_be_bytes(buffer)) + } + + fn write(writer: &mut EvmDataWriter, value: Self) { + let mut buffer = [0u8; 32]; + buffer[32 - core::mem::size_of::()..].copy_from_slice(&value.to_be_bytes()); + writer.data.extend_from_slice(&buffer); + } + } + )* + }; +} + +impl_evmdata_for_uints!(u16, u32, u64, u128,); + +// The implementation for u8 is specific, for performance reasons. +impl EvmData for u8 { + fn read(reader: &mut EvmDataReader, gasometer: &Gasometer) -> EvmResult { + let range = reader.move_cursor(gasometer, 32)?; + + let data = reader + .input + .get(range) + .ok_or_else(|| gasometer.revert("tried to parse u64 out of bounds"))?; + + Ok(data[31]) + } + + fn write(writer: &mut EvmDataWriter, value: Self) { + let mut buffer = [0u8; 32]; + buffer[31] = value; + + writer.data.extend_from_slice(&buffer); + } +} + +impl EvmData for bool { + fn read(reader: &mut EvmDataReader, gasometer: &Gasometer) -> EvmResult { + let h256 = H256::read(reader, gasometer) + .map_err(|_| gasometer.revert("tried to parse bool out of bounds"))?; + + Ok(!h256.is_zero()) + } + + fn write(writer: &mut EvmDataWriter, value: Self) { + let mut buffer = [0u8; 32]; + if value { + buffer[31] = 1; + } + + writer.data.extend_from_slice(&buffer); + } +} + +impl EvmData for Vec { + fn read(reader: &mut EvmDataReader, gasometer: &Gasometer) -> EvmResult { + let mut inner_reader = reader.read_pointer(gasometer)?; + + let array_size: usize = inner_reader + .read::(gasometer) + .map_err(|_| gasometer.revert("tried to parse array length out of bounds"))? + .try_into() + .map_err(|_| gasometer.revert("array length is too large"))?; + + let mut array = vec![]; + + let mut item_reader = EvmDataReader { + input: inner_reader + .input + .get(32..) + .ok_or_else(|| gasometer.revert("try to read array items out of bound"))?, + cursor: 0, + }; + + for _ in 0..array_size { + array.push(item_reader.read(gasometer)?); + } + + Ok(array) + } + + fn write(writer: &mut EvmDataWriter, value: Self) { + let mut inner_writer = EvmDataWriter::new().write(U256::from(value.len())); + + for inner in value { + // Any offset in items are relative to the start of the item instead of the + // start of the array. However if there is offseted data it must but appended after + // all items (offsets) are written. We thus need to rely on `compute_offsets` to do + // that, and must store a "shift" to correct the offsets. + let shift = inner_writer.data.len(); + let item_writer = EvmDataWriter::new().write(inner); + + inner_writer = inner_writer.write_raw_bytes(&item_writer.data); + for mut offset_datum in item_writer.offset_data { + offset_datum.offset_shift += 32; + offset_datum.offset_position += shift; + inner_writer.offset_data.push(offset_datum); + } + } + + writer.write_pointer(inner_writer.build()); + } +} + +impl EvmData for Bytes { + fn read(reader: &mut EvmDataReader, gasometer: &Gasometer) -> EvmResult { + let mut inner_reader = reader.read_pointer(gasometer)?; + + // Read bytes/string size. + let array_size: usize = inner_reader + .read::(gasometer) + .map_err(|_| gasometer.revert("tried to parse bytes/string length out of bounds"))? + .try_into() + .map_err(|_| gasometer.revert("bytes/string length is too large"))?; + + // Get valid range over the bytes data. + let range = inner_reader.move_cursor(gasometer, array_size)?; + + let data = inner_reader + .input + .get(range) + .ok_or_else(|| gasometer.revert("tried to parse bytes/string out of bounds"))?; + + let bytes = Self(data.to_owned()); + + Ok(bytes) + } + + fn write(writer: &mut EvmDataWriter, value: Self) { + let length = value.0.len(); + + // Pad the data. + // Leave it as is if a multiple of 32, otherwise pad to next + // multiple or 32. + let chunks = length / 32; + let padded_size = match length % 32 { + 0 => chunks * 32, + _ => (chunks + 1) * 32, + }; + + let mut value = value.0.to_vec(); + value.resize(padded_size, 0); + + writer.write_pointer( + EvmDataWriter::new() + .write(U256::from(length)) + .write_raw_bytes(&value) + .build(), + ); + } +} diff --git a/runtime/common/ethereum/precompiles/utils/macro/Cargo.toml b/runtime/common/ethereum/precompiles/utils/macro/Cargo.toml new file mode 100644 index 0000000000..75c66edc8d --- /dev/null +++ b/runtime/common/ethereum/precompiles/utils/macro/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "precompile-utils-macro" +authors = [ "StakeTechnologies", "PureStake" ] +description = "" +edition = "2018" +version = "0.1.0" + +[lib] +proc-macro = true + +[dependencies] +num_enum = { version = "0.5.3", default-features = false } +proc-macro2 = "1.0" +quote = "1.0" +sha3 = "0.8" +syn = { version = "1.0", features = [ "extra-traits", "fold", "full", "visit" ] } diff --git a/runtime/common/ethereum/precompiles/utils/macro/src/lib.rs b/runtime/common/ethereum/precompiles/utils/macro/src/lib.rs new file mode 100644 index 0000000000..a7fb58efda --- /dev/null +++ b/runtime/common/ethereum/precompiles/utils/macro/src/lib.rs @@ -0,0 +1,115 @@ +// Copyright 2019-2022 PureStake Inc. +// Copyright 2022 Stake Technologies +// This file is part of Utils package, originally developed by Purestake Inc. +// Utils package used in Astar Network in terms of GPLv3. +// +// Utils is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Utils is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Utils. If not, see . + +#![crate_type = "proc-macro"] +extern crate proc_macro; + +use proc_macro::TokenStream; +use proc_macro2::Literal; +use quote::{quote, quote_spanned}; +use sha3::{Digest, Keccak256}; +use std::convert::TryInto; +use syn::{parse_macro_input, spanned::Spanned, Expr, ExprLit, Ident, ItemEnum, Lit}; + +/// This macro allows to associate to each variant of an enumeration a discriminant (of type u32 +/// whose value corresponds to the first 4 bytes of the Hash Keccak256 of the character string +///indicated by the user of this macro. +/// +/// Usage: +/// +/// ```ignore +/// #[generate_function_selector] +/// enum Action { +/// Toto = "toto()", +/// Tata = "tata()", +/// } +/// ``` +/// +/// Extanded to: +/// +/// ```rust +/// #[repr(u32)] +/// enum Action { +/// Toto = 119097542u32, +/// Tata = 1414311903u32, +/// } +/// ``` +/// +#[proc_macro_attribute] +pub fn generate_function_selector(_: TokenStream, input: TokenStream) -> TokenStream { + let item = parse_macro_input!(input as ItemEnum); + + let ItemEnum { + attrs, + vis, + enum_token, + ident, + variants, + .. + } = item; + + let mut ident_expressions: Vec = vec![]; + let mut variant_expressions: Vec = vec![]; + for variant in variants { + match variant.discriminant { + Some((_, Expr::Lit(ExprLit { lit, .. }))) => { + if let Lit::Str(lit_str) = lit { + let selector = u32::from_be_bytes( + Keccak256::digest(lit_str.value().as_ref())[..4] + .try_into() + .unwrap(), + ); + ident_expressions.push(variant.ident); + variant_expressions.push(Expr::Lit(ExprLit { + lit: Lit::Verbatim(Literal::u32_suffixed(selector)), + attrs: Default::default(), + })); + } else { + return quote_spanned! { + lit.span() => compile_error("Expected literal string"); + } + .into(); + } + } + Some((_eg, expr)) => { + return quote_spanned! { + expr.span() => compile_error("Expected literal"); + } + .into() + } + None => { + return quote_spanned! { + variant.span() => compile_error("Each variant must have a discriminant"); + } + .into() + } + } + } + + (quote! { + #(#attrs)* + #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)] + #[repr(u32)] + #vis #enum_token #ident { + #( + #ident_expressions = #variant_expressions, + )* + } + }) + .into() +} diff --git a/runtime/common/ethereum/precompiles/utils/mod.rs b/runtime/common/ethereum/precompiles/utils/mod.rs new file mode 100644 index 0000000000..7763f591e9 --- /dev/null +++ b/runtime/common/ethereum/precompiles/utils/mod.rs @@ -0,0 +1,95 @@ +// Copyright 2019-2022 PureStake Inc. +// Copyright 2022 Stake Technologies +// This file is part of Utils package, originally developed by Purestake Inc. +// Utils package used in Astar Network in terms of GPLv3. +// +// Utils is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Utils is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Utils. If not, see . + +use sp_std::borrow::ToOwned; +use fp_evm::{Context, ExitRevert, PrecompileFailure}; +use sp_core::U256; +use sp_std::marker::PhantomData; + +mod data; + +pub use data::{Bytes, EvmData, EvmDataReader, EvmDataWriter}; + +/// Alias for Result returning an EVM precompile error. +pub type EvmResult = Result; + +/// Helper functions requiring a Runtime. +/// This runtime must of course implement `pallet_evm::Config`. +#[derive(Clone, Copy, Debug)] +pub struct RuntimeHelper(PhantomData); + +/// Represents modifiers a Solidity function can be annotated with. +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum FunctionModifier { + /// Function that doesn't modify the state. + View, + /// Function that modifies the state and accept funds. + Payable, +} + +/// Custom Gasometer to record costs in precompiles. +/// It is advised to record known costs as early as possible to +/// avoid unecessary computations if there is an Out of Gas. +/// +/// Provides functions related to reverts, as reverts takes the recorded amount +/// of gas into account. +#[derive(Clone, Copy, Debug)] +pub struct Gasometer(); + +impl Gasometer { + /// Create a new Gasometer with provided gas limit. + /// None is no limit. + pub fn new() -> Self { + Self() + } + + /// Revert the execution, making the user pay for the the currently + /// recorded cost. It is better to **revert** instead of **error** as + /// erroring consumes the entire gas limit, and **revert** returns an error + /// message to the calling contract. + /// + /// TODO : Record cost of the input based on its size and handle Out of Gas ? + /// This might be required if we format revert messages using user data. + #[must_use] + pub fn revert(&self, output: impl AsRef<[u8]>) -> PrecompileFailure { + PrecompileFailure::Revert { + exit_status: ExitRevert::Reverted, + output: output.as_ref().to_owned(), + } + } + + #[must_use] + /// Check that a function call is compatible with the context it is + /// called into. + pub fn check_function_modifier( + &self, + context: &Context, + is_static: bool, + modifier: FunctionModifier, + ) -> EvmResult { + if is_static && modifier != FunctionModifier::View { + return Err(self.revert("can't call non-static function in static context")); + } + + if modifier != FunctionModifier::Payable && context.apparent_value > U256::zero() { + return Err(self.revert("function is not payable")); + } + + Ok(()) + } +} diff --git a/runtime/common/ethereum/self_contained_call.rs b/runtime/common/ethereum/self_contained_call.rs index 2b26d07af7..7a5d245776 100644 --- a/runtime/common/ethereum/self_contained_call.rs +++ b/runtime/common/ethereum/self_contained_call.rs @@ -69,9 +69,13 @@ impl fp_self_contained::SelfContainedCall for RuntimeCall { fn pre_dispatch_self_contained( &self, info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, ) -> Option> { match self { - RuntimeCall::Ethereum(call) => call.pre_dispatch_self_contained(info), + RuntimeCall::Ethereum(call) => { + call.pre_dispatch_self_contained(info, dispatch_info, len) + } _ => None, } } diff --git a/runtime/common/ethereum/sponsoring.rs b/runtime/common/ethereum/sponsoring.rs index a78d8606d7..6d8fd7b4d3 100644 --- a/runtime/common/ethereum/sponsoring.rs +++ b/runtime/common/ethereum/sponsoring.rs @@ -32,14 +32,22 @@ use pallet_fungible::{ Config as FungibleConfig, erc::{UniqueFungibleCall, ERC20Call}, }; -use pallet_refungible::Config as RefungibleConfig; +use pallet_refungible::{ + Config as RefungibleConfig, + erc::UniqueRefungibleCall, + erc_token::{RefungibleTokenHandle, UniqueRefungibleTokenCall}, + RefungibleHandle, +}; use pallet_unique::Config as UniqueConfig; use sp_std::prelude::*; -use up_data_structs::{CollectionMode, CreateItemData, CreateNftData, TokenId}; +use up_data_structs::{ + CollectionMode, CreateItemData, CreateNftData, mapping::TokenAddressMapping, TokenId, +}; use up_sponsorship::SponsorshipHandler; - use crate::{Runtime, runtime_common::sponsoring::*}; +mod refungible; + pub type EvmSponsorshipHandler = ( UniqueEthSponsorshipHandler, pallet_evm_contract_helpers::HelpersContractSponsoring, @@ -53,80 +61,163 @@ impl who: &T::CrossAccountId, call_context: &CallContext, ) -> Option { - let collection_id = map_eth_to_id(&call_context.contract_address)?; - let collection = >::new(collection_id)?; - let sponsor = collection.sponsorship.sponsor()?.clone(); - let (method_id, mut reader) = AbiReader::new_call(&call_context.input).ok()?; - Some(T::CrossAccountId::from_sub(match &collection.mode { - CollectionMode::NFT => { - let call = >::parse(method_id, &mut reader).ok()??; - match call { - UniqueNFTCall::TokenProperties(TokenPropertiesCall::SetProperty { - token_id, - key, - value, - .. - }) => { - let token_id: TokenId = token_id.try_into().ok()?; - withdraw_set_token_property::( + if let Some(collection_id) = map_eth_to_id(&call_context.contract_address) { + let collection = >::new(collection_id)?; + let sponsor = collection.sponsorship.sponsor()?.clone(); + let (method_id, mut reader) = AbiReader::new_call(&call_context.input).ok()?; + Some(T::CrossAccountId::from_sub(match &collection.mode { + CollectionMode::NFT => { + let call = >::parse(method_id, &mut reader).ok()??; + match call { + UniqueNFTCall::TokenProperties(TokenPropertiesCall::SetProperty { + token_id, + key, + value, + .. + }) => { + let token_id: TokenId = token_id.try_into().ok()?; + withdraw_set_token_property::( + &collection, + &who, + &token_id, + key.len() + value.len(), + ) + .map(|()| sponsor) + } + UniqueNFTCall::ERC721UniqueExtensions( + ERC721UniqueExtensionsCall::Transfer { token_id, .. }, + ) => { + let token_id: TokenId = token_id.try_into().ok()?; + withdraw_transfer::(&collection, &who, &token_id).map(|()| sponsor) + } + UniqueNFTCall::ERC721UniqueMintable( + ERC721UniqueMintableCall::Mint { .. } + | ERC721UniqueMintableCall::MintCheckId { .. } + | ERC721UniqueMintableCall::MintWithTokenUri { .. } + | ERC721UniqueMintableCall::MintWithTokenUriCheckId { .. }, + ) => withdraw_create_item::( &collection, &who, - &token_id, - key.len() + value.len(), + &CreateItemData::NFT(CreateNftData::default()), ) - .map(|()| sponsor) - } - UniqueNFTCall::ERC721UniqueExtensions( - ERC721UniqueExtensionsCall::Transfer { token_id, .. }, - ) => { - let token_id: TokenId = token_id.try_into().ok()?; - withdraw_transfer::(&collection, &who, &token_id).map(|()| sponsor) + .map(|()| sponsor), + UniqueNFTCall::ERC721(ERC721Call::TransferFrom { + token_id, from, .. + }) => { + let token_id: TokenId = token_id.try_into().ok()?; + let from = T::CrossAccountId::from_eth(from); + withdraw_transfer::(&collection, &from, &token_id).map(|()| sponsor) + } + UniqueNFTCall::ERC721(ERC721Call::Approve { token_id, .. }) => { + let token_id: TokenId = token_id.try_into().ok()?; + withdraw_approve::(&collection, who.as_sub(), &token_id) + .map(|()| sponsor) + } + _ => None, } - UniqueNFTCall::ERC721UniqueMintable( - ERC721UniqueMintableCall::Mint { .. } - | ERC721UniqueMintableCall::MintCheckId { .. } - | ERC721UniqueMintableCall::MintWithTokenUri { .. } - | ERC721UniqueMintableCall::MintWithTokenUriCheckId { .. }, - ) => withdraw_create_item::( - &collection, - &who, - &CreateItemData::NFT(CreateNftData::default()), - ) - .map(|()| sponsor), - UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, from, .. }) => { - let token_id: TokenId = token_id.try_into().ok()?; - let from = T::CrossAccountId::from_eth(from); - withdraw_transfer::(&collection, &from, &token_id).map(|()| sponsor) - } - UniqueNFTCall::ERC721(ERC721Call::Approve { token_id, .. }) => { - let token_id: TokenId = token_id.try_into().ok()?; - withdraw_approve::(&collection, who.as_sub(), &token_id) - .map(|()| sponsor) - } - _ => None, } - } - CollectionMode::Fungible(_) => { - let call = >::parse(method_id, &mut reader).ok()??; - #[allow(clippy::single_match)] - match call { - UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => { - withdraw_transfer::(&collection, who, &TokenId::default()) - .map(|()| sponsor) - } - UniqueFungibleCall::ERC20(ERC20Call::TransferFrom { from, .. }) => { - let from = T::CrossAccountId::from_eth(from); - withdraw_transfer::(&collection, &from, &TokenId::default()) - .map(|()| sponsor) - } - UniqueFungibleCall::ERC20(ERC20Call::Approve { .. }) => { - withdraw_approve::(&collection, who.as_sub(), &TokenId::default()) - .map(|()| sponsor) + CollectionMode::ReFungible => { + let call = >::parse(method_id, &mut reader).ok()??; + refungible::call_sponsor(call, collection, who).map(|()| sponsor) + } + CollectionMode::Fungible(_) => { + let call = >::parse(method_id, &mut reader).ok()??; + match call { + UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => { + withdraw_transfer::(&collection, who, &TokenId::default()) + .map(|()| sponsor) + } + UniqueFungibleCall::ERC20(ERC20Call::TransferFrom { from, .. }) => { + let from = T::CrossAccountId::from_eth(from); + withdraw_transfer::(&collection, &from, &TokenId::default()) + .map(|()| sponsor) + } + UniqueFungibleCall::ERC20(ERC20Call::Approve { .. }) => { + withdraw_approve::(&collection, who.as_sub(), &TokenId::default()) + .map(|()| sponsor) + } + _ => None, } - _ => None, } + }?)) + } else { + let (collection_id, token_id) = + T::EvmTokenAddressMapping::address_to_token(&call_context.contract_address)?; + let collection = >::new(collection_id)?; + if collection.mode != CollectionMode::ReFungible { + return None; } - _ => None, - }?)) + let sponsor = collection.sponsorship.sponsor()?.clone(); + let rft_collection = RefungibleHandle::cast(collection); + // Token existance isn't checked at this point and should be checked in `withdraw` method. + let token = RefungibleTokenHandle(rft_collection, token_id); + + let (method_id, mut reader) = AbiReader::new_call(&call_context.input).ok()?; + let call = >::parse(method_id, &mut reader).ok()??; + Some(T::CrossAccountId::from_sub( + refungible::token_call_sponsor(call, token, who).map(|()| sponsor)?, + )) + } + } +} + +mod common { + use super::*; + + use pallet_common::erc::{CollectionCall}; + + pub fn collection_call_sponsor( + call: CollectionCall, + _collection: CollectionHandle, + _who: &T::CrossAccountId, + ) -> Option<()> + where + T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig, + { + use CollectionCall::*; + + match call { + // Readonly + ERC165Call(_, _) + | CollectionProperty { .. } + | CollectionProperties { .. } + | HasCollectionPendingSponsor + | CollectionSponsor + | ContractAddress + | AllowlistedCross { .. } + | IsOwnerOrAdminEth { .. } + | IsOwnerOrAdminCross { .. } + | CollectionOwner + | CollectionAdmins + | CollectionLimits + | CollectionNestingRestrictedIds + | CollectionNestingPermissions + | UniqueCollectionType => None, + + // Not sponsored + AddToCollectionAllowList { .. } + | AddToCollectionAllowListCross { .. } + | RemoveFromCollectionAllowList { .. } + | RemoveFromCollectionAllowListCross { .. } + | AddCollectionAdminCross { .. } + | RemoveCollectionAdminCross { .. } + | AddCollectionAdmin { .. } + | RemoveCollectionAdmin { .. } + | SetNestingBool { .. } + | SetNesting { .. } + | SetCollectionAccess { .. } + | SetCollectionMintMode { .. } + | SetOwner { .. } + | ChangeCollectionOwnerCross { .. } + | SetCollectionProperty { .. } + | SetCollectionProperties { .. } + | DeleteCollectionProperty { .. } + | DeleteCollectionProperties { .. } + | SetCollectionSponsor { .. } + | SetCollectionSponsorCross { .. } + | SetCollectionLimit { .. } + | ConfirmCollectionSponsorship + | RemoveCollectionSponsor => None, + } } } diff --git a/runtime/common/ethereum/sponsoring/refungible.rs b/runtime/common/ethereum/sponsoring/refungible.rs new file mode 100644 index 0000000000..b92b88bd7c --- /dev/null +++ b/runtime/common/ethereum/sponsoring/refungible.rs @@ -0,0 +1,381 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +//! Implements EVM sponsoring logic via TransactionValidityHack + +use core::convert::TryInto; +use pallet_common::CollectionHandle; +use pallet_evm::account::CrossAccountId; +use pallet_fungible::Config as FungibleConfig; +use pallet_refungible::Config as RefungibleConfig; +use pallet_nonfungible::Config as NonfungibleConfig; +use pallet_unique::Config as UniqueConfig; +use up_data_structs::{CreateItemData, CreateNftData, TokenId}; + +use super::common; +use crate::runtime_common::sponsoring::*; + +use pallet_refungible::{ + erc::{ + ERC721BurnableCall, ERC721Call, ERC721EnumerableCall, ERC721MetadataCall, + ERC721UniqueExtensionsCall, ERC721UniqueMintableCall, TokenPropertiesCall, + UniqueRefungibleCall, + }, + erc_token::{ + ERC1633Call, ERC20Call, ERC20UniqueExtensionsCall, RefungibleTokenHandle, + UniqueRefungibleTokenCall, + }, +}; + +pub fn call_sponsor( + call: UniqueRefungibleCall, + collection: CollectionHandle, + who: &T::CrossAccountId, +) -> Option<()> +where + T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig, +{ + use UniqueRefungibleCall::*; + + match call { + // Readonly + ERC165Call(_, _) => None, + + ERC721Enumerable(call) => erc721::enumerable_call_sponsor(call, collection, who), + ERC721Burnable(call) => erc721::burnable_call_sponsor(call, collection, who), + ERC721Metadata(call) => erc721::metadata_call_sponsor(call, collection, who), + Collection(call) => common::collection_call_sponsor(call, collection, who), + ERC721(call) => erc721::call_sponsor(call, collection, who), + ERC721UniqueExtensions(call) => { + erc721::unique_extensions_call_sponsor(call, collection, who) + } + ERC721UniqueMintable(call) => erc721::unique_mintable_call_sponsor(call, collection, who), + TokenProperties(call) => token_properties_call_sponsor(call, collection, who), + } +} + +pub fn token_properties_call_sponsor( + call: TokenPropertiesCall, + collection: CollectionHandle, + who: &T::CrossAccountId, +) -> Option<()> +where + T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig, +{ + use TokenPropertiesCall::*; + + match call { + // Readonly + ERC165Call(_, _) | Property { .. } | TokenPropertyPermissions => None, + + // Not sponsored + SetTokenPropertyPermission { .. } + | SetTokenPropertyPermissions { .. } + | SetProperties { .. } + | DeleteProperty { .. } + | DeleteProperties { .. } => None, + + SetProperty { + token_id, + key, + value, + .. + } => { + let token_id = TokenId::try_from(token_id).ok()?; + withdraw_set_token_property::(&collection, &who, &token_id, key.len() + value.len()) + } + } +} + +pub fn token_call_sponsor( + call: UniqueRefungibleTokenCall, + token: RefungibleTokenHandle, + who: &T::CrossAccountId, +) -> Option<()> +where + T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig, +{ + use UniqueRefungibleTokenCall::*; + + match call { + // Readonly + ERC165Call(_, _) => None, + + ERC20(call) => erc20::call_sponsor(call, token, who), + ERC20UniqueExtensions(call) => erc20::unique_extensions_call_sponsor(call, token, who), + ERC1633(call) => erc1633::call_sponsor(call, token, who), + } +} + +mod erc721 { + use super::*; + + pub fn call_sponsor( + call: ERC721Call, + collection: CollectionHandle, + _who: &T::CrossAccountId, + ) -> Option<()> + where + T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig, + { + use ERC721Call::*; + + match call { + // Readonly + ERC165Call(_, _) + | BalanceOf { .. } + | OwnerOf { .. } + | GetApproved { .. } + | IsApprovedForAll { .. } + | CollectionHelperAddress => None, + + // Not sponsored + SafeTransferFromWithData { .. } + | SafeTransferFrom { .. } + | SetApprovalForAll { .. } => None, + + TransferFrom { token_id, from, .. } => { + let token_id = TokenId::try_from(token_id).ok()?; + let from = T::CrossAccountId::from_eth(from); + withdraw_transfer::(&collection, &from, &token_id) + } + + // Not supported + Approve { .. } => None, + } + } + + pub fn enumerable_call_sponsor( + call: ERC721EnumerableCall, + _collection: CollectionHandle, + _who: &T::CrossAccountId, + ) -> Option<()> + where + T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig, + { + use ERC721EnumerableCall::*; + + match call { + // Readonly + ERC165Call(_, _) | TokenByIndex { .. } | TokenOfOwnerByIndex { .. } | TotalSupply => { + None + } + } + } + + pub fn burnable_call_sponsor( + call: ERC721BurnableCall, + _collection: CollectionHandle, + _who: &T::CrossAccountId, + ) -> Option<()> + where + T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig, + { + use ERC721BurnableCall::*; + + match call { + // Readonly + ERC165Call(_, _) => None, + + // Not sponsored + Burn { .. } => None, + } + } + + pub fn metadata_call_sponsor( + call: ERC721MetadataCall, + _collection: CollectionHandle, + _who: &T::CrossAccountId, + ) -> Option<()> + where + T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig, + { + use ERC721MetadataCall::*; + + match call { + // Readonly + ERC165Call(_, _) | NameProxy | SymbolProxy | TokenUri { .. } => None, + } + } + + pub fn unique_extensions_call_sponsor( + call: ERC721UniqueExtensionsCall, + collection: CollectionHandle, + who: &T::CrossAccountId, + ) -> Option<()> + where + T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig, + { + use ERC721UniqueExtensionsCall::*; + + match call { + // Readonly + ERC165Call(_, _) + | Name + | Symbol + | Description + | CrossOwnerOf { .. } + | Properties { .. } + | NextTokenId + | TokenContractAddress { .. } => None, + + // Not sponsored + BurnFrom { .. } + | BurnFromCross { .. } + | MintBulk { .. } + | MintBulkWithTokenUri { .. } => None, + + MintCross { .. } => withdraw_create_item::( + &collection, + &who, + &CreateItemData::NFT(CreateNftData::default()), + ), + + TransferCross { token_id, .. } + | TransferFromCross { token_id, .. } + | Transfer { token_id, .. } => { + let token_id = TokenId::try_from(token_id).ok()?; + withdraw_transfer::(&collection, &who, &token_id) + } + } + } + + pub fn unique_mintable_call_sponsor( + call: ERC721UniqueMintableCall, + collection: CollectionHandle, + who: &T::CrossAccountId, + ) -> Option<()> + where + T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig, + { + use ERC721UniqueMintableCall::*; + + match call { + // Readonly + ERC165Call(_, _) | MintingFinished => None, + + // Not sponsored + FinishMinting => None, + + Mint { .. } + | MintCheckId { .. } + | MintWithTokenUri { .. } + | MintWithTokenUriCheckId { .. } => withdraw_create_item::( + &collection, + &who, + &CreateItemData::NFT(CreateNftData::default()), + ), + } + } +} + +/// Module for methods of refungible token +/// +/// Existance of token should be checked before searching for sponsor +/// because RefungibleTokenHandle doesn't check token's existence upon creation +mod erc20 { + use super::*; + + pub fn call_sponsor( + call: ERC20Call, + token: RefungibleTokenHandle, + who: &T::CrossAccountId, + ) -> Option<()> + where + T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig, + { + use ERC20Call::*; + + match call { + // Readonly + ERC165Call(_, _) + | Name + | Symbol + | TotalSupply + | Decimals + | BalanceOf { .. } + | Allowance { .. } => None, + + Transfer { .. } => { + let RefungibleTokenHandle(handle, token_id) = token; + let token_id = token_id.try_into().ok()?; + withdraw_transfer::(&handle, &who, &token_id) + } + TransferFrom { from, .. } => { + let RefungibleTokenHandle(handle, token_id) = token; + let token_id = token_id.try_into().ok()?; + let from = T::CrossAccountId::from_eth(from); + withdraw_transfer::(&handle, &from, &token_id) + } + Approve { .. } => { + let RefungibleTokenHandle(handle, token_id) = token; + let token_id = token_id.try_into().ok()?; + withdraw_approve::(&handle, who.as_sub(), &token_id) + } + } + } + + pub fn unique_extensions_call_sponsor( + call: ERC20UniqueExtensionsCall, + token: RefungibleTokenHandle, + who: &T::CrossAccountId, + ) -> Option<()> + where + T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig, + { + use ERC20UniqueExtensionsCall::*; + + match call { + // Readonly + ERC165Call(_, _) => None, + + // Not sponsored + BurnFrom { .. } | BurnFromCross { .. } | Repartition { .. } => None, + + TransferCross { .. } | TransferFromCross { .. } => { + let RefungibleTokenHandle(handle, token_id) = token; + let token_id = token_id.try_into().ok()?; + withdraw_transfer::(&handle, &who, &token_id) + } + + ApproveCross { .. } => { + let RefungibleTokenHandle(handle, token_id) = token; + let token_id = token_id.try_into().ok()?; + withdraw_approve::(&handle, who.as_sub(), &token_id) + } + } + } +} + +mod erc1633 { + use super::*; + + pub fn call_sponsor( + call: ERC1633Call, + _token: RefungibleTokenHandle, + _who: &T::CrossAccountId, + ) -> Option<()> + where + T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig, + { + use ERC1633Call::*; + + match call { + // Readonly + ERC165Call(_, _) | ParentToken | ParentTokenId => None, + } + } +} diff --git a/runtime/common/mod.rs b/runtime/common/mod.rs index 14f8d197b0..38a2334ef4 100644 --- a/runtime/common/mod.rs +++ b/runtime/common/mod.rs @@ -145,6 +145,10 @@ impl BlockNumberProvider .map(|d| d.relay_parent_number) .unwrap_or_default() } + #[cfg(feature = "runtime-benchmarks")] + fn set_block_number(block: Self::BlockNumber) { + cumulus_pallet_parachain_system::RelaychainBlockNumberProvider::::set_block_number(block) + } } pub(crate) struct CheckInherents; diff --git a/runtime/common/runtime_apis.rs b/runtime/common/runtime_apis.rs index 9e2bcd0c77..241c0db9c4 100644 --- a/runtime/common/runtime_apis.rs +++ b/runtime/common/runtime_apis.rs @@ -35,7 +35,7 @@ macro_rules! impl_common_runtime_apis { ) => { use sp_std::prelude::*; use sp_api::impl_runtime_apis; - use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160}; + use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H256, U256, H160, Bytes}; use sp_runtime::{ Permill, traits::Block as BlockT, @@ -186,6 +186,10 @@ macro_rules! impl_common_runtime_apis { fn total_pieces(collection: CollectionId, token_id: TokenId) -> Result, DispatchError> { dispatch_unique_runtime!(collection.total_pieces(token_id)) + } + + fn allowance_for_all(collection: CollectionId, owner: CrossAccountId, operator: CrossAccountId) -> Result { + dispatch_unique_runtime!(collection.allowance_for_all(owner, operator)) } } @@ -482,6 +486,7 @@ macro_rules! impl_common_runtime_apis { }; let is_transactional = false; + let validate = false; ::Runner::call( CrossAccountId::from_eth(from), to, @@ -493,6 +498,7 @@ macro_rules! impl_common_runtime_apis { nonce, access_list.unwrap_or_default(), is_transactional, + validate, config.as_ref().unwrap_or_else(|| ::config()), ).map_err(|err| err.error.into()) } @@ -518,6 +524,7 @@ macro_rules! impl_common_runtime_apis { }; let is_transactional = false; + let validate = false; ::Runner::create( CrossAccountId::from_eth(from), data, @@ -528,6 +535,7 @@ macro_rules! impl_common_runtime_apis { nonce, access_list.unwrap_or_default(), is_transactional, + validate, config.as_ref().unwrap_or_else(|| ::config()), ).map_err(|err| err.error.into()) } @@ -566,6 +574,8 @@ macro_rules! impl_common_runtime_apis { fn elasticity() -> Option { None } + + fn gas_limit_multiplier_support() {} } impl fp_rpc::ConvertTransactionRuntimeApi for Runtime { @@ -768,17 +778,41 @@ macro_rules! impl_common_runtime_apis { } } + impl up_pov_estimate_rpc::PovEstimateApi for Runtime { + #[allow(unused_variables)] + fn pov_estimate(uxt: Bytes) -> ApplyExtrinsicResult { + #[cfg(feature = "pov-estimate")] + { + use codec::Decode; + + let uxt_decode = <::Extrinsic as Decode>::decode(&mut &*uxt) + .map_err(|_| DispatchError::Other("failed to decode the extrinsic")); + + let uxt = match uxt_decode { + Ok(uxt) => uxt, + Err(err) => return Ok(err.into()), + }; + + Executive::apply_extrinsic(uxt) + } + + #[cfg(not(feature = "pov-estimate"))] + return Ok(unsupported!()); + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade() -> (frame_support::pallet_prelude::Weight, frame_support::pallet_prelude::Weight) { + fn on_runtime_upgrade(checks: bool) -> (frame_support::pallet_prelude::Weight, frame_support::pallet_prelude::Weight) { log::info!("try-runtime::on_runtime_upgrade unique-chain."); - let weight = Executive::try_runtime_upgrade().unwrap(); + let weight = Executive::try_runtime_upgrade(checks).unwrap(); (weight, crate::config::substrate::RuntimeBlockWeights::get().max_block) } fn execute_block( block: Block, state_root_check: bool, + signature_check: bool, select: frame_try_runtime::TryStateSelect ) -> frame_support::pallet_prelude::Weight { log::info!( @@ -789,7 +823,7 @@ macro_rules! impl_common_runtime_apis { select, ); - Executive::try_execute_block(block, state_root_check, select).unwrap() + Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() } } } diff --git a/runtime/common/scheduler.rs b/runtime/common/scheduler.rs index 7c0e3104fe..88ee4c7222 100644 --- a/runtime/common/scheduler.rs +++ b/runtime/common/scheduler.rs @@ -15,129 +15,79 @@ // along with Unique Network. If not, see . use frame_support::{ - traits::NamedReservableCurrency, - weights::{GetDispatchInfo, PostDispatchInfo, DispatchInfo}, + dispatch::{GetDispatchInfo, PostDispatchInfo, DispatchInfo}, }; use sp_runtime::{ traits::{Dispatchable, Applyable, Member}, - generic::Era, transaction_validity::TransactionValidityError, - DispatchErrorWithPostInfo, DispatchError, + DispatchErrorWithPostInfo, }; use codec::Encode; -use crate::{Runtime, Call, Origin, Balances, ChargeTransactionPayment, maintenance}; -use up_common::types::{AccountId, Balance}; +use crate::{Runtime, RuntimeCall, RuntimeOrigin, maintenance}; +use up_common::types::AccountId; use fp_self_contained::SelfContainedCall; -use pallet_unique_scheduler::DispatchCall; +use pallet_unique_scheduler_v2::DispatchCall; +use pallet_transaction_payment::ChargeTransactionPayment; /// The SignedExtension to the basic transaction logic. pub type SignedExtraScheduler = ( - frame_system::CheckSpecVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, frame_system::CheckWeight, maintenance::CheckMaintenance, ChargeTransactionPayment, ); -fn get_signed_extras(from: ::AccountId) -> SignedExtraScheduler { +fn get_signed_extras() -> SignedExtraScheduler { ( - frame_system::CheckSpecVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(Era::Immortal), - frame_system::CheckNonce::::from(frame_system::Pallet::::account_nonce( - from, - )), frame_system::CheckWeight::::new(), maintenance::CheckMaintenance, + ChargeTransactionPayment::::from(0), ) } pub struct SchedulerPaymentExecutor; -impl +impl DispatchCall for SchedulerPaymentExecutor where - ::Call: Member - + Dispatchable + ::RuntimeCall: Member + + Dispatchable + SelfContainedCall + GetDispatchInfo + From>, SelfContainedSignedInfo: Send + Sync + 'static, - Call: From<::Call> - + From<::Call> + RuntimeCall: From<::RuntimeCall> + + From<::RuntimeCall> + SelfContainedCall, sp_runtime::AccountId32: From<::AccountId>, { fn dispatch_call( - signer: ::AccountId, - call: ::Call, + signer: Option<::AccountId>, + call: ::RuntimeCall, ) -> Result< Result>, TransactionValidityError, > { let dispatch_info = call.get_dispatch_info(); + let len = call.encoded_size(); + + let signed = match signer { + Some(signer) => fp_self_contained::CheckedSignature::Signed( + signer.clone().into(), + get_signed_extras(), + ), + None => fp_self_contained::CheckedSignature::Unsigned, + }; + let extrinsic = fp_self_contained::CheckedExtrinsic::< AccountId, - Call, + RuntimeCall, SignedExtraScheduler, SelfContainedSignedInfo, > { - signed: fp_self_contained::CheckedSignature::< - AccountId, - SignedExtraScheduler, - SelfContainedSignedInfo, - >::Signed(signer.clone().into(), get_signed_extras(signer.into())), + signed, function: call.into(), }; - extrinsic.apply::(&dispatch_info, 0) - } - - fn reserve_balance( - id: [u8; 16], - sponsor: ::AccountId, - call: ::Call, - count: u32, - ) -> Result<(), DispatchError> { - let dispatch_info = call.get_dispatch_info(); - let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0) - .saturating_mul(count.into()); - - >::reserve_named( - &id, - &(sponsor.into()), - weight, - ) - } - - fn pay_for_call( - id: [u8; 16], - sponsor: ::AccountId, - call: ::Call, - ) -> Result { - let dispatch_info = call.get_dispatch_info(); - let weight: Balance = ChargeTransactionPayment::traditional_fee(0, &dispatch_info, 0); - Ok( - >::unreserve_named( - &id, - &(sponsor.into()), - weight, - ), - ) - } - - fn cancel_reserve( - id: [u8; 16], - sponsor: ::AccountId, - ) -> Result { - Ok( - >::unreserve_named( - &id, - &(sponsor.into()), - u128::MAX, - ), - ) + extrinsic.apply::(&dispatch_info, len) } } diff --git a/runtime/common/weights.rs b/runtime/common/weights.rs index 9d68268d21..274c320738 100644 --- a/runtime/common/weights.rs +++ b/runtime/common/weights.rs @@ -121,8 +121,12 @@ where max_weight_of!(token_owner()) } - fn repair_item() -> Weight { - max_weight_of!(repair_item()) + fn set_allowance_for_all() -> Weight { + max_weight_of!(set_allowance_for_all()) + } + + fn force_repair_item() -> Weight { + max_weight_of!(force_repair_item()) } } diff --git a/runtime/opal/Cargo.toml b/runtime/opal/Cargo.toml index 2df2883d26..1218d6cdf3 100644 --- a/runtime/opal/Cargo.toml +++ b/runtime/opal/Cargo.toml @@ -1,8 +1,6 @@ ################################################################################ # Package -cargo-features = ["workspace-inheritance"] - [package] authors = ['Unique Network '] build = 'build.rs' @@ -12,7 +10,7 @@ homepage = 'https://unique.network' license = 'GPLv3' name = 'opal-runtime' repository = 'https://github.com/UniqueNetwork/unique-chain' -version = "0.9.30" +version.workspace = true [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] @@ -41,14 +39,16 @@ runtime-benchmarks = [ 'pallet-unique/runtime-benchmarks', 'pallet-inflation/runtime-benchmarks', 'pallet-app-promotion/runtime-benchmarks', - 'pallet-unique-scheduler/runtime-benchmarks', + 'pallet-unique-scheduler-v2/runtime-benchmarks', 'pallet-xcm/runtime-benchmarks', 'sp-runtime/runtime-benchmarks', 'xcm-builder/runtime-benchmarks', 'pallet-maintenance/runtime-benchmarks', + 'cumulus-pallet-parachain-system/runtime-benchmarks' ] try-runtime = [ 'frame-try-runtime', + 'frame-try-runtime?/try-runtime', 'frame-executive/try-runtime', 'frame-support/try-runtime', 'frame-system/try-runtime', @@ -71,7 +71,6 @@ try-runtime = [ 'cumulus-pallet-dmp-queue/try-runtime', 'pallet-inflation/try-runtime', 'pallet-unique/try-runtime', - 'pallet-unique-scheduler/try-runtime', 'pallet-configuration/try-runtime', 'pallet-charge-transaction/try-runtime', 'pallet-common/try-runtime', @@ -83,13 +82,17 @@ try-runtime = [ 'pallet-proxy-rmrk-equip/try-runtime', 'pallet-app-promotion/try-runtime', 'pallet-foreign-assets/try-runtime', - 'pallet-evm/try-runtime', 'pallet-ethereum/try-runtime', + 'pallet-evm/try-runtime', 'pallet-evm-coder-substrate/try-runtime', 'pallet-evm-contract-helpers/try-runtime', 'pallet-evm-transaction-payment/try-runtime', 'pallet-evm-migration/try-runtime', + 'pallet-base-fee/try-runtime', + 'pallet-unique-scheduler-v2/try-runtime', 'pallet-maintenance/try-runtime', + 'pallet-test-utils?/try-runtime', + 'fp-self-contained/try-runtime', ] std = [ 'codec/std', @@ -125,6 +128,7 @@ std = [ 'pallet-base-fee/std', 'fp-rpc/std', 'up-rpc/std', + 'up-pov-estimate-rpc/std', 'app-promotion-rpc/std', 'fp-evm-mapping/std', 'fp-self-contained/std', @@ -141,7 +145,7 @@ std = [ 'pallet-proxy-rmrk-core/std', 'pallet-proxy-rmrk-equip/std', 'pallet-unique/std', - 'pallet-unique-scheduler/std', + 'pallet-unique-scheduler-v2/std', 'pallet-charge-transaction/std', 'up-data-structs/std', 'sp-api/std', @@ -171,10 +175,18 @@ std = [ "pallet-foreign-assets/std", 'pallet-maintenance/std', + 'pallet-test-utils?/std', ] limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing'] -opal-runtime = ['refungible', 'app-promotion', 'foreign-assets'] +opal-runtime = [ + 'refungible', + 'rmrk', + 'app-promotion', + 'foreign-assets', + 'pallet-test-utils', +] become-sapphire = [] +pov-estimate = [] refungible = [] scheduler = [] @@ -195,39 +207,39 @@ version = '3.1.2' default-features = false git = "https://github.com/paritytech/substrate" optional = true -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-try-runtime] default-features = false git = "https://github.com/paritytech/substrate" optional = true -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-executive] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-support] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-system] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-system-benchmarking] default-features = false git = "https://github.com/paritytech/substrate" optional = true -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-system-rpc-runtime-api] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.hex-literal] optional = true @@ -242,12 +254,12 @@ version = '1.0.130' [dependencies.pallet-aura] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-balances] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" # Contracts specific packages # [dependencies.pallet-contracts] @@ -271,97 +283,97 @@ branch = "polkadot-v0.9.30" [dependencies.pallet-randomness-collective-flip] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-sudo] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-timestamp] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-transaction-payment] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-transaction-payment-rpc-runtime-api] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-treasury] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-arithmetic] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-api] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-block-builder] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-core] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-consensus-aura] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-inherents] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-io] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-offchain] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-runtime] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-session] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-std] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-transaction-pool] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-version] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.smallvec] version = '1.6.1' @@ -372,46 +384,46 @@ version = '1.6.1' [dependencies.parachain-info] default-features = false git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.cumulus-pallet-aura-ext] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-pallet-parachain-system] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-primitives-core] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-pallet-xcm] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-pallet-dmp-queue] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-pallet-xcmp-queue] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-primitives-utility] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-primitives-timestamp] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false ################################################################################ @@ -419,27 +431,27 @@ default-features = false [dependencies.polkadot-parachain] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false [dependencies.xcm] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false [dependencies.xcm-builder] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false [dependencies.xcm-executor] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false [dependencies.pallet-xcm] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false ################################################################################ @@ -459,9 +471,11 @@ scale-info = { version = "2.0.1", default-features = false, features = [ derivative = "2.2.0" pallet-unique = { path = '../../pallets/unique', default-features = false } up-rpc = { path = "../../primitives/rpc", default-features = false } +up-pov-estimate-rpc = { path = "../../primitives/pov-estimate-rpc", default-features = false } app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false } rmrk-rpc = { path = "../../primitives/rmrk-rpc", default-features = false } -fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } pallet-inflation = { path = '../../pallets/inflation', default-features = false } pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false } up-data-structs = { path = '../../primitives/data-structs', default-features = false } @@ -473,21 +487,29 @@ pallet-refungible = { default-features = false, path = "../../pallets/refungible pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" } pallet-proxy-rmrk-core = { default-features = false, path = "../../pallets/proxy-rmrk-core", package = "pallet-rmrk-core" } pallet-proxy-rmrk-equip = { default-features = false, path = "../../pallets/proxy-rmrk-equip", package = "pallet-rmrk-equip" } -pallet-unique-scheduler = { path = '../../pallets/scheduler', default-features = false } -pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" } +pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.36", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" } +pallet-unique-scheduler-v2 = { path = '../../pallets/scheduler-v2', default-features = false } pallet-evm-migration = { path = '../../pallets/evm-migration', default-features = false } pallet-evm-contract-helpers = { path = '../../pallets/evm-contract-helpers', default-features = false } pallet-evm-transaction-payment = { path = '../../pallets/evm-transaction-payment', default-features = false } pallet-evm-coder-substrate = { default-features = false, path = "../../pallets/evm-coder-substrate" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +pallet-evm-precompile-simple = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } evm-coder = { default-features = false, path = '../../crates/evm-coder' } -up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.30' } +up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.36' } pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" } pallet-maintenance = { default-features = false, path = "../../pallets/maintenance" } +precompile-utils-macro = { path = "../common/ethereum/precompiles/utils/macro" } +num_enum = { version = "0.5.3", default-features = false } + +################################################################################ +# Test dependencies + +pallet-test-utils = { optional = true, default-features = false, path = "../../test-pallets/utils" } ################################################################################ # Other Dependencies @@ -505,4 +527,4 @@ version = "2.0.0" [build-dependencies.substrate-wasm-builder] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" diff --git a/runtime/opal/src/lib.rs b/runtime/opal/src/lib.rs index 4d35498c5f..3c5258a875 100644 --- a/runtime/opal/src/lib.rs +++ b/runtime/opal/src/lib.rs @@ -25,6 +25,8 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +extern crate alloc; + use frame_support::parameter_types; use sp_version::RuntimeVersion; @@ -57,10 +59,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!(RUNTIME_NAME), impl_name: create_runtime_str!(RUNTIME_NAME), authoring_version: 1, - spec_version: 930034, + spec_version: 336040, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 2, + transaction_version: 3, state_version: 0, }; diff --git a/runtime/quartz/Cargo.toml b/runtime/quartz/Cargo.toml index efdebbd0c6..c347912a76 100644 --- a/runtime/quartz/Cargo.toml +++ b/runtime/quartz/Cargo.toml @@ -1,8 +1,6 @@ ################################################################################ # Package -cargo-features = ["workspace-inheritance"] - [package] authors = ['Unique Network '] build = 'build.rs' @@ -12,7 +10,7 @@ homepage = 'https://unique.network' license = 'GPLv3' name = 'quartz-runtime' repository = 'https://github.com/UniqueNetwork/unique-chain' -version = '0.9.30' +version.workspace = true [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] @@ -45,6 +43,7 @@ runtime-benchmarks = [ 'sp-runtime/runtime-benchmarks', 'xcm-builder/runtime-benchmarks', 'pallet-maintenance/runtime-benchmarks', + 'cumulus-pallet-parachain-system/runtime-benchmarks', ] try-runtime = [ 'frame-try-runtime', @@ -70,7 +69,6 @@ try-runtime = [ 'cumulus-pallet-dmp-queue/try-runtime', 'pallet-inflation/try-runtime', 'pallet-unique/try-runtime', - 'pallet-unique-scheduler/try-runtime', 'pallet-configuration/try-runtime', 'pallet-charge-transaction/try-runtime', 'pallet-common/try-runtime', @@ -82,13 +80,14 @@ try-runtime = [ 'pallet-proxy-rmrk-equip/try-runtime', 'pallet-app-promotion/try-runtime', 'pallet-foreign-assets/try-runtime', - 'pallet-evm/try-runtime', 'pallet-ethereum/try-runtime', + 'pallet-evm/try-runtime', 'pallet-evm-coder-substrate/try-runtime', 'pallet-evm-contract-helpers/try-runtime', 'pallet-evm-transaction-payment/try-runtime', 'pallet-evm-migration/try-runtime', 'pallet-maintenance/try-runtime', + 'fp-self-contained/try-runtime', ] std = [ 'codec/std', @@ -124,6 +123,7 @@ std = [ 'pallet-base-fee/std', 'fp-rpc/std', 'up-rpc/std', + 'up-pov-estimate-rpc/std', 'app-promotion-rpc/std', 'fp-evm-mapping/std', 'fp-self-contained/std', @@ -140,7 +140,6 @@ std = [ 'pallet-proxy-rmrk-core/std', 'pallet-proxy-rmrk-equip/std', 'pallet-unique/std', - 'pallet-unique-scheduler/std', 'pallet-charge-transaction/std', 'up-data-structs/std', 'sp-api/std', @@ -172,6 +171,7 @@ std = [ ] limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing'] quartz-runtime = ['refungible', 'app-promotion', 'foreign-assets'] +pov-estimate = [] refungible = [] scheduler = [] @@ -192,39 +192,39 @@ version = '3.1.2' default-features = false git = "https://github.com/paritytech/substrate" optional = true -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-try-runtime] default-features = false git = "https://github.com/paritytech/substrate" optional = true -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-executive] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-support] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-system] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-system-benchmarking] default-features = false git = "https://github.com/paritytech/substrate" optional = true -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-system-rpc-runtime-api] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.hex-literal] optional = true @@ -239,12 +239,12 @@ version = '1.0.130' [dependencies.pallet-aura] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-balances] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" # Contracts specific packages # [dependencies.pallet-contracts] @@ -268,97 +268,97 @@ branch = "polkadot-v0.9.30" [dependencies.pallet-randomness-collective-flip] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-sudo] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-timestamp] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-transaction-payment] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-transaction-payment-rpc-runtime-api] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-treasury] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-arithmetic] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-api] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-block-builder] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-core] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-consensus-aura] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-inherents] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-io] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-offchain] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-runtime] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-session] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-std] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-transaction-pool] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-version] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.smallvec] version = '1.6.1' @@ -369,46 +369,46 @@ version = '1.6.1' [dependencies.parachain-info] default-features = false git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.cumulus-pallet-aura-ext] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-pallet-parachain-system] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-primitives-core] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-pallet-xcm] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-pallet-dmp-queue] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-pallet-xcmp-queue] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-primitives-utility] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-primitives-timestamp] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false ################################################################################ @@ -416,27 +416,27 @@ default-features = false [dependencies.polkadot-parachain] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false [dependencies.xcm] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false [dependencies.xcm-builder] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false [dependencies.xcm-executor] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false [dependencies.pallet-xcm] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false ################################################################################ @@ -464,8 +464,10 @@ scale-info = { version = "2.0.1", default-features = false, features = [ derivative = "2.2.0" pallet-unique = { path = '../../pallets/unique', default-features = false } up-rpc = { path = "../../primitives/rpc", default-features = false } +up-pov-estimate-rpc = { path = "../../primitives/pov-estimate-rpc", default-features = false } app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false } -fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } pallet-inflation = { path = '../../pallets/inflation', default-features = false } pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false } up-data-structs = { path = '../../primitives/data-structs', default-features = false } @@ -477,22 +479,24 @@ pallet-refungible = { default-features = false, path = "../../pallets/refungible pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" } pallet-proxy-rmrk-core = { default-features = false, path = "../../pallets/proxy-rmrk-core", package = "pallet-rmrk-core" } pallet-proxy-rmrk-equip = { default-features = false, path = "../../pallets/proxy-rmrk-equip", package = "pallet-rmrk-equip" } -pallet-unique-scheduler = { path = '../../pallets/scheduler', default-features = false } # pallet-contract-helpers = { path = '../pallets/contract-helpers', default-features = false, version = '0.1.0' } -pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" } +pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.36", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" } pallet-evm-migration = { path = '../../pallets/evm-migration', default-features = false } pallet-evm-contract-helpers = { path = '../../pallets/evm-contract-helpers', default-features = false } pallet-evm-transaction-payment = { path = '../../pallets/evm-transaction-payment', default-features = false } pallet-evm-coder-substrate = { default-features = false, path = "../../pallets/evm-coder-substrate" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +pallet-evm-precompile-simple = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } evm-coder = { default-features = false, path = '../../crates/evm-coder' } -up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.30' } +up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.36' } pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" } pallet-maintenance = { default-features = false, path = "../../pallets/maintenance" } +precompile-utils-macro = { path = "../common/ethereum/precompiles/utils/macro" } +num_enum = { version = "0.5.3", default-features = false } ################################################################################ # Other Dependencies @@ -510,4 +514,4 @@ version = "2.0.0" [build-dependencies.substrate-wasm-builder] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" diff --git a/runtime/quartz/src/lib.rs b/runtime/quartz/src/lib.rs index 172aa0a142..9c73075863 100644 --- a/runtime/quartz/src/lib.rs +++ b/runtime/quartz/src/lib.rs @@ -25,6 +25,8 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +extern crate alloc; + use frame_support::parameter_types; use sp_version::RuntimeVersion; @@ -50,10 +52,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!(RUNTIME_NAME), impl_name: create_runtime_str!(RUNTIME_NAME), authoring_version: 1, - spec_version: 930034, + spec_version: 336040, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 2, + transaction_version: 3, state_version: 0, }; diff --git a/runtime/tests/Cargo.toml b/runtime/tests/Cargo.toml index 3497f9b392..b0e35c466d 100644 --- a/runtime/tests/Cargo.toml +++ b/runtime/tests/Cargo.toml @@ -11,22 +11,22 @@ refungible = [] [dependencies] up-data-structs = { default-features = false, path = '../../primitives/data-structs' } -sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } -fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } -frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } -pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } -pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } pallet-common = { path = '../../pallets/common' } pallet-structure = { path = '../../pallets/structure' } @@ -43,4 +43,4 @@ parity-scale-codec = { version = "3.1.2", default-features = false, features = [ scale-info = "*" evm-coder = { default-features = false, path = '../../crates/evm-coder' } -up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30" } +up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.36" } diff --git a/runtime/tests/src/lib.rs b/runtime/tests/src/lib.rs index 5c673517bf..7960ac5217 100644 --- a/runtime/tests/src/lib.rs +++ b/runtime/tests/src/lib.rs @@ -21,6 +21,7 @@ use frame_support::{ parameter_types, traits::{Everything, ConstU32, ConstU64}, weights::IdentityFee, + pallet_prelude::Weight, }; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, @@ -61,7 +62,7 @@ frame_support::construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system, - Unique: pallet_unique::{Pallet, Call, Storage, Event}, + Unique: pallet_unique::{Pallet, Call, Storage}, Balances: pallet_balances::{Pallet, Call, Storage, Event}, Common: pallet_common::{Pallet, Storage, Event}, Fungible: pallet_fungible::{Pallet, Storage}, @@ -202,6 +203,7 @@ impl Default for TestCrossAccountId { parameter_types! { pub BlockGasLimit: U256 = 0u32.into(); + pub WeightPerGas: Weight = Weight::from_ref_time(20); } impl pallet_ethereum::Config for Test { @@ -210,11 +212,15 @@ impl pallet_ethereum::Config for Test { } impl pallet_evm::Config for Test { + type CrossAccountId = TestCrossAccountId; + type EvmAddressMapping = TestEvmAddressMapping; + type EvmBackwardsAddressMapping = TestEvmBackwardsAddressMapping; type RuntimeEvent = RuntimeEvent; type FeeCalculator = (); - type GasWeightMapping = (); - type CallOrigin = EnsureAddressNever; - type WithdrawOrigin = EnsureAddressNever; + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type CallOrigin = EnsureAddressNever; + type WithdrawOrigin = EnsureAddressNever; type AddressMapping = TestEvmAddressMapping; type Currency = Balances; type PrecompilesType = (); @@ -244,12 +250,6 @@ impl pallet_common::Config for Test { type ContractAddress = EvmCollectionHelpersAddress; } -impl pallet_evm::account::Config for Test { - type CrossAccountId = TestCrossAccountId; - type EvmAddressMapping = TestEvmAddressMapping; - type EvmBackwardsAddressMapping = TestEvmBackwardsAddressMapping; -} - impl pallet_structure::Config for Test { type WeightInfo = (); type RuntimeEvent = RuntimeEvent; @@ -273,7 +273,6 @@ parameter_types! { } impl pallet_unique::Config for Test { - type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type CommonWeightInfo = CommonWeights; type RefungibleExtensionsWeightInfo = CommonWeights; diff --git a/runtime/tests/src/tests.rs b/runtime/tests/src/tests.rs index c064a7d2f6..00de740675 100644 --- a/runtime/tests/src/tests.rs +++ b/runtime/tests/src/tests.rs @@ -294,7 +294,6 @@ fn create_refungible_item() { let data = default_re_fungible_data(); create_test_item(collection_id, &data.clone().into()); - let item = >::get((collection_id, TokenId(1))); let balance = >::get((collection_id, TokenId(1), account(1))); assert_eq!(balance, 1023); @@ -325,12 +324,11 @@ fn create_multiple_refungible_items() { .collect() )); for (index, data) in items_data.into_iter().enumerate() { - let item = >::get(( + let balance = >::get(( CollectionId(1), TokenId((index + 1) as u32), + account(1), )); - let balance = - >::get((CollectionId(1), TokenId(1), account(1))); assert_eq!(balance, 1023); } }); @@ -442,7 +440,6 @@ fn transfer_refungible_item() { // Create RFT 1 in 1023 pieces for account 1 let data = default_re_fungible_data(); create_test_item(collection_id, &data.clone().into()); - let item = >::get((collection_id, TokenId(1))); assert_eq!( >::get((collection_id, account(1))), 1 diff --git a/runtime/unique/Cargo.toml b/runtime/unique/Cargo.toml index 36a3e7f831..cf883c8265 100644 --- a/runtime/unique/Cargo.toml +++ b/runtime/unique/Cargo.toml @@ -1,8 +1,6 @@ ################################################################################ # Package -cargo-features = ["workspace-inheritance"] - [package] authors = ['Unique Network '] build = 'build.rs' @@ -12,7 +10,7 @@ homepage = 'https://unique.network' license = 'GPLv3' name = 'unique-runtime' repository = 'https://github.com/UniqueNetwork/unique-chain' -version = '0.9.30' +version.workspace = true [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] @@ -71,7 +69,6 @@ try-runtime = [ 'cumulus-pallet-dmp-queue/try-runtime', 'pallet-inflation/try-runtime', 'pallet-unique/try-runtime', - 'pallet-unique-scheduler/try-runtime', 'pallet-configuration/try-runtime', 'pallet-charge-transaction/try-runtime', 'pallet-common/try-runtime', @@ -83,13 +80,14 @@ try-runtime = [ 'pallet-proxy-rmrk-equip/try-runtime', 'pallet-app-promotion/try-runtime', 'pallet-foreign-assets/try-runtime', - 'pallet-evm/try-runtime', 'pallet-ethereum/try-runtime', + 'pallet-evm/try-runtime', 'pallet-evm-coder-substrate/try-runtime', 'pallet-evm-contract-helpers/try-runtime', 'pallet-evm-transaction-payment/try-runtime', 'pallet-evm-migration/try-runtime', 'pallet-maintenance/try-runtime', + 'fp-self-contained/try-runtime', ] std = [ 'codec/std', @@ -125,6 +123,7 @@ std = [ 'pallet-base-fee/std', 'fp-rpc/std', 'up-rpc/std', + 'up-pov-estimate-rpc/std', 'app-promotion-rpc/std', 'fp-evm-mapping/std', 'fp-self-contained/std', @@ -141,7 +140,6 @@ std = [ 'pallet-proxy-rmrk-core/std', 'pallet-proxy-rmrk-equip/std', 'pallet-unique/std', - 'pallet-unique-scheduler/std', 'pallet-charge-transaction/std', 'up-data-structs/std', 'sp-api/std', @@ -173,6 +171,8 @@ std = [ ] limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing'] unique-runtime = ['foreign-assets'] +pov-estimate = [] +stubgen = ["evm-coder/stubgen"] refungible = [] scheduler = [] @@ -192,39 +192,39 @@ version = '3.1.2' default-features = false git = "https://github.com/paritytech/substrate" optional = true -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-try-runtime] default-features = false git = "https://github.com/paritytech/substrate" optional = true -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-executive] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-support] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-system] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-system-benchmarking] default-features = false git = "https://github.com/paritytech/substrate" optional = true -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.frame-system-rpc-runtime-api] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.hex-literal] optional = true @@ -239,12 +239,12 @@ version = '1.0.130' [dependencies.pallet-aura] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-balances] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" # Contracts specific packages # [dependencies.pallet-contracts] @@ -268,97 +268,97 @@ branch = "polkadot-v0.9.30" [dependencies.pallet-randomness-collective-flip] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-sudo] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-timestamp] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-transaction-payment] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-transaction-payment-rpc-runtime-api] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.pallet-treasury] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-arithmetic] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-api] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-block-builder] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-core] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-consensus-aura] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-inherents] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-io] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-offchain] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-runtime] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-session] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-std] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-transaction-pool] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.sp-version] default-features = false git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.smallvec] version = '1.6.1' @@ -369,46 +369,46 @@ version = '1.6.1' [dependencies.parachain-info] default-features = false git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" [dependencies.cumulus-pallet-aura-ext] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-pallet-parachain-system] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-primitives-core] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-pallet-xcm] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-pallet-dmp-queue] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-pallet-xcmp-queue] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-primitives-utility] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false [dependencies.cumulus-primitives-timestamp] git = "https://github.com/paritytech/cumulus" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" default-features = false ################################################################################ @@ -416,27 +416,27 @@ default-features = false [dependencies.polkadot-parachain] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false [dependencies.xcm] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false [dependencies.xcm-builder] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false [dependencies.xcm-executor] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false [dependencies.pallet-xcm] git = "https://github.com/paritytech/polkadot" -branch = "release-v0.9.30" +branch = "release-v0.9.36" default-features = false ################################################################################ @@ -456,6 +456,7 @@ scale-info = { version = "2.0.1", default-features = false, features = [ derivative = "2.2.0" pallet-unique = { path = '../../pallets/unique', default-features = false } up-rpc = { path = "../../primitives/rpc", default-features = false } +up-pov-estimate-rpc = { path = "../../primitives/pov-estimate-rpc", default-features = false } app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false } rmrk-rpc = { path = "../../primitives/rmrk-rpc", default-features = false } pallet-inflation = { path = '../../pallets/inflation', default-features = false } @@ -469,23 +470,26 @@ pallet-refungible = { default-features = false, path = "../../pallets/refungible pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" } pallet-proxy-rmrk-core = { default-features = false, path = "../../pallets/proxy-rmrk-core", package = "pallet-rmrk-core" } pallet-proxy-rmrk-equip = { default-features = false, path = "../../pallets/proxy-rmrk-equip", package = "pallet-rmrk-equip" } -pallet-unique-scheduler = { path = '../../pallets/scheduler', default-features = false } # pallet-contract-helpers = { path = '../pallets/contract-helpers', default-features = false, version = '0.1.0' } -pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" } +pallet-charge-transaction = { git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.36", package = "pallet-template-transaction-payment", default-features = false, version = "3.0.0" } pallet-evm-migration = { path = '../../pallets/evm-migration', default-features = false } pallet-evm-contract-helpers = { path = '../../pallets/evm-contract-helpers', default-features = false } pallet-evm-transaction-payment = { path = '../../pallets/evm-transaction-payment', default-features = false } pallet-evm-coder-substrate = { default-features = false, path = "../../pallets/evm-coder-substrate" } -pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } -fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" } +pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } +pallet-evm-precompile-simple = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" } evm-coder = { default-features = false, path = '../../crates/evm-coder' } -up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.30' } +up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.36' } pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" } pallet-maintenance = { default-features = false, path = "../../pallets/maintenance" } +precompile-utils-macro = { path = "../common/ethereum/precompiles/utils/macro" } +num_enum = { version = "0.5.3", default-features = false } ################################################################################ # Other Dependencies @@ -503,4 +507,4 @@ version = "2.0.0" [build-dependencies.substrate-wasm-builder] git = "https://github.com/paritytech/substrate" -branch = "polkadot-v0.9.30" +branch = "polkadot-v0.9.36" diff --git a/runtime/unique/src/lib.rs b/runtime/unique/src/lib.rs index 2a64fe02af..805519d050 100644 --- a/runtime/unique/src/lib.rs +++ b/runtime/unique/src/lib.rs @@ -25,6 +25,8 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +extern crate alloc; + use frame_support::parameter_types; use sp_version::RuntimeVersion; @@ -50,10 +52,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!(RUNTIME_NAME), impl_name: create_runtime_str!(RUNTIME_NAME), authoring_version: 1, - spec_version: 930034, + spec_version: 336040, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 2, + transaction_version: 3, state_version: 0, }; diff --git a/test-pallets/utils/Cargo.toml b/test-pallets/utils/Cargo.toml new file mode 100644 index 0000000000..53c46ca6db --- /dev/null +++ b/test-pallets/utils/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "pallet-test-utils" +version = "0.1.0" +license = "GPLv3" +edition = "2021" +publish = false + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.1.1", default-features = false, features = [ + "derive", +] } +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } +# pallet-unique-scheduler = { path = '../../pallets/scheduler', default-features = false } +pallet-unique-scheduler-v2 = { path = '../../pallets/scheduler-v2', default-features = false } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.36" } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", + "pallet-unique-scheduler-v2/std", + "sp-std/std", +] +try-runtime = [ + "frame-support/try-runtime", + "pallet-unique-scheduler-v2/try-runtime", +] diff --git a/test-pallets/utils/src/lib.rs b/test-pallets/utils/src/lib.rs new file mode 100644 index 0000000000..df207f2242 --- /dev/null +++ b/test-pallets/utils/src/lib.rs @@ -0,0 +1,177 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::{ + pallet_prelude::*, + dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo}, + traits::{UnfilteredDispatchable, IsSubType, OriginTrait}, + }; + use frame_system::pallet_prelude::*; + use sp_std::vec::Vec; + // use pallet_unique_scheduler_v2::{TaskName, Pallet as SchedulerPallet}; + + #[pallet::config] + pub trait Config: frame_system::Config /*+ pallet_unique_scheduler_v2::Config*/ { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The overarching call type. + type RuntimeCall: Parameter + + Dispatchable< + RuntimeOrigin = ::RuntimeOrigin, + PostInfo = PostDispatchInfo, + > + GetDispatchInfo + + From> + + UnfilteredDispatchable::RuntimeOrigin> + + IsSubType> + + IsType<::RuntimeCall>; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + ValueIsSet, + ShouldRollback, + BatchCompleted, + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + #[pallet::storage] + #[pallet::getter(fn is_enabled)] + pub type Enabled = StorageValue<_, bool, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn test_value)] + pub type TestValue = StorageValue<_, u32, ValueQuery>; + + #[pallet::error] + pub enum Error { + TestPalletDisabled, + TriggerRollback, + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(10_000)] + pub fn enable(origin: OriginFor) -> DispatchResult { + ensure_root(origin)?; + >::set(true); + + Ok(()) + } + + #[pallet::call_index(1)] + #[pallet::weight(10_000)] + pub fn set_test_value(origin: OriginFor, value: u32) -> DispatchResult { + Self::ensure_origin_and_enabled(origin)?; + + >::put(value); + + Self::deposit_event(Event::ValueIsSet); + + Ok(()) + } + + #[pallet::call_index(2)] + #[pallet::weight(10_000)] + pub fn set_test_value_and_rollback(origin: OriginFor, value: u32) -> DispatchResult { + Self::set_test_value(origin, value)?; + + Self::deposit_event(Event::ShouldRollback); + + Err(>::TriggerRollback.into()) + } + + #[pallet::call_index(3)] + #[pallet::weight(10_000)] + pub fn inc_test_value(origin: OriginFor) -> DispatchResult { + Self::set_test_value(origin, >::get() + 1) + } + + // #[pallet::weight(10_000)] + // pub fn self_canceling_inc( + // origin: OriginFor, + // id: TaskName, + // max_test_value: u32, + // ) -> DispatchResult { + // Self::ensure_origin_and_enabled(origin.clone())?; + // Self::inc_test_value(origin.clone())?; + + // if >::get() == max_test_value { + // SchedulerPallet::::cancel_named(origin, id)?; + // } + + // Ok(()) + // } + + #[pallet::call_index(4)] + #[pallet::weight(100_000_000)] + pub fn just_take_fee(origin: OriginFor) -> DispatchResult { + Self::ensure_origin_and_enabled(origin)?; + Ok(()) + } + + #[pallet::call_index(5)] + #[pallet::weight(10_000)] + pub fn batch_all( + origin: OriginFor, + calls: Vec<::RuntimeCall>, + ) -> DispatchResultWithPostInfo { + Self::ensure_origin_and_enabled(origin.clone())?; + + let is_root = ensure_root(origin.clone()).is_ok(); + + for call in calls { + if is_root { + call.dispatch_bypass_filter(origin.clone())?; + } else { + let mut filtered_origin = origin.clone(); + // Don't allow users to nest `batch_all` calls. + filtered_origin.add_filter( + move |c: &::RuntimeCall| { + let c = ::RuntimeCall::from_ref(c); + !matches!(c.is_sub_type(), Some(Call::batch_all { .. })) + }, + ); + call.dispatch(filtered_origin)?; + } + } + + Self::deposit_event(Event::BatchCompleted); + Ok(None::.into()) + } + } +} + +impl Pallet { + fn ensure_origin_and_enabled(origin: OriginFor) -> DispatchResult { + ensure_signed(origin)?; + >::get() + .then(|| ()) + .ok_or(>::TestPalletDisabled.into()) + } +} diff --git a/tests/.eslintrc.json b/tests/.eslintrc.json index eb6fabc601..319023d056 100644 --- a/tests/.eslintrc.json +++ b/tests/.eslintrc.json @@ -10,13 +10,17 @@ "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": 11, - "sourceType": "module" + "sourceType": "module", + "project": "**/tsconfig.json" }, "plugins": [ "@typescript-eslint", "mocha" ], "rules": { + "@typescript-eslint/no-floating-promises": [ + "error" + ], "indent": [ "error", 2, @@ -24,6 +28,7 @@ "SwitchCase": 1 } ], + "no-trailing-spaces": "warn", "function-call-argument-newline": [ "error", "consistent" diff --git a/tests/.gitignore b/tests/.gitignore index 2ccbe4656c..f7da561348 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1 +1,2 @@ /node_modules/ +properties.csv diff --git a/tests/.vscode/settings.json b/tests/.vscode/settings.json index ae497b34ae..b05c111ade 100644 --- a/tests/.vscode/settings.json +++ b/tests/.vscode/settings.json @@ -1,5 +1,12 @@ { - "mocha.enabled": true, - "mochaExplorer.files": "**/*.test.ts", - "mochaExplorer.require": "ts-node/register" + "mocha.enabled": true, + "mochaExplorer.files": "**/*.test.ts", + "mochaExplorer.require": "ts-node/register", + "eslint.format.enable": true, + "[javascript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "[typescript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + } } diff --git a/tests/package.json b/tests/package.json index 0aab2072cb..c0d7498172 100644 --- a/tests/package.json +++ b/tests/package.json @@ -4,15 +4,17 @@ "description": "Unique Chain Tests", "main": "", "devDependencies": { - "@polkadot/typegen": "9.5.2", + "@polkadot/typegen": "9.10.2", "@types/chai": "^4.3.3", "@types/chai-as-promised": "^7.1.5", "@types/chai-like": "^1.1.1", + "@types/chai-subset": "^1.3.3", "@types/mocha": "^10.0.0", "@types/node": "^18.11.2", - "@typescript-eslint/eslint-plugin": "^5.40.1", - "@typescript-eslint/parser": "^5.40.1", + "@typescript-eslint/eslint-plugin": "^5.47.0", + "@typescript-eslint/parser": "^5.47.0", "chai": "^4.3.6", + "chai-subset": "^1.6.0", "eslint": "^8.25.0", "eslint-plugin-mocha": "^10.1.0", "mocha": "^10.1.0", @@ -44,7 +46,9 @@ "testEvmCoder": "mocha --timeout 9999999 -r ts-node/register './**/eth/evmCoder.test.ts'", "testNesting": "mocha --timeout 9999999 -r ts-node/register ./**/nest.test.ts", "testUnnesting": "mocha --timeout 9999999 -r ts-node/register ./**/unnest.test.ts", - "testProperties": "mocha --timeout 9999999 -r ts-node/register ./**/collectionProperties.test.ts ./**/tokenProperties.test.ts ./**/getPropertiesRpc.test.ts", + "testProperties": "mocha --timeout 9999999 -r ts-node/register ./**/collectionProperties.*test.ts ./**/tokenProperties.*test.ts ./**/getPropertiesRpc.test.ts", + "testCollectionProperties": "mocha --timeout 9999999 -r ts-node/register ./**/collectionProperties.*test.ts", + "testTokenProperties": "mocha --timeout 9999999 -r ts-node/register ./**/tokenProperties.*test.ts", "testMigration": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/migration-check.test.ts", "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts", "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts", @@ -100,6 +104,8 @@ "testXcmTransferAcala": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferAcala.test.ts acalaId=2000 uniqueId=5000", "testXcmTransferStatemine": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferStatemine.test.ts statemineId=1000 uniqueId=5000", "testXcmTransferMoonbeam": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferMoonbeam.test.ts", + "benchMintingFee": "ts-node src/benchmarks/mintFee/benchmark.ts", + "testApiConsts": "mocha --timeout 9999999 -r ts-node/register ./**/apiConsts.test.ts", "load": "mocha --timeout 9999999 -r ts-node/register './**/*.load.ts'", "loadTransfer": "ts-node src/transfer.nload.ts", "polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json", @@ -111,12 +117,17 @@ "license": "SEE LICENSE IN ../LICENSE", "homepage": "", "dependencies": { - "@polkadot/api": "9.5.2", - "@polkadot/util-crypto": "10.1.11", + "@polkadot/api": "9.10.2", + "@polkadot/util": "10.2.1", + "@polkadot/util-crypto": "10.2.1", "chai-as-promised": "^7.1.1", "chai-like": "^1.1.1", + "csv-writer": "^1.6.0", "find-process": "^1.4.7", "solc": "0.8.17", - "web3": "^1.8.0" + "web3": "^1.8.1" + }, + "resolutions": { + "decode-uri-component": "^0.2.1" } } diff --git a/tests/scripts/functions.sh b/tests/scripts/functions.sh new file mode 100755 index 0000000000..6407433812 --- /dev/null +++ b/tests/scripts/functions.sh @@ -0,0 +1,4 @@ + +function do_rpc { + curl -s --header "Content-Type: application/json" -XPOST --data "{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"$1\",\"params\":[$2]}" $RPC_URL +} diff --git a/tests/scripts/generate_types_package.sh b/tests/scripts/generate_types_package.sh new file mode 100755 index 0000000000..3862f30847 --- /dev/null +++ b/tests/scripts/generate_types_package.sh @@ -0,0 +1,205 @@ +#!/usr/bin/env bash + +set -eu + +DIR=$(realpath $(dirname "$0")) +TEMPLATE=$DIR/types_template +GIT_REPO=git@github.com:UniqueNetwork/unique-types-js.git + +. $DIR/functions.sh + +usage() { + echo "Usage: [RPC_URL=http://localhost:9933] $0 <--rc|--release> [--force] [--push] [--rpc-url=http://localhost:9933]" 1>&2 + exit 1 +} + +rc= +release= +force= +push= + +for i in "$@"; do +case $i in + --rc) + rc=1 + if test "$release"; then usage; fi + ;; + --release) + release=1 + if test "$rc"; then usage; fi + ;; + --force) + force=1 + ;; + --push) + push=1 + ;; + --rpc-url=*) + RPC_URL=${i#*=} + ;; + *) + usage + ;; +esac +done + +if test \( ! \( "$rc" -o "$release" \) \) -o \( "${RPC_URL=}" = "" \); then + usage +elif test "$rc"; then + echo "Rc build" +else + echo "Release build" +fi + +cd $DIR/.. +yarn polkadot-types + +version=$(do_rpc state_getRuntimeVersion "") +spec_version=$(echo $version | jq -r .result.specVersion) +spec_name=$(echo $version | jq -r .result.specName) +echo "Spec version: $spec_version, name: $spec_name" + +case $spec_name in + opal) + package_name=@unique-nft/opal-testnet-types + repo_branch=opal-testnet + repo_tag=$repo_branch + ;; + sapphire) + package_name=@unique-nft/sapphire-mainnet-types + repo_branch=sapphire-mainnet + repo_tag=$repo_branch + ;; + quartz) + package_name=@unique-nft/quartz-mainnet-types + repo_branch=quartz-mainnet + repo_tag=$repo_branch + ;; + unique) + package_name=@unique-nft/unique-mainnet-types + repo_branch=master + repo_tag=unique-mainnet + ;; + *) + echo "unknown spec name: $spec_name" + exit 1 + ;; +esac + +if test "$rc" = 1; then + if "$spec_name" != opal; then + echo "rc types can only be based on opal spec" + exit 1 + fi + package_name=@unique-nft/rc-types + repo_branch=rc + repo_tag=$repo_branch +fi + +package_version=${spec_version:0:3}.$(echo ${spec_version:3:3} | sed 's/^0*//'). +last_patch=NEVER +for tag in $(git ls-remote -t --refs $GIT_REPO | cut -f 2 | sort -r); do + tag_prefix=refs/tags/$repo_tag-v$package_version + if [[ $tag == $tag_prefix* ]]; then + last_patch=${tag#$tag_prefix} + break; + fi +done +echo "Package version: ${package_version}X, name: $package_name" +echo "Last published: $package_version$last_patch" + +if test "$last_patch" = "NEVER"; then + new_package_version=${package_version}0 +else + new_package_version=${package_version}$((last_patch+1)) +fi +package_version=${package_version}$last_patch +echo "New package version: $new_package_version" + +pjsapi_ver=^$(cat $DIR/../package.json | jq -r '.dependencies."@polkadot/api"' | sed -e "s/^\^//") +tsnode_ver=^$(cat $DIR/../package.json | jq -r '.devDependencies."ts-node"' | sed -e "s/^\^//") +ts_ver=^$(cat $DIR/../package.json | jq -r '.devDependencies."typescript"' | sed -e "s/^\^//") + +gen=$(mktemp -d) +pushd $gen +git clone $GIT_REPO -b $repo_branch --depth 1 . +if test "$last_patch" != "NEVER"; then + git reset --hard $repo_tag-v$package_version +fi +git rm -r "*" +popd + +# Using old package_version here, becaue we first check if +# there is any difference between generated and already uplaoded types +cat $TEMPLATE/package.json \ +| jq '.private = false' - \ +| jq '.name = "'$package_name'"' - \ +| jq '.version = "'$package_version'"' - \ +| jq '.peerDependencies."@polkadot/api" = "'$pjsapi_ver'"' - \ +| jq '.peerDependencies."@polkadot/types" = "'$pjsapi_ver'"' - \ +| jq '.devDependencies."@polkadot/api" = "'$pjsapi_ver'"' - \ +| jq '.devDependencies."@polkadot/types" = "'$pjsapi_ver'"' - \ +| jq '.devDependencies."ts-node" = "'$tsnode_ver'"' - \ +| jq '.devDependencies."typescript" = "'$ts_ver'"' - \ +> $gen/package.json +for file in .gitignore .npmignore README.md tsconfig.json; do + cp $TEMPLATE/$file $gen/ +done +package_name_replacement=$(printf '%s\n' "$package_name" | sed -e 's/[\/&]/\\&/g') +sed -i 's/PKGNAME/'$package_name_replacement'/' $gen/README.md + +rsync -ar --exclude .gitignore src/interfaces/ $gen +for file in $gen/augment-* $gen/**/types.ts $gen/registry.ts; do + sed -i '1s;^;//@ts-nocheck\n;' $file +done + +pushd $gen +git add . +popd + +pushd $gen +if git diff --quiet HEAD && test ! "$force"; then + echo "no changes detected" + exit 0 +fi +popd + +mv $gen/package.json $gen/package.old.json +cat $gen/package.old.json \ +| jq '.version = "'$new_package_version'"' - \ +> $gen/package.json +rm $gen/package.old.json +pushd $gen +git add package.json +popd + +echo "package.json contents:" +cat $gen/package.json +echo "overall diff:" +pushd $gen +git status +git diff HEAD || true +popd + +# This check is only active if running in interactive terminal +if [ -t 0 ]; then + read -p "Is everything ok at $gen [y/n]? " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Aborting!" + exit 1 + fi +fi + +pushd $gen +yarn +yarn prepublish +git commit -m "chore: upgrade types to v$new_package_version" +git tag --force $repo_tag-v$new_package_version +if test "$push" = 1; then + git push --tags --force -u origin HEAD +else + echo "--push not given, origin repo left intact" + echo "To publish manually, go to $gen, and run \"git push --tags --force -u origin HEAD\"" +fi +popd diff --git a/tests/scripts/types_template/.gitignore b/tests/scripts/types_template/.gitignore new file mode 100644 index 0000000000..f289057b13 --- /dev/null +++ b/tests/scripts/types_template/.gitignore @@ -0,0 +1,5 @@ +*.js +*.map +*.d.ts +/node_modules +metadata.json diff --git a/tests/scripts/types_template/.npmignore b/tests/scripts/types_template/.npmignore new file mode 100644 index 0000000000..a57582cc39 --- /dev/null +++ b/tests/scripts/types_template/.npmignore @@ -0,0 +1 @@ +/src diff --git a/tests/scripts/types_template/README.md b/tests/scripts/types_template/README.md new file mode 100644 index 0000000000..0f5fe7ebb9 --- /dev/null +++ b/tests/scripts/types_template/README.md @@ -0,0 +1,31 @@ +# PKGNAME + +Unique network api types + +Do not edit by hand, those types are generated automatically, and definitions are located in chain repo + +## Using types + +Install library: + +```bash +yarn add --dev PKGNAME +``` + +Replace polkadot.js types with our chain types adding corresponding path override to the tsconfig `compilerOptions.paths` section: + +```json +// in tsconfig.json +{ + "compilerOptions": { + "paths": { + "@polkadot/types/lookup": ["node_modules/PKGNAME/types-lookup"] + } + } +} +``` + +Since polkadot v7 api augmentations not loaded by default, in every file, where you need to access `api.tx`, `api.query`, `api.rpc`, etc; you should explicitly import corresponding augmentation before any other `polkadot.js` related import: +``` +import 'PKGNAME/augment-api'; +``` diff --git a/tests/scripts/types_template/package.json b/tests/scripts/types_template/package.json new file mode 100644 index 0000000000..d1e9c36257 --- /dev/null +++ b/tests/scripts/types_template/package.json @@ -0,0 +1,22 @@ +{ + "name": "TODO", + "private": true, + "version": "TODO", + "main": "index.js", + "repository": "git@github.com:UniqueNetwork/unique-types-js.git", + "homepage": "https://unique.network/", + "license": "MIT", + "scripts": { + "prepublish": "tsc -d" + }, + "peerDependencies": { + "@polkadot/api": "TODO", + "@polkadot/types": "TODO" + }, + "devDependencies": { + "@polkadot/api": "TODO", + "@polkadot/types": "TODO", + "ts-node": "TODO", + "typescript": "TODO" + } +} diff --git a/tests/scripts/types_template/tsconfig.json b/tests/scripts/types_template/tsconfig.json new file mode 100644 index 0000000000..baa7166cd0 --- /dev/null +++ b/tests/scripts/types_template/tsconfig.json @@ -0,0 +1,28 @@ +{ + "exclude": [ + "node_modules", + "node_modules/**/*", + "../node_modules/**/*", + "**/node_modules/**/*" + ], + "compilerOptions": { + "target": "ES2020", + "moduleResolution": "node", + "esModuleInterop": true, + "resolveJsonModule": true, + "module": "commonjs", + "sourceMap": true, + "outDir": ".", + "rootDir": ".", + "strict": true, + "paths": { + }, + "skipLibCheck": true, + }, + "include": [ + "**/*", + ], + "lib": [ + "es2017" + ], +} diff --git a/tests/scripts/wait_for_first_block.sh b/tests/scripts/wait_for_first_block.sh index 2f8a113d8d..fd20aef48d 100755 --- a/tests/scripts/wait_for_first_block.sh +++ b/tests/scripts/wait_for_first_block.sh @@ -1,15 +1,11 @@ #!/usr/bin/env bash -function do_rpc { - curl -s --header "Content-Type: application/json" -XPOST --data "{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"$1\",\"params\":[$2]}" $RPC_URL -} +DIR=$(dirname "$0") + +. $DIR/functions.sh function is_started { - block_hash_rpc=$(do_rpc chain_getFinalizedHead) - echo Rpc response = $block_hash_rpc - block_hash=$(echo $block_hash_rpc | jq -r .result) - echo Head = $block_hash - block_id_hex=$(do_rpc chain_getHeader "\"$block_hash\"" | jq -r .result.number) + block_id_hex=$(do_rpc chain_getHeader | jq -r .result.number) block_id=$((${block_id_hex})) echo Id = $block_id if (( $block_id > 1 )); then diff --git a/tests/src/.outdated/eth/scheduling.test.ts b/tests/src/.outdated/eth/scheduling.test.ts deleted file mode 100644 index 91ba16b6de..0000000000 --- a/tests/src/.outdated/eth/scheduling.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. -// This file is part of Unique Network. - -// Unique Network is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Unique Network is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Unique Network. If not, see . - -import {expect} from 'chai'; -import {createEthAccountWithBalance, deployFlipper, GAS_ARGS, itWeb3, subToEth, transferBalanceToEth} from '../../deprecated-helpers/eth/helpers'; -import {scheduleExpectSuccess, waitNewBlocks, requirePallets, Pallets} from '../../deprecated-helpers/helpers'; - -// TODO mrshiposha update this test in #581 -describe.skip('Scheduing EVM smart contracts', () => { - before(async function() { - await requirePallets(this, [Pallets.Scheduler]); - }); - - itWeb3('Successfully schedules and periodically executes an EVM contract', async ({api, web3, privateKeyWrapper}) => { - const deployer = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const flipper = await deployFlipper(web3, deployer); - const initialValue = await flipper.methods.getValue().call(); - const alice = privateKeyWrapper('//Alice'); - await transferBalanceToEth(api, alice, subToEth(alice.address)); - - { - const tx = api.tx.evm.call( - subToEth(alice.address), - flipper.options.address, - flipper.methods.flip().encodeABI(), - '0', - GAS_ARGS.gas, - await web3.eth.getGasPrice(), - null, - null, - [], - ); - const waitForBlocks = 4; - const periodBlocks = 2; - - await scheduleExpectSuccess(tx, alice, waitForBlocks, '0x' + '0'.repeat(32), periodBlocks, 2); - expect(await flipper.methods.getValue().call()).to.be.equal(initialValue); - - await waitNewBlocks(waitForBlocks - 1); - expect(await flipper.methods.getValue().call()).to.be.not.equal(initialValue); - - await waitNewBlocks(periodBlocks); - expect(await flipper.methods.getValue().call()).to.be.equal(initialValue); - } - }); -}); diff --git a/tests/src/rmrk/acceptNft.seqtest.ts b/tests/src/.outdated/rmrk/acceptNft.seqtest.ts similarity index 100% rename from tests/src/rmrk/acceptNft.seqtest.ts rename to tests/src/.outdated/rmrk/acceptNft.seqtest.ts diff --git a/tests/src/rmrk/addResource.seqtest.ts b/tests/src/.outdated/rmrk/addResource.seqtest.ts similarity index 100% rename from tests/src/rmrk/addResource.seqtest.ts rename to tests/src/.outdated/rmrk/addResource.seqtest.ts diff --git a/tests/src/rmrk/addTheme.seqtest.ts b/tests/src/.outdated/rmrk/addTheme.seqtest.ts similarity index 100% rename from tests/src/rmrk/addTheme.seqtest.ts rename to tests/src/.outdated/rmrk/addTheme.seqtest.ts diff --git a/tests/src/rmrk/burnNft.seqtest.ts b/tests/src/.outdated/rmrk/burnNft.seqtest.ts similarity index 100% rename from tests/src/rmrk/burnNft.seqtest.ts rename to tests/src/.outdated/rmrk/burnNft.seqtest.ts diff --git a/tests/src/rmrk/changeCollectionIssuer.seqtest.ts b/tests/src/.outdated/rmrk/changeCollectionIssuer.seqtest.ts similarity index 100% rename from tests/src/rmrk/changeCollectionIssuer.seqtest.ts rename to tests/src/.outdated/rmrk/changeCollectionIssuer.seqtest.ts diff --git a/tests/src/rmrk/createBase.seqtest.ts b/tests/src/.outdated/rmrk/createBase.seqtest.ts similarity index 100% rename from tests/src/rmrk/createBase.seqtest.ts rename to tests/src/.outdated/rmrk/createBase.seqtest.ts diff --git a/tests/src/rmrk/createCollection.seqtest.ts b/tests/src/.outdated/rmrk/createCollection.seqtest.ts similarity index 100% rename from tests/src/rmrk/createCollection.seqtest.ts rename to tests/src/.outdated/rmrk/createCollection.seqtest.ts diff --git a/tests/src/rmrk/deleteCollection.seqtest.ts b/tests/src/.outdated/rmrk/deleteCollection.seqtest.ts similarity index 100% rename from tests/src/rmrk/deleteCollection.seqtest.ts rename to tests/src/.outdated/rmrk/deleteCollection.seqtest.ts diff --git a/tests/src/rmrk/equipNft.seqtest.ts b/tests/src/.outdated/rmrk/equipNft.seqtest.ts similarity index 100% rename from tests/src/rmrk/equipNft.seqtest.ts rename to tests/src/.outdated/rmrk/equipNft.seqtest.ts diff --git a/tests/src/rmrk/getOwnedNfts.seqtest.ts b/tests/src/.outdated/rmrk/getOwnedNfts.seqtest.ts similarity index 100% rename from tests/src/rmrk/getOwnedNfts.seqtest.ts rename to tests/src/.outdated/rmrk/getOwnedNfts.seqtest.ts diff --git a/tests/src/rmrk/lockCollection.seqtest.ts b/tests/src/.outdated/rmrk/lockCollection.seqtest.ts similarity index 100% rename from tests/src/rmrk/lockCollection.seqtest.ts rename to tests/src/.outdated/rmrk/lockCollection.seqtest.ts diff --git a/tests/src/rmrk/mintNft.seqtest.ts b/tests/src/.outdated/rmrk/mintNft.seqtest.ts similarity index 100% rename from tests/src/rmrk/mintNft.seqtest.ts rename to tests/src/.outdated/rmrk/mintNft.seqtest.ts diff --git a/tests/src/rmrk/rejectNft.seqtest.ts b/tests/src/.outdated/rmrk/rejectNft.seqtest.ts similarity index 100% rename from tests/src/rmrk/rejectNft.seqtest.ts rename to tests/src/.outdated/rmrk/rejectNft.seqtest.ts diff --git a/tests/src/rmrk/removeResource.seqtest.ts b/tests/src/.outdated/rmrk/removeResource.seqtest.ts similarity index 100% rename from tests/src/rmrk/removeResource.seqtest.ts rename to tests/src/.outdated/rmrk/removeResource.seqtest.ts diff --git a/tests/src/rmrk/rmrkIsolation.seqtest.ts b/tests/src/.outdated/rmrk/rmrkIsolation.seqtest.ts similarity index 99% rename from tests/src/rmrk/rmrkIsolation.seqtest.ts rename to tests/src/.outdated/rmrk/rmrkIsolation.seqtest.ts index 44c86cd6a5..903a6e503e 100644 --- a/tests/src/rmrk/rmrkIsolation.seqtest.ts +++ b/tests/src/.outdated/rmrk/rmrkIsolation.seqtest.ts @@ -1,7 +1,7 @@ import {executeTransaction} from '../substrate/substrate-api'; import {IKeyringPair} from '@polkadot/types/types'; -import {itSub, expect, usingPlaygrounds, Pallets, requirePalletsOrSkip} from '../util'; -import {UniqueHelper} from '../util/playgrounds/unique'; +import {itSub, expect, usingPlaygrounds, Pallets, requirePalletsOrSkip} from '../../util'; +import {UniqueHelper} from '../../util/playgrounds/unique'; let alice: IKeyringPair; let bob: IKeyringPair; diff --git a/tests/src/rmrk/sendNft.seqtest.ts b/tests/src/.outdated/rmrk/sendNft.seqtest.ts similarity index 100% rename from tests/src/rmrk/sendNft.seqtest.ts rename to tests/src/.outdated/rmrk/sendNft.seqtest.ts diff --git a/tests/src/rmrk/setCollectionProperty.seqtest.ts b/tests/src/.outdated/rmrk/setCollectionProperty.seqtest.ts similarity index 100% rename from tests/src/rmrk/setCollectionProperty.seqtest.ts rename to tests/src/.outdated/rmrk/setCollectionProperty.seqtest.ts diff --git a/tests/src/rmrk/setEquippableList.seqtest.ts b/tests/src/.outdated/rmrk/setEquippableList.seqtest.ts similarity index 100% rename from tests/src/rmrk/setEquippableList.seqtest.ts rename to tests/src/.outdated/rmrk/setEquippableList.seqtest.ts diff --git a/tests/src/rmrk/setNftProperty.seqtest.ts b/tests/src/.outdated/rmrk/setNftProperty.seqtest.ts similarity index 100% rename from tests/src/rmrk/setNftProperty.seqtest.ts rename to tests/src/.outdated/rmrk/setNftProperty.seqtest.ts diff --git a/tests/src/rmrk/setResourcePriorities.seqtest.ts b/tests/src/.outdated/rmrk/setResourcePriorities.seqtest.ts similarity index 100% rename from tests/src/rmrk/setResourcePriorities.seqtest.ts rename to tests/src/.outdated/rmrk/setResourcePriorities.seqtest.ts diff --git a/tests/src/rmrk/util/fetch.ts b/tests/src/.outdated/rmrk/util/fetch.ts similarity index 95% rename from tests/src/rmrk/util/fetch.ts rename to tests/src/.outdated/rmrk/util/fetch.ts index ef01641bcf..94f8e525c7 100644 --- a/tests/src/rmrk/util/fetch.ts +++ b/tests/src/.outdated/rmrk/util/fetch.ts @@ -9,9 +9,9 @@ import type { RmrkTraitsNftNftChild as NftChild, RmrkTraitsTheme as Theme, RmrkTraitsPropertyPropertyInfo as Property, -} from '../../interfaces/default/types'; // '@polkadot/types/lookup'; -import '../../interfaces/augment-api'; -import '../../interfaces/augment-api-query'; +} from '../../../interfaces/default/types'; // '@polkadot/types/lookup'; +import '../../../interfaces/augment-api'; +import '../../../interfaces/augment-api-query'; import privateKey from '../../substrate/privateKey'; export type NftIdTuple = [number, number]; diff --git a/tests/src/rmrk/util/helpers.ts b/tests/src/.outdated/rmrk/util/helpers.ts similarity index 100% rename from tests/src/rmrk/util/helpers.ts rename to tests/src/.outdated/rmrk/util/helpers.ts diff --git a/tests/src/rmrk/util/tx.ts b/tests/src/.outdated/rmrk/util/tx.ts similarity index 99% rename from tests/src/rmrk/util/tx.ts rename to tests/src/.outdated/rmrk/util/tx.ts index b218784baa..22abfe5da2 100644 --- a/tests/src/rmrk/util/tx.ts +++ b/tests/src/.outdated/rmrk/util/tx.ts @@ -8,7 +8,7 @@ import { import {IKeyringPair} from '@polkadot/types/types'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; -import '../../interfaces/augment-api'; +import '../../../interfaces/augment-api'; import privateKey from '../../substrate/privateKey'; import {executeTransaction} from '../../substrate/substrate-api'; import { diff --git a/tests/src/.outdated/scheduler.test.ts b/tests/src/.outdated/scheduler.test.ts deleted file mode 100644 index 08a257cb48..0000000000 --- a/tests/src/.outdated/scheduler.test.ts +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. -// This file is part of Unique Network. - -// Unique Network is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Unique Network is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Unique Network. If not, see . - -import chai, {expect} from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import { - default as usingApi, - submitTransactionAsync, -} from '../substrate/substrate-api'; -import { - createItemExpectSuccess, - createCollectionExpectSuccess, - scheduleTransferExpectSuccess, - scheduleTransferAndWaitExpectSuccess, - setCollectionSponsorExpectSuccess, - confirmSponsorshipExpectSuccess, - findUnusedAddress, - UNIQUE, - enablePublicMintingExpectSuccess, - addToAllowListExpectSuccess, - waitNewBlocks, - normalizeAccountId, - getTokenOwner, - getGenericResult, - scheduleTransferFundsPeriodicExpectSuccess, - getFreeBalance, - confirmSponsorshipByKeyExpectSuccess, - scheduleExpectFailure, -} from '../deprecated-helpers/helpers'; -import {IKeyringPair} from '@polkadot/types/types'; - -chai.use(chaiAsPromised); - -// todo:playgrounds skipped ~ postponed -describe.skip('Scheduling token and balance transfers', () => { - let alice: IKeyringPair; - let bob: IKeyringPair; - let scheduledIdBase: string; - let scheduledIdSlider: number; - - before(async() => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - }); - - scheduledIdBase = '0x' + '0'.repeat(31); - scheduledIdSlider = 0; - }); - - // Loop scheduledId around 10. Unless there are concurrent tasks with long periods/repetitions, tests' tasks' ids shouldn't ovelap. - function makeScheduledId(): string { - return scheduledIdBase + ((scheduledIdSlider++) % 10); - } - - it('Can schedule a transfer of an owned token with delay', async () => { - await usingApi(async () => { - const nftCollectionId = await createCollectionExpectSuccess(); - const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT'); - await setCollectionSponsorExpectSuccess(nftCollectionId, alice.address); - await confirmSponsorshipExpectSuccess(nftCollectionId); - - await scheduleTransferAndWaitExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 1, 4, makeScheduledId()); - }); - }); - - it('Can transfer funds periodically', async () => { - await usingApi(async () => { - const waitForBlocks = 4; - const period = 2; - await scheduleTransferFundsPeriodicExpectSuccess(1n * UNIQUE, alice, bob, waitForBlocks, makeScheduledId(), period, 2); - const bobsBalanceBefore = await getFreeBalance(bob); - - // discounting already waited-for operations - await waitNewBlocks(waitForBlocks - 2); - const bobsBalanceAfterFirst = await getFreeBalance(bob); - expect(bobsBalanceAfterFirst > bobsBalanceBefore).to.be.true; - - await waitNewBlocks(period); - const bobsBalanceAfterSecond = await getFreeBalance(bob); - expect(bobsBalanceAfterSecond > bobsBalanceAfterFirst).to.be.true; - }); - }); - - it('Can sponsor scheduling a transaction', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); - - await usingApi(async () => { - const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); - - const bobBalanceBefore = await getFreeBalance(bob); - const waitForBlocks = 4; - // no need to wait to check, fees must be deducted on scheduling, immediately - await scheduleTransferExpectSuccess(collectionId, tokenId, alice, bob, 0, waitForBlocks, makeScheduledId()); - const bobBalanceAfter = await getFreeBalance(bob); - // expect(aliceBalanceAfter == aliceBalanceBefore).to.be.true; - expect(bobBalanceAfter < bobBalanceBefore).to.be.true; - // wait for sequentiality matters - await waitNewBlocks(waitForBlocks - 1); - }); - }); - - it('Schedules and dispatches a transaction even if the caller has no funds at the time of the dispatch', async () => { - await usingApi(async (api, privateKeyWrapper) => { - // Find an empty, unused account - const zeroBalance = await findUnusedAddress(api, privateKeyWrapper); - - const collectionId = await createCollectionExpectSuccess(); - - // Add zeroBalance address to allow list - await enablePublicMintingExpectSuccess(alice, collectionId); - await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address); - - // Grace zeroBalance with money, enough to cover future transactions - const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE); - await submitTransactionAsync(alice, balanceTx); - - // Mint a fresh NFT - const tokenId = await createItemExpectSuccess(zeroBalance, collectionId, 'NFT'); - - // Schedule transfer of the NFT a few blocks ahead - const waitForBlocks = 5; - await scheduleTransferExpectSuccess(collectionId, tokenId, zeroBalance, alice, 1, waitForBlocks, makeScheduledId()); - - // Get rid of the account's funds before the scheduled transaction takes place - const balanceTx2 = api.tx.balances.transfer(alice.address, UNIQUE * 68n / 100n); - const events = await submitTransactionAsync(zeroBalance, balanceTx2); - expect(getGenericResult(events).success).to.be.true; - /*const emptyBalanceTx = api.tx.balances.setBalance(zeroBalance.address, 0, 0); // do not null reserved? - const sudoTx = api.tx.sudo.sudo(emptyBalanceTx as any); - const events = await submitTransactionAsync(alice, sudoTx); - expect(getGenericResult(events).success).to.be.true;*/ - - // Wait for a certain number of blocks, discarding the ones that already happened while accepting the late transactions - await waitNewBlocks(waitForBlocks - 3); - - expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(alice.address)); - }); - }); - - it('Sponsor going bankrupt does not impact a scheduled transaction', async () => { - const collectionId = await createCollectionExpectSuccess(); - - await usingApi(async (api, privateKeyWrapper) => { - const zeroBalance = await findUnusedAddress(api, privateKeyWrapper); - const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE); - await submitTransactionAsync(alice, balanceTx); - - await setCollectionSponsorExpectSuccess(collectionId, zeroBalance.address); - await confirmSponsorshipByKeyExpectSuccess(collectionId, zeroBalance); - - const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); - - const waitForBlocks = 5; - await scheduleTransferExpectSuccess(collectionId, tokenId, alice, zeroBalance, 1, waitForBlocks, makeScheduledId()); - - const emptyBalanceSponsorTx = api.tx.balances.setBalance(zeroBalance.address, 0, 0); - const sudoTx = api.tx.sudo.sudo(emptyBalanceSponsorTx as any); - const events = await submitTransactionAsync(alice, sudoTx); - expect(getGenericResult(events).success).to.be.true; - - // Wait for a certain number of blocks, save for the ones that already happened while accepting the late transactions - await waitNewBlocks(waitForBlocks - 3); - - expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(zeroBalance.address)); - }); - }); - - it.skip('Exceeding sponsor rate limit without having enough funds prevents scheduling a periodic transaction', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); - - await usingApi(async (api, privateKeyWrapper) => { - const zeroBalance = await findUnusedAddress(api, privateKeyWrapper); - - await enablePublicMintingExpectSuccess(alice, collectionId); - await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address); - - const bobBalanceBefore = await getFreeBalance(bob); - - const createData = {nft: {const_data: [], variable_data: []}}; - const creationTx = api.tx.unique.createItem(collectionId, normalizeAccountId(zeroBalance), createData as any); - - /*const badTransaction = async function () { - await submitTransactionExpectFailAsync(zeroBalance, zeroToAlice); - }; - await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');*/ - - await scheduleExpectFailure(creationTx, zeroBalance, 3, makeScheduledId(), 1, 3); - - expect(await getFreeBalance(bob)).to.be.equal(bobBalanceBefore); - }); - }); -}); diff --git a/tests/src/substrate/get-balance.ts b/tests/src/.outdated/substrate/get-balance.ts similarity index 100% rename from tests/src/substrate/get-balance.ts rename to tests/src/.outdated/substrate/get-balance.ts diff --git a/tests/src/substrate/privateKey.ts b/tests/src/.outdated/substrate/privateKey.ts similarity index 100% rename from tests/src/substrate/privateKey.ts rename to tests/src/.outdated/substrate/privateKey.ts diff --git a/tests/src/substrate/promisify-substrate.ts b/tests/src/.outdated/substrate/promisify-substrate.ts similarity index 100% rename from tests/src/substrate/promisify-substrate.ts rename to tests/src/.outdated/substrate/promisify-substrate.ts diff --git a/tests/src/substrate/substrate-api.ts b/tests/src/.outdated/substrate/substrate-api.ts similarity index 96% rename from tests/src/substrate/substrate-api.ts rename to tests/src/.outdated/substrate/substrate-api.ts index 90ecf85b5b..0ca5b0b111 100644 --- a/tests/src/substrate/substrate-api.ts +++ b/tests/src/.outdated/substrate/substrate-api.ts @@ -19,13 +19,13 @@ import {ApiOptions, ApiTypes, SubmittableExtrinsic} from '@polkadot/api/types'; import {ExtrinsicStatus} from '@polkadot/types/interfaces/author/types'; import {EventRecord} from '@polkadot/types/interfaces/system/types'; import {IKeyringPair} from '@polkadot/types/types'; -import config from '../config'; -import '../interfaces/augment-api-events'; -import * as defs from '../interfaces/definitions'; +import config from '../../config'; +import '../../interfaces/augment-api-events'; +import * as defs from '../../interfaces/definitions'; import privateKey from './privateKey'; import promisifySubstrate from './promisify-substrate'; -import {SilentConsole} from '../util/playgrounds/unique.dev'; +import {SilentConsole} from '../../util/playgrounds/unique.dev'; @@ -37,6 +37,10 @@ function defaultApiOptions(): ApiOptions { extrinsic: {}, payload: {}, }, + CheckMaintenance: { + extrinsic: {}, + payload: {}, + }, FakeTransactionFinalizer: { extrinsic: {}, payload: {}, diff --git a/tests/src/substrate/wait-new-blocks.ts b/tests/src/.outdated/substrate/wait-new-blocks.ts similarity index 100% rename from tests/src/substrate/wait-new-blocks.ts rename to tests/src/.outdated/substrate/wait-new-blocks.ts diff --git a/tests/src/addCollectionAdmin.test.ts b/tests/src/addCollectionAdmin.test.ts index 194a9a306d..1599c75107 100644 --- a/tests/src/addCollectionAdmin.test.ts +++ b/tests/src/addCollectionAdmin.test.ts @@ -56,10 +56,8 @@ describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_ const collection = await helper.collection.getData(collectionId); expect(collection?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(alice.address)); - const changeAdminTxBob = () => helper.collection.addAdmin(bob, collectionId, {Substrate: bob.address}); - const changeAdminTxCharlie = () => helper.collection.addAdmin(bob, collectionId, {Substrate: charlie.address}); - await expect(changeAdminTxCharlie()).to.be.rejectedWith(/common\.NoPermission/); - await expect(changeAdminTxBob()).to.be.rejectedWith(/common\.NoPermission/); + await expect(helper.collection.addAdmin(bob, collectionId, {Substrate: charlie.address})).to.be.rejectedWith(/common\.NoPermission/); + await expect(helper.collection.addAdmin(bob, collectionId, {Substrate: bob.address})).to.be.rejectedWith(/common\.NoPermission/); const adminListAfterAddAdmin = await helper.collection.getAdmins(collectionId); expect(adminListAfterAddAdmin).to.be.not.deep.contains({Substrate: charlie.address}); @@ -75,8 +73,7 @@ describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_ const adminListAfterAddAdmin = await collection.getAdmins(); expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: bob.address}); - const changeAdminTxCharlie = () => collection.addAdmin(bob, {Substrate: charlie.address}); - await expect(changeAdminTxCharlie()).to.be.rejectedWith(/common\.NoPermission/); + await expect(collection.addAdmin(bob, {Substrate: charlie.address})).to.be.rejectedWith(/common\.NoPermission/); const adminListAfterAddNewAdmin = await collection.getAdmins(); expect(adminListAfterAddNewAdmin).to.be.deep.contains({Substrate: bob.address}); @@ -87,8 +84,7 @@ describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_ const [alice, bob] = await helper.arrange.createAccounts([10n, 10n, 10n], donor); const collectionId = (1 << 32) - 1; - const addAdminTx = () => helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address}); - await expect(addAdminTx()).to.be.rejectedWith(/common\.CollectionNotFound/); + await expect(helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address})).to.be.rejectedWith(/common\.CollectionNotFound/); // Verifying that nothing bad happened (network is live, new collections can be created, etc.) await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'}); @@ -99,8 +95,7 @@ describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_ const collection = await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'}); await collection.burn(alice); - const addAdminTx = () => collection.addAdmin(alice, {Substrate: bob.address}); - await expect(addAdminTx()).to.be.rejectedWith(/common\.CollectionNotFound/); + await expect(collection.addAdmin(alice, {Substrate: bob.address})).to.be.rejectedWith(/common\.CollectionNotFound/); // Verifying that nothing bad happened (network is live, new collections can be created, etc.) await helper.nft.mintCollection(alice, {name: 'Collection Name', description: 'Collection Description', tokenPrefix: 'COL'}); @@ -119,7 +114,6 @@ describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_ expect(adminListAfterAddAdmin).to.be.deep.contains({Substrate: accounts[i].address}); } - const addExtraAdminTx = () => collection.addAdmin(alice, {Substrate: accounts[chainAdminLimit].address}); - await expect(addExtraAdminTx()).to.be.rejectedWith(/common\.CollectionAdminCountExceeded/); + await expect(collection.addAdmin(alice, {Substrate: accounts[chainAdminLimit].address})).to.be.rejectedWith(/common\.CollectionAdminCountExceeded/); }); }); diff --git a/tests/src/adminTransferAndBurn.test.ts b/tests/src/adminTransferAndBurn.test.ts index 3a41406ff3..70c7373dff 100644 --- a/tests/src/adminTransferAndBurn.test.ts +++ b/tests/src/adminTransferAndBurn.test.ts @@ -36,8 +36,7 @@ describe('Integration Test: ownerCanTransfer allows admins to use only transferF expect(limits.ownerCanTransfer).to.be.true; const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address}); - const transferResult = () => helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}); - await expect(transferResult()).to.be.rejected; + await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address})).to.be.rejected; await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: bob.address}, {Substrate: charlie.address}); const newTokenOwner = await helper.nft.getTokenOwner(collectionId, tokenId); @@ -52,9 +51,8 @@ describe('Integration Test: ownerCanTransfer allows admins to use only transferF expect(limits.ownerCanTransfer).to.be.true; const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address}); - const burnTxFailed = () => helper.nft.burnToken(alice, collectionId, tokenId); - await expect(burnTxFailed()).to.be.rejected; + await expect(helper.nft.burnToken(alice, collectionId, tokenId)).to.be.rejected; await helper.nft.burnToken(bob, collectionId, tokenId); const token = await helper.nft.getToken(collectionId, tokenId); diff --git a/tests/src/apiConsts.test.ts b/tests/src/apiConsts.test.ts new file mode 100644 index 0000000000..041a0ae9d7 --- /dev/null +++ b/tests/src/apiConsts.test.ts @@ -0,0 +1,119 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {ApiPromise} from '@polkadot/api'; +import {usingPlaygrounds, itSub, expect} from './util'; + + +const MAX_COLLECTION_DESCRIPTION_LENGTH = 256n; +const MAX_COLLECTION_NAME_LENGTH = 64n; +const COLLECTION_ADMINS_LIMIT = 5n; +const MAX_COLLECTION_PROPERTIES_SIZE = 40960n; +const MAX_TOKEN_PREFIX_LENGTH = 16n; +const MAX_PROPERTY_KEY_LENGTH = 256n; +const MAX_PROPERTY_VALUE_LENGTH = 32768n; +const MAX_PROPERTIES_PER_ITEM = 64n; +const MAX_TOKEN_PROPERTIES_SIZE = 32768n; +const NESTING_BUDGET = 5n; + +const DEFAULT_COLLETCTION_LIMIT = { + accountTokenOwnershipLimit: '1,000,000', + sponsoredDataSize: '2,048', + sponsoredDataRateLimit: 'SponsoringDisabled', + tokenLimit: '4,294,967,295', + sponsorTransferTimeout: '5', + sponsorApproveTimeout: '5', + ownerCanTransfer: false, + ownerCanDestroy: true, + transfersEnabled: true, +}; + +const EVM_COLLECTION_HELPERS_ADDRESS = '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f'; +const HELPERS_CONTRACT_ADDRESS = '0x842899ECF380553E8a4de75bF534cdf6fBF64049'; + +describe('integration test: API UNIQUE consts', () => { + let api: ApiPromise; + + before(async () => { + await usingPlaygrounds(async (helper) => { + api = await helper.getApi(); + }); + }); + + itSub('DEFAULT_NFT_COLLECTION_LIMITS', () => { + expect(api.consts.unique.nftDefaultCollectionLimits.toHuman()).to.deep.equal(DEFAULT_COLLETCTION_LIMIT); + }); + + itSub('DEFAULT_RFT_COLLECTION_LIMITS', () => { + expect(api.consts.unique.rftDefaultCollectionLimits.toHuman()).to.deep.equal(DEFAULT_COLLETCTION_LIMIT); + }); + + itSub('DEFAULT_FT_COLLECTION_LIMITS', () => { + expect(api.consts.unique.ftDefaultCollectionLimits.toHuman()).to.deep.equal(DEFAULT_COLLETCTION_LIMIT); + }); + + itSub('MAX_COLLECTION_NAME_LENGTH', () => { + checkConst(api.consts.unique.maxCollectionNameLength, MAX_COLLECTION_NAME_LENGTH); + }); + + itSub('MAX_COLLECTION_DESCRIPTION_LENGTH', () => { + checkConst(api.consts.unique.maxCollectionDescriptionLength, MAX_COLLECTION_DESCRIPTION_LENGTH); + }); + + itSub('MAX_COLLECTION_PROPERTIES_SIZE', () => { + checkConst(api.consts.unique.maxCollectionPropertiesSize, MAX_COLLECTION_PROPERTIES_SIZE); + }); + + itSub('MAX_TOKEN_PREFIX_LENGTH', () => { + checkConst(api.consts.unique.maxTokenPrefixLength, MAX_TOKEN_PREFIX_LENGTH); + }); + + itSub('MAX_PROPERTY_KEY_LENGTH', () => { + checkConst(api.consts.unique.maxPropertyKeyLength, MAX_PROPERTY_KEY_LENGTH); + }); + + itSub('MAX_PROPERTY_VALUE_LENGTH', () => { + checkConst(api.consts.unique.maxPropertyValueLength, MAX_PROPERTY_VALUE_LENGTH); + }); + + itSub('MAX_PROPERTIES_PER_ITEM', () => { + checkConst(api.consts.unique.maxPropertiesPerItem, MAX_PROPERTIES_PER_ITEM); + }); + + itSub('NESTING_BUDGET', () => { + checkConst(api.consts.unique.nestingBudget, NESTING_BUDGET); + }); + + itSub('MAX_TOKEN_PROPERTIES_SIZE', () => { + checkConst(api.consts.unique.maxTokenPropertiesSize, MAX_TOKEN_PROPERTIES_SIZE); + }); + + itSub('COLLECTION_ADMINS_LIMIT', () => { + checkConst(api.consts.unique.collectionAdminsLimit, COLLECTION_ADMINS_LIMIT); + }); + + itSub('HELPERS_CONTRACT_ADDRESS', () => { + expect(api.consts.evmContractHelpers.contractAddress.toString().toLowerCase()).to.be.equal(HELPERS_CONTRACT_ADDRESS.toLowerCase()); + }); + + itSub('EVM_COLLECTION_HELPERS_ADDRESS', () => { + expect(api.consts.common.contractAddress.toString().toLowerCase()).to.be.equal(EVM_COLLECTION_HELPERS_ADDRESS.toLowerCase()); + }); +}); + +function checkConst(constValue: any, expectedValue: T) { + expect(constValue.toBigInt()).equal(expectedValue); +} \ No newline at end of file diff --git a/tests/src/app-promotion.seqtest.ts b/tests/src/app-promotion.seqtest.ts index 7bf1cb9350..233670576e 100644 --- a/tests/src/app-promotion.seqtest.ts +++ b/tests/src/app-promotion.seqtest.ts @@ -50,31 +50,31 @@ describe('App promotion', () => { await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address}))).to.be.rejected; await expect(helper.signTransaction(nonAdmin, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: nonAdmin.address})))).to.be.rejected; }); - + itSub('can be any valid CrossAccountId', async ({helper}) => { // We are not going to set an eth address as a sponsor, // but we do want to check, it doesn't break anything; const api = helper.getApi(); const [account] = await helper.arrange.createAccounts([10n], donor); - const ethAccount = helper.address.substrateToEth(account.address); + const ethAccount = helper.address.substrateToEth(account.address); // Alice sets Ethereum address as a sudo. Then Substrate address back... await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Ethereum: ethAccount})))).to.be.fulfilled; await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.fulfilled; - + // ...It doesn't break anything; const collection = await helper.nft.mintCollection(account, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'}); await expect(helper.signTransaction(account, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected; }); - + itSub('can be reassigned', async ({helper}) => { const api = helper.getApi(); const [oldAdmin, newAdmin, collectionOwner] = await helper.arrange.createAccounts([10n, 10n, 10n], donor); const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'}); - + await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: oldAdmin.address})))).to.be.fulfilled; await expect(helper.signTransaction(superuser, api.tx.sudo.sudo(api.tx.appPromotion.setAdminAddress({Substrate: newAdmin.address})))).to.be.fulfilled; await expect(helper.signTransaction(oldAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected; - + await expect(helper.signTransaction(newAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.fulfilled; }); }); diff --git a/tests/src/app-promotion.test.ts b/tests/src/app-promotion.test.ts index 318a22ebdb..79e80a0d96 100644 --- a/tests/src/app-promotion.test.ts +++ b/tests/src/app-promotion.test.ts @@ -45,112 +45,113 @@ describe('App promotion', () => { }); }); - describe('stake extrinsic', () => { + describe('stake extrinsic', () => { itSub('should "lock" staking balance, add it to "staked" map, and increase "totalStaked" amount', async ({helper}) => { const [staker, recepient] = [accounts.pop()!, accounts.pop()!]; const totalStakedBefore = await helper.staking.getTotalStaked(); - + // Minimum stake amount is 100: await expect(helper.staking.stake(staker, 100n * nominal - 1n)).to.be.rejected; await helper.staking.stake(staker, 100n * nominal); - + // Staker balance is: miscFrozen: 100, feeFrozen: 100, reserved: 0n... // ...so he can not transfer 900 - expect (await helper.balance.getSubstrateFull(staker.address)).to.contain({miscFrozen: 100n * nominal, feeFrozen: 100n * nominal, reserved: 0n}); + expect(await helper.balance.getSubstrateFull(staker.address)).to.contain({miscFrozen: 100n * nominal, feeFrozen: 100n * nominal, reserved: 0n}); + expect(await helper.balance.getLocked(staker.address)).to.deep.eq([{id: 'appstake', amount: 100n * nominal, reasons: 'All'}]); await expect(helper.balance.transferToSubstrate(staker, recepient.address, 900n * nominal)).to.be.rejectedWith('balances.LiquidityRestrictions'); - + expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(100n * nominal); expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n); - // it is potentially flaky test. Promotion can credited some tokens. Maybe we need to use closeTo? - expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore + 100n * nominal); // total tokens amount staked in app-promotion increased - - + // it is potentially flaky test. Promotion can credited some tokens. Maybe we need to use closeTo? + expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore + 100n * nominal); // total tokens amount staked in app-promotion increased + + await helper.staking.stake(staker, 200n * nominal); expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(300n * nominal); const totalStakedPerBlock = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}); expect(totalStakedPerBlock[0].amount).to.equal(100n * nominal); expect(totalStakedPerBlock[1].amount).to.equal(200n * nominal); }); - + itSub('should allow to create maximum 10 stakes for account', async ({helper}) => { const [staker] = await helper.arrange.createAccounts([2000n], donor); for (let i = 0; i < 10; i++) { await helper.staking.stake(staker, 100n * nominal); } - + // can have 10 stakes expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(1000n * nominal); expect(await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).to.have.length(10); - + await expect(helper.staking.stake(staker, 100n * nominal)).to.be.rejectedWith('appPromotion.NoPermission'); - + // After unstake can stake again await helper.staking.unstake(staker); await helper.staking.stake(staker, 100n * nominal); expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.equal(100n * nominal); }); - + itSub('should reject transaction if stake amount is more than total free balance minus frozen', async ({helper}) => { const staker = accounts.pop()!; - + // Can't stake full balance because Alice needs to pay some fee await expect(helper.staking.stake(staker, 1000n * nominal)).to.be.rejected; await helper.staking.stake(staker, 500n * nominal); - + // Can't stake 500 tkn because Alice has Less than 500 transferable; - await expect(helper.staking.stake(staker, 500n * nominal)).to.be.rejectedWith('balances.LiquidityRestrictions'); + await expect(helper.staking.stake(staker, 500n * nominal)).to.be.rejectedWith('balances.LiquidityRestrictions'); expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(500n * nominal); }); - + itSub('for different accounts in one block is possible', async ({helper}) => { const crowd = [accounts.pop()!, accounts.pop()!, accounts.pop()!, accounts.pop()!]; - + const crowdStartsToStake = crowd.map(user => helper.staking.stake(user, 100n * nominal)); await expect(Promise.all(crowdStartsToStake)).to.be.fulfilled; - + const crowdStakes = await Promise.all(crowd.map(address => helper.staking.getTotalStaked({Substrate: address.address}))); expect(crowdStakes).to.deep.equal([100n * nominal, 100n * nominal, 100n * nominal, 100n * nominal]); }); }); - - describe('unstake extrinsic', () => { + + describe('unstake extrinsic', () => { itSub('should change balance state from "frozen" to "reserved", add it to "pendingUnstake" map, and subtract it from totalStaked', async ({helper}) => { const [staker, recepient] = [accounts.pop()!, accounts.pop()!]; const totalStakedBefore = await helper.staking.getTotalStaked(); await helper.staking.stake(staker, 900n * nominal); await helper.staking.unstake(staker); - + // Right after unstake balance is reserved - // Staker can not transfer + // Staker can not transfer expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 900n * nominal, miscFrozen: 0n, feeFrozen: 0n}); await expect(helper.balance.transferToSubstrate(staker, recepient.address, 100n * nominal)).to.be.rejectedWith('balances.InsufficientBalance'); expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(900n * nominal); expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n); expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedBefore); }); - + itSub('should unlock balance after unlocking period ends and remove it from "pendingUnstake"', async ({helper}) => { const staker = accounts.pop()!; await helper.staking.stake(staker, 100n * nominal); await helper.staking.unstake(staker); const [pendingUnstake] = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address}); - + // Wait for unstaking period. Balance now free ~1000; reserved, frozen, miscFrozeb: 0n await helper.wait.forParachainBlockNumber(pendingUnstake.block); expect(await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, miscFrozen: 0n, feeFrozen: 0n}); expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n); - + // staker can transfer: await helper.balance.transferToSubstrate(staker, donor.address, 998n * nominal); expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(1n); }); - + itSub('should successfully unstake multiple stakes', async ({helper}) => { const staker = accounts.pop()!; await helper.staking.stake(staker, 100n * nominal); await helper.staking.stake(staker, 200n * nominal); await helper.staking.stake(staker, 300n * nominal); - + // staked: [100, 200, 300]; unstaked: 0 let totalPendingUnstake = await helper.staking.getPendingUnstake({Substrate: staker.address}); let pendingUnstake = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address}); @@ -160,7 +161,7 @@ describe('App promotion', () => { expect(stakes[0].amount).to.equal(100n * nominal); expect(stakes[1].amount).to.equal(200n * nominal); expect(stakes[2].amount).to.equal(300n * nominal); - + // Can unstake multiple stakes await helper.staking.unstake(staker); pendingUnstake = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address}); @@ -169,58 +170,58 @@ describe('App promotion', () => { expect(totalPendingUnstake).to.be.equal(600n * nominal); expect(stakes).to.be.deep.equal([]); expect(pendingUnstake[0].amount).to.equal(600n * nominal); - + expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 600n * nominal, feeFrozen: 0n, miscFrozen: 0n}); await helper.wait.forParachainBlockNumber(pendingUnstake[0].block); expect (await helper.balance.getSubstrateFull(staker.address)).to.deep.contain({reserved: 0n, feeFrozen: 0n, miscFrozen: 0n}); expect (await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n); }); - + itSub('should not have any effects if no active stakes', async ({helper}) => { const staker = accounts.pop()!; - + // unstake has no effect if no stakes at all await helper.staking.unstake(staker); expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(0n); expect(await helper.balance.getSubstrate(staker.address) / nominal).to.be.equal(999n); // TODO bigint closeTo helper - + // TODO stake() unstake() waitUnstaked() unstake(); - + // can't unstake if there are only pendingUnstakes await helper.staking.stake(staker, 100n * nominal); await helper.staking.unstake(staker); await helper.staking.unstake(staker); - + expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(100n * nominal); expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n); }); - + itSub('should keep different unlocking block for each unlocking stake', async ({helper}) => { const staker = accounts.pop()!; await helper.staking.stake(staker, 100n * nominal); await helper.staking.unstake(staker); await helper.staking.stake(staker, 120n * nominal); await helper.staking.unstake(staker); - + const unstakingPerBlock = await helper.staking.getPendingUnstakePerBlock({Substrate: staker.address}); expect(unstakingPerBlock).has.length(2); expect(unstakingPerBlock[0].amount).to.equal(100n * nominal); expect(unstakingPerBlock[1].amount).to.equal(120n * nominal); }); - + itSub('should be possible for different accounts in one block', async ({helper}) => { const stakers = [accounts.pop()!, accounts.pop()!, accounts.pop()!]; - + await Promise.all(stakers.map(staker => helper.staking.stake(staker, 100n * nominal))); await Promise.all(stakers.map(staker => helper.staking.unstake(staker))); - + await Promise.all(stakers.map(async (staker) => { expect(await helper.staking.getPendingUnstake({Substrate: staker.address})).to.be.equal(100n * nominal); expect(await helper.staking.getTotalStaked({Substrate: staker.address})).to.be.equal(0n); })); }); }); - + describe('collection sponsoring', () => { itSub('should actually sponsor transactions', async ({helper}) => { const api = helper.getApi(); @@ -229,368 +230,374 @@ describe('App promotion', () => { const token = await collection.mintToken(collectionOwner, {Substrate: tokenSender.address}); await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId)); const palletBalanceBefore = await helper.balance.getSubstrate(palletAddress); - + await token.transfer(tokenSender, {Substrate: receiver.address}); expect (await token.getOwner()).to.be.deep.equal({Substrate: receiver.address}); const palletBalanceAfter = await helper.balance.getSubstrate(palletAddress); - + // senders balance the same, transaction has sponsored expect (await helper.balance.getSubstrate(tokenSender.address)).to.be.equal(1000n * nominal); expect (palletBalanceBefore > palletBalanceAfter).to.be.true; }); - + itSub('can not be set by non admin', async ({helper}) => { const api = helper.getApi(); const [collectionOwner, nonAdmin] = [accounts.pop()!, accounts.pop()!]; - + const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'}); - + await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected; expect((await collection.getData())?.raw.sponsorship).to.equal('Disabled'); }); - + itSub('should set pallet address as confirmed admin', async ({helper}) => { const api = helper.getApi(); const [collectionOwner, oldSponsor] = [accounts.pop()!, accounts.pop()!]; - + // Can set sponsoring for collection without sponsor const collectionWithoutSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'No-sponsor', description: 'New Collection', tokenPrefix: 'Promotion'}); await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithoutSponsor.collectionId))).to.be.fulfilled; expect((await collectionWithoutSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress}); - + // Can set sponsoring for collection with unconfirmed sponsor const collectionWithUnconfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Unconfirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: oldSponsor.address}); expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: oldSponsor.address}); await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithUnconfirmedSponsor.collectionId))).to.be.fulfilled; expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress}); - + // Can set sponsoring for collection with confirmed sponsor const collectionWithConfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Confirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: oldSponsor.address}); await collectionWithConfirmedSponsor.confirmSponsorship(oldSponsor); await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithConfirmedSponsor.collectionId))).to.be.fulfilled; expect((await collectionWithConfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress}); }); - - itSub('can be overwritten by collection owner', async ({helper}) => { + + itSub('can be overwritten by collection owner', async ({helper}) => { const api = helper.getApi(); const [collectionOwner, newSponsor] = [accounts.pop()!, accounts.pop()!]; const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'}); const collectionId = collection.collectionId; - + await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionId))).to.be.fulfilled; - + // Collection limits still can be changed by the owner expect(await collection.setLimits(collectionOwner, {sponsorTransferTimeout: 0})).to.be.true; expect((await collection.getData())?.raw.limits.sponsorTransferTimeout).to.be.equal(0); expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress}); - + // Collection sponsor can be changed too expect((await collection.setSponsor(collectionOwner, newSponsor.address))).to.be.true; expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: newSponsor.address}); }); - + itSub('should not overwrite collection limits set by the owner earlier', async ({helper}) => { const api = helper.getApi(); const limits = {ownerCanDestroy: true, ownerCanTransfer: true, sponsorTransferTimeout: 0}; const collectionWithLimits = await helper.nft.mintCollection(accounts.pop()!, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits}); - + await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collectionWithLimits.collectionId))).to.be.fulfilled; expect((await collectionWithLimits.getData())?.raw.limits).to.be.deep.contain(limits); }); - + itSub('should reject transaction if collection doesn\'t exist', async ({helper}) => { const api = helper.getApi(); const collectionOwner = accounts.pop()!; - + // collection has never existed await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(999999999))).to.be.rejected; // collection has been burned const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'}); await collection.burn(collectionOwner); - + await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.rejected; }); }); - + describe('stopSponsoringCollection', () => { itSub('can not be called by non-admin', async ({helper}) => { const api = helper.getApi(); const [collectionOwner, nonAdmin] = [accounts.pop()!, accounts.pop()!]; const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'}); - + await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId))).to.be.fulfilled; - + await expect(helper.signTransaction(nonAdmin, api.tx.appPromotion.stopSponsoringCollection(collection.collectionId))).to.be.rejected; expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress}); }); - + itSub('should set sponsoring as disabled', async ({helper}) => { const api = helper.getApi(); const [collectionOwner, recepient] = [accounts.pop()!, accounts.pop()!]; const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits: {sponsorTransferTimeout: 0}}); const token = await collection.mintToken(collectionOwner, {Substrate: collectionOwner.address}); - + await helper.signTransaction(palletAdmin, api.tx.appPromotion.sponsorCollection(collection.collectionId)); await helper.signTransaction(palletAdmin, api.tx.appPromotion.stopSponsoringCollection(collection.collectionId)); - + expect((await collection.getData())?.raw.sponsorship).to.be.equal('Disabled'); - + // Transactions are not sponsored anymore: const ownerBalanceBefore = await helper.balance.getSubstrate(collectionOwner.address); await token.transfer(collectionOwner, {Substrate: recepient.address}); const ownerBalanceAfter = await helper.balance.getSubstrate(collectionOwner.address); expect(ownerBalanceAfter < ownerBalanceBefore).to.be.equal(true); }); - + itSub('should not affect collection which is not sponsored by pallete', async ({helper}) => { const api = helper.getApi(); const collectionOwner = accounts.pop()!; const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: collectionOwner.address}); await collection.confirmSponsorship(collectionOwner); - + await expect(helper.signTransaction(palletAdmin, api.tx.appPromotion.stopSponsoringCollection(collection.collectionId))).to.be.rejected; - + expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: collectionOwner.address}); }); - - itSub('should reject transaction if collection does not exist', async ({helper}) => { + + itSub('should reject transaction if collection does not exist', async ({helper}) => { const collectionOwner = accounts.pop()!; const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'}); - + await collection.burn(collectionOwner); await expect(helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.stopSponsoringCollection', [collection.collectionId], true)).to.be.rejectedWith('common.CollectionNotFound'); await expect(helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.stopSponsoringCollection', [999_999_999], true)).to.be.rejectedWith('common.CollectionNotFound'); }); }); - + describe('contract sponsoring', () => { itEth('should set palletes address as a sponsor', async ({helper}) => { const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase(); const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner); - const contractHelper = helper.ethNativeContract.contractHelpers(contractOwner); - + const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner); + await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address]); - - expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true; - expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner); + + expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true; + expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner); expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({ confirmed: { substrate: palletAddress, }, }); }); - + itEth('should overwrite sponsoring mode and existed sponsor', async ({helper}) => { const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase(); const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner); - const contractHelper = helper.ethNativeContract.contractHelpers(contractOwner); - + const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner); + await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.fulfilled; - + // Contract is self sponsored expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.be.deep.equal({ confirmed: { ethereum: flipper.options.address.toLowerCase(), }, }); - + // set promotion sponsoring await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true); - + // new sponsor is pallet address - expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true; - expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner); + expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true; + expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner); expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({ confirmed: { substrate: palletAddress, }, }); }); - + itEth('can be overwritten by contract owner', async ({helper}) => { const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase(); const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner); - const contractHelper = helper.ethNativeContract.contractHelpers(contractOwner); - + const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner); + // contract sponsored by pallet await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true); - + // owner sets self sponsoring await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected; - - expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true; - expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner); + + expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.true; + expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner); expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({ confirmed: { ethereum: flipper.options.address.toLowerCase(), }, }); }); - + itEth('can not be set by non admin', async ({helper}) => { const nonAdmin = accounts.pop()!; const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase(); const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner); - const contractHelper = helper.ethNativeContract.contractHelpers(contractOwner); - + const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner); + await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.fulfilled; - + // nonAdmin calls sponsorContract await expect(helper.executeExtrinsic(nonAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true)).to.be.rejectedWith('appPromotion.NoPermission'); - - // contract still self-sponsored + + // contract still self-sponsored expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({ confirmed: { ethereum: flipper.options.address.toLowerCase(), }, }); }); - + itEth('should actually sponsor transactions', async ({helper}) => { // Contract caller const caller = await helper.eth.createAccountWithBalance(donor, 1000n); const palletBalanceBefore = await helper.balance.getSubstrate(palletAddress); - + // Deploy flipper const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase(); const flipper = await helper.eth.deployFlipper(contractOwner); // await deployFlipper(web3, contractOwner); - const contractHelper = helper.ethNativeContract.contractHelpers(contractOwner); - + const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner); + // Owner sets to sponsor every tx await contractHelper.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: contractOwner}); await contractHelper.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: contractOwner}); await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address, 1000n); // transferBalanceToEth(api, alice, flipper.options.address, 1000n); - + // Set promotion to the Flipper await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true); - + // Caller calls Flipper await flipper.methods.flip().send({from: caller}); expect(await flipper.methods.getValue().call()).to.be.true; - + // The contracts and caller balances have not changed const callerBalance = await helper.balance.getEthereum(caller); const contractBalanceAfter = await helper.balance.getEthereum(flipper.options.address); expect(callerBalance).to.be.equal(1000n * nominal); expect(1000n * nominal === contractBalanceAfter).to.be.true; - + // The pallet balance has decreased const palletBalanceAfter = await helper.balance.getSubstrate(palletAddress); expect(palletBalanceAfter < palletBalanceBefore).to.be.true; }); }); - - describe('stopSponsoringContract', () => { + + describe('stopSponsoringContract', () => { itEth('should remove pallet address from contract sponsors', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor, 1000n); const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase(); const flipper = await helper.eth.deployFlipper(contractOwner); await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address); - const contractHelper = helper.ethNativeContract.contractHelpers(contractOwner); - + const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner); + await contractHelper.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: contractOwner}); await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address], true); await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.stopSponsoringContract', [flipper.options.address], true); - - expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.false; - expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner); + + expect(await contractHelper.methods.hasSponsor(flipper.options.address).call()).to.be.false; + expect((await helper.callRpc('api.query.evmContractHelpers.owner', [flipper.options.address])).toJSON()).to.be.equal(contractOwner); expect((await helper.callRpc('api.query.evmContractHelpers.sponsoring', [flipper.options.address])).toJSON()).to.deep.equal({ disabled: null, }); - + await flipper.methods.flip().send({from: caller}); expect(await flipper.methods.getValue().call()).to.be.true; - + const callerBalance = await helper.balance.getEthereum(caller); const contractBalanceAfter = await helper.balance.getEthereum(flipper.options.address); - + // caller payed for call expect(1000n * nominal > callerBalance).to.be.true; expect(contractBalanceAfter).to.be.equal(100n * nominal); }); - + itEth('can not be called by non-admin', async ({helper}) => { const nonAdmin = accounts.pop()!; const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase(); const flipper = await helper.eth.deployFlipper(contractOwner); - + await helper.executeExtrinsic(palletAdmin, 'api.tx.appPromotion.sponsorContract', [flipper.options.address]); await expect(helper.executeExtrinsic(nonAdmin, 'api.tx.appPromotion.stopSponsoringContract', [flipper.options.address])) .to.be.rejectedWith(/appPromotion\.NoPermission/); }); - + itEth('should not affect a contract which is not sponsored by pallete', async ({helper}) => { const nonAdmin = accounts.pop()!; const contractOwner = (await helper.eth.createAccountWithBalance(donor, 1000n)).toLowerCase(); const flipper = await helper.eth.deployFlipper(contractOwner); - const contractHelper = helper.ethNativeContract.contractHelpers(contractOwner); + const contractHelper = await helper.ethNativeContract.contractHelpers(contractOwner); await expect(contractHelper.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.fulfilled; - + await expect(helper.executeExtrinsic(nonAdmin, 'api.tx.appPromotion.stopSponsoringContract', [flipper.options.address], true)).to.be.rejectedWith('appPromotion.NoPermission'); }); }); - - describe('rewards', () => { + + describe('payoutStakers', () => { itSub('can not be called by non admin', async ({helper}) => { const nonAdmin = accounts.pop()!; await expect(helper.admin.payoutStakers(nonAdmin, 100)).to.be.rejectedWith('appPromotion.NoPermission'); }); - + itSub('should increase total staked', async ({helper}) => { const staker = accounts.pop()!; const totalStakedBefore = await helper.staking.getTotalStaked(); await helper.staking.stake(staker, 100n * nominal); - + // Wait for rewards and pay const [stakedInBlock] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}); await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stakedInBlock.block)); const totalPayout = (await helper.admin.payoutStakers(palletAdmin, 100)).reduce((prev, payout) => prev + payout.payout, 0n); - + const totalStakedAfter = await helper.staking.getTotalStaked(); expect(totalStakedAfter).to.equal(totalStakedBefore + (100n * nominal) + totalPayout); // staker can unstake await helper.staking.unstake(staker); expect(await helper.staking.getTotalStaked()).to.be.equal(totalStakedAfter - calculateIncome(100n * nominal)); }); - - itSub('should credit 0.05% for staking period', async ({helper}) => { + + itSub('should credit 0.05% for staking period', async ({helper}) => { const staker = accounts.pop()!; - + await waitPromotionPeriodDoesntEnd(helper); - + await helper.staking.stake(staker, 100n * nominal); await helper.staking.stake(staker, 200n * nominal); - + // wait rewards are available: const [_stake1, stake2] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}); await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake2.block)); - + const payoutToStaker = (await helper.admin.payoutStakers(palletAdmin, 100)).find((payout) => payout.staker === staker.address)?.payout; expect(payoutToStaker + 300n * nominal).to.equal(calculateIncome(300n * nominal)); - + const totalStakedPerBlock = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}); - expect(totalStakedPerBlock[0].amount).to.equal(calculateIncome(100n * nominal)); - expect(totalStakedPerBlock[1].amount).to.equal(calculateIncome(200n * nominal)); + const income1 = calculateIncome(100n * nominal); + const income2 = calculateIncome(200n * nominal); + expect(totalStakedPerBlock[0].amount).to.equal(income1); + expect(totalStakedPerBlock[1].amount).to.equal(income2); + + const stakerBalance = await helper.balance.getSubstrateFull(staker.address); + expect(stakerBalance).to.contain({miscFrozen: income1 + income2, feeFrozen: income1 + income2, reserved: 0n}); + expect(stakerBalance.free / nominal).to.eq(999n); }); - + itSub('shoud be paid for more than one period if payments was missed', async ({helper}) => { const staker = accounts.pop()!; - + await helper.staking.stake(staker, 100n * nominal); // wait for two rewards are available: let [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}); await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD); - + await helper.admin.payoutStakers(palletAdmin, 100); [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}); const frozenBalanceShouldBe = calculateIncome(100n * nominal, 2); expect(stake.amount).to.be.equal(frozenBalanceShouldBe); - + const stakerFullBalance = await helper.balance.getSubstrateFull(staker.address); - + expect(stakerFullBalance).to.contain({reserved: 0n, feeFrozen: frozenBalanceShouldBe, miscFrozen: frozenBalanceShouldBe}); }); - + itSub('should not be credited for unstaked (reserved) balance', async ({helper}) => { // staker unstakes before rewards has been payed const staker = accounts.pop()!; @@ -598,37 +605,37 @@ describe('App promotion', () => { const [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}); await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD); await helper.staking.unstake(staker); - + // so he did not receive any rewards const totalBalanceBefore = await helper.balance.getSubstrate(staker.address); await helper.admin.payoutStakers(palletAdmin, 100); const totalBalanceAfter = await helper.balance.getSubstrate(staker.address); - + expect(totalBalanceBefore).to.be.equal(totalBalanceAfter); }); - + itSub('should bring compound interest', async ({helper}) => { const staker = accounts.pop()!; - + await helper.staking.stake(staker, 100n * nominal); - + let [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}); await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block)); - + await helper.admin.payoutStakers(palletAdmin, 100); [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}); expect(stake.amount).to.equal(calculateIncome(100n * nominal)); - + await helper.wait.forRelayBlockNumber(rewardAvailableInBlock(stake.block) + LOCKING_PERIOD); await helper.admin.payoutStakers(palletAdmin, 100); [stake] = await helper.staking.getTotalStakedPerBlock({Substrate: staker.address}); expect(stake.amount).to.equal(calculateIncome(100n * nominal, 2)); }); - + itSub.skip('can be paid 1000 rewards in a time', async ({helper}) => { // all other stakes should be unstaked const oneHundredStakers = await helper.arrange.createCrowd(100, 1050n, donor); - + // stakers stakes 10 times each for (let i = 0; i < 10; i++) { await Promise.all(oneHundredStakers.map(staker => helper.staking.stake(staker, 100n * nominal))); @@ -636,20 +643,20 @@ describe('App promotion', () => { await helper.wait.newBlocks(40); await helper.admin.payoutStakers(palletAdmin, 100); }); - + itSub.skip('can handle 40.000 rewards', async ({helper}) => { const crowdStakes = async () => { // each account in the crowd stakes 2 times const crowd = await helper.arrange.createCrowd(500, 300n, donor); await Promise.all(crowd.map(account => helper.staking.stake(account, 100n * nominal))); await Promise.all(crowd.map(account => helper.staking.stake(account, 100n * nominal))); - // + // }; - + for (let i = 0; i < 40; i++) { await crowdStakes(); } - + // TODO pay rewards for some period }); }); @@ -660,7 +667,7 @@ function calculateIncome(base: bigint, iter = 0, calcPeriod: bigint = UNLOCKING_ const ACCURACY = 1_000_000_000n; // 5n / 10_000n = 0.05% p/day const income = base + base * (ACCURACY * (calcPeriod * 5n) / (10_000n * DAY)) / ACCURACY ; - + if (iter > 1) { return calculateIncome(income, iter - 1, calcPeriod); } else return income; diff --git a/tests/src/approve.test.ts b/tests/src/approve.test.ts index f9891b688e..821e0fc20b 100644 --- a/tests/src/approve.test.ts +++ b/tests/src/approve.test.ts @@ -538,7 +538,7 @@ describe('Negative Integration Test approve(spender, collection_id, item_id, amo const approveTx = () => helper.rft.approveToken(alice, collectionId, 1, {Substrate: bob.address}); await expect(approveTx()).to.be.rejected; }); - + itSub('[nft] Approve transfer of a token that does not exist', async ({helper}) => { const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); const approveTx = () => helper.nft.approveToken(alice, collectionId, 2, {Substrate: bob.address}); @@ -603,3 +603,45 @@ describe('Negative Integration Test approve(spender, collection_id, item_id, amo await expect(approveTx()).to.be.rejected; }); }); + +describe('Normal user can approve other users to be wallet operator:', () => { + let alice: IKeyringPair; + let bob: IKeyringPair; + + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + const donor = await privateKey({filename: __filename}); + [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor); + }); + }); + + itSub('[nft] Enable and disable approval', async ({helper}) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + + const checkBeforeApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address}); + expect(checkBeforeApproval).to.be.false; + + await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true); + const checkAfterApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address}); + expect(checkAfterApproval).to.be.true; + + await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false); + const checkAfterDisapproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address}); + expect(checkAfterDisapproval).to.be.false; + }); + + itSub.ifWithPallets('[rft] Enable and disable approval', [Pallets.ReFungible], async ({helper}) => { + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + + const checkBeforeApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address}); + expect(checkBeforeApproval).to.be.false; + + await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true); + const checkAfterApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address}); + expect(checkAfterApproval).to.be.true; + + await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false); + const checkAfterDisapproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address}); + expect(checkAfterDisapproval).to.be.false; + }); +}); diff --git a/tests/src/benchmarks/mintFee/benchmark.ts b/tests/src/benchmarks/mintFee/benchmark.ts new file mode 100644 index 0000000000..f37d3c7bcd --- /dev/null +++ b/tests/src/benchmarks/mintFee/benchmark.ts @@ -0,0 +1,436 @@ +import {EthUniqueHelper, usingEthPlaygrounds} from '../../eth/util'; +import {readFile} from 'fs/promises'; +import {ContractImports} from '../../eth/util/playgrounds/types'; +import { + ICrossAccountId, + ITokenPropertyPermission, +} from '../../util/playgrounds/types'; +import {IKeyringPair} from '@polkadot/types/types'; +import {UniqueNFTCollection} from '../../util/playgrounds/unique'; +import {Contract} from 'web3-eth-contract'; +import {createObjectCsvWriter} from 'csv-writer'; + +const CONTRACT_IMPORT: ContractImports[] = [ + { + fsPath: `${__dirname}/../../eth/api/CollectionHelpers.sol`, + solPath: 'eth/api/CollectionHelpers.sol', + }, + { + fsPath: `${__dirname}/../../eth/api/ContractHelpers.sol`, + solPath: 'eth/api/ContractHelpers.sol', + }, + { + fsPath: `${__dirname}/../../eth/api/UniqueRefungibleToken.sol`, + solPath: 'eth/api/UniqueRefungibleToken.sol', + }, + { + fsPath: `${__dirname}/../../eth/api/UniqueRefungible.sol`, + solPath: 'eth/api/UniqueRefungible.sol', + }, + { + fsPath: `${__dirname}/../../eth/api/UniqueNFT.sol`, + solPath: 'eth/api/UniqueNFT.sol', + }, +]; + +const PROPERTIES = Array(40) + .fill(0) + .map((_, i) => { + return { + key: `key_${i}`, + value: Uint8Array.from(Buffer.from(`value_${i}`)), + }; + }); + +const PERMISSIONS: ITokenPropertyPermission[] = PROPERTIES.map((p) => { + return { + key: p.key, + permission: { + tokenOwner: true, + collectionAdmin: true, + mutable: true, + }, + }; +}); + +interface IBenchmarkResultForProp { + propertiesNumber: number; + substrateFee: number; + ethFee: number; + ethBulkFee: number; + evmProxyContractFee: number; + evmProxyContractBulkFee: number; +} + +const main = async () => { + const benchmarks = [ + 'substrateFee', + 'ethFee', + 'ethBulkFee', + 'evmProxyContractFee', + 'evmProxyContractBulkFee', + ]; + const headers = [ + 'propertiesNumber', + ...benchmarks, + ]; + + + const csvWriter = createObjectCsvWriter({ + path: 'properties.csv', + header: headers, + }); + + await usingEthPlaygrounds(async (helper, privateKey) => { + const CONTRACT_SOURCE = ( + await readFile(`${__dirname}/proxyContract.sol`) + ).toString(); + + const donor = await privateKey('//Alice'); // Seed from account with balance on this network + const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n); + + const contract = await helper.ethContract.deployByCode( + ethSigner, + 'ProxyMint', + CONTRACT_SOURCE, + CONTRACT_IMPORT, + ); + + const fees = await benchMintFee(helper, privateKey, contract); + console.log('Minting without properties'); + console.table(fees); + + const result: IBenchmarkResultForProp[] = []; + const csvResult: IBenchmarkResultForProp[] = []; + + for (let i = 1; i <= 20; i++) { + const benchResult = await benchMintWithProperties(helper, privateKey, contract, { + propertiesNumber: i, + }) as any; + + csvResult.push(benchResult); + + const minFee = Math.min(...(benchmarks.map(x => benchResult[x]))); + for(const key of benchmarks) { + const keyPercent = Math.round((benchResult[key] / minFee) * 100); + benchResult[key] = `${benchResult[key]} (${keyPercent}%)`; + } + + result.push(benchResult); + } + + await csvWriter.writeRecords(csvResult); + + console.log('Minting with properties'); + console.table(result, headers); + }); +}; + +main() + .then(() => process.exit(0)) + .catch((e) => { + console.log(e); + process.exit(1); + }); + +async function createCollectionForBenchmarks( + helper: EthUniqueHelper, + privateKey: (seed: string) => Promise, + ethSigner: string, + proxyContract: string, + permissions: ITokenPropertyPermission[], +) { + const donor = await privateKey('//Alice'); + + const collection = await helper.nft.mintCollection(donor, { + name: 'test mintToSubstrate', + description: 'EVMHelpers', + tokenPrefix: 'ap', + tokenPropertyPermissions: [ + { + key: 'url', + permission: { + tokenOwner: true, + collectionAdmin: true, + mutable: true, + }, + }, + ], + limits: {sponsorTransferTimeout: 0, sponsorApproveTimeout: 0}, + permissions: {mintMode: true}, + }); + + await collection.addToAllowList(donor, { + Ethereum: helper.address.substrateToEth(donor.address), + }); + await collection.addToAllowList(donor, {Substrate: donor.address}); + await collection.addAdmin(donor, {Ethereum: ethSigner}); + await collection.addAdmin(donor, { + Ethereum: helper.address.substrateToEth(donor.address), + }); + await collection.addToAllowList(donor, {Ethereum: proxyContract}); + await collection.addAdmin(donor, {Ethereum: proxyContract}); + await collection.setTokenPropertyPermissions(donor, permissions); + + return collection; +} + +async function benchMintFee( + helper: EthUniqueHelper, + privateKey: (seed: string) => Promise, + proxyContract: Contract, +): Promise<{ + substrateFee: number; + ethFee: number; + evmProxyContractFee: number; +}> { + const donor = await privateKey('//Alice'); + const substrateReceiver = await privateKey('//Bob'); + const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n); + + const nominal = helper.balance.getOneTokenNominal(); + + await helper.eth.transferBalanceFromSubstrate( + donor, + proxyContract.options.address, + 100n, + ); + + const collection = await createCollectionForBenchmarks( + helper, + privateKey, + ethSigner, + proxyContract.options.address, + PERMISSIONS, + ); + + const substrateFee = await helper.arrange.calculcateFee( + {Substrate: donor.address}, + () => collection.mintToken(donor, {Substrate: substrateReceiver.address}), + ); + + const collectionEthAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionContract = await helper.ethNativeContract.collection( + collectionEthAddress, + 'nft', + ); + + const receiverEthAddress = helper.address.substrateToEth(substrateReceiver.address); + + const encodedCall = collectionContract.methods + .mint(receiverEthAddress) + .encodeABI(); + + const ethFee = await helper.arrange.calculcateFee( + {Substrate: donor.address}, + async () => { + await helper.eth.sendEVM( + donor, + collectionContract.options.address, + encodedCall, + '0', + ); + }, + ); + + const evmProxyContractFee = await helper.arrange.calculcateFee( + {Ethereum: ethSigner}, + async () => { + await proxyContract.methods + .mintToSubstrate( + helper.ethAddress.fromCollectionId(collection.collectionId), + substrateReceiver.addressRaw, + ) + .send({from: ethSigner}); + }, + ); + + return { + substrateFee: convertToTokens(substrateFee, nominal), + ethFee: convertToTokens(ethFee, nominal), + evmProxyContractFee: convertToTokens(evmProxyContractFee, nominal), + }; +} + +async function benchMintWithProperties( + helper: EthUniqueHelper, + privateKey: (seed: string) => Promise, + proxyContract: Contract, + setup: { propertiesNumber: number }, +): Promise { + const donor = await privateKey('//Alice'); // Seed from account with balance on this network + const ethSigner = await helper.eth.createAccountWithBalance(donor, 100n); + + const susbstrateReceiver = await privateKey('//Bob'); + const receiverEthAddress = helper.address.substrateToEth(susbstrateReceiver.address); + + const nominal = helper.balance.getOneTokenNominal(); + + const substrateFee = await calculateFeeNftMintWithProperties( + helper, + privateKey, + {Substrate: donor.address}, + ethSigner, + proxyContract.options.address, + async (collection) => { + await collection.mintToken( + donor, + {Substrate: susbstrateReceiver.address}, + PROPERTIES.slice(0, setup.propertiesNumber).map((p) => { + return {key: p.key, value: Buffer.from(p.value).toString()}; + }), + ); + }, + ); + + const ethFee = await calculateFeeNftMintWithProperties( + helper, + privateKey, + {Substrate: donor.address}, + ethSigner, + proxyContract.options.address, + async (collection) => { + const evmContract = await helper.ethNativeContract.collection( + helper.ethAddress.fromCollectionId(collection.collectionId), + 'nft', + ); + + const subTokenId = await evmContract.methods.nextTokenId().call(); + + let encodedCall = evmContract.methods + .mint(receiverEthAddress) + .encodeABI(); + + await helper.eth.sendEVM( + donor, + evmContract.options.address, + encodedCall, + '0', + ); + + for (const val of PROPERTIES.slice(0, setup.propertiesNumber)) { + encodedCall = await evmContract.methods + .setProperty(subTokenId, val.key, Buffer.from(val.value)) + .encodeABI(); + + await helper.eth.sendEVM( + donor, + evmContract.options.address, + encodedCall, + '0', + ); + } + }, + ); + + const ethBulkFee = await calculateFeeNftMintWithProperties( + helper, + privateKey, + {Substrate: donor.address}, + ethSigner, + proxyContract.options.address, + async (collection) => { + const evmContract = await helper.ethNativeContract.collection( + helper.ethAddress.fromCollectionId(collection.collectionId), + 'nft', + ); + + const subTokenId = await evmContract.methods.nextTokenId().call(); + + let encodedCall = evmContract.methods + .mint(receiverEthAddress) + .encodeABI(); + + await helper.eth.sendEVM( + donor, + evmContract.options.address, + encodedCall, + '0', + ); + + encodedCall = await evmContract.methods + .setProperties( + subTokenId, + PROPERTIES.slice(0, setup.propertiesNumber).map((p) => { + return {field_0: p.key, field_1: p.value}; + }), + ) + .encodeABI(); + + await helper.eth.sendEVM( + donor, + evmContract.options.address, + encodedCall, + '0', + ); + }, + ); + + const proxyContractFee = await calculateFeeNftMintWithProperties( + helper, + privateKey, + {Ethereum: ethSigner}, + ethSigner, + proxyContract.options.address, + async (collection) => { + await proxyContract.methods + .mintToSubstrateWithProperty( + helper.ethAddress.fromCollectionId(collection.collectionId), + susbstrateReceiver.addressRaw, + PROPERTIES.slice(0, setup.propertiesNumber), + ) + .send({from: ethSigner}); + }, + ); + + const proxyContractBulkFee = await calculateFeeNftMintWithProperties( + helper, + privateKey, + {Ethereum: ethSigner}, + ethSigner, + proxyContract.options.address, + async (collection) => { + await proxyContract.methods + .mintToSubstrateBulkProperty( + helper.ethAddress.fromCollectionId(collection.collectionId), + susbstrateReceiver.addressRaw, + PROPERTIES.slice(0, setup.propertiesNumber).map((p) => { + return {field_0: p.key, field_1: p.value}; + }), + ) + .send({from: ethSigner, gas: 25_000_000}); + }, + ); + + return { + propertiesNumber: setup.propertiesNumber, + substrateFee: convertToTokens(substrateFee, nominal), + ethFee: convertToTokens(ethFee, nominal), + ethBulkFee: convertToTokens(ethBulkFee, nominal), + evmProxyContractFee: convertToTokens(proxyContractFee, nominal), + evmProxyContractBulkFee: convertToTokens(proxyContractBulkFee, nominal), + }; +} + +async function calculateFeeNftMintWithProperties( + helper: EthUniqueHelper, + privateKey: (seed: string) => Promise, + payer: ICrossAccountId, + ethSigner: string, + proxyContractAddress: string, + calculatedCall: (collection: UniqueNFTCollection) => Promise, +): Promise { + const collection = await createCollectionForBenchmarks( + helper, + privateKey, + ethSigner, + proxyContractAddress, + PERMISSIONS, + ); + return helper.arrange.calculcateFee(payer, async () => { + await calculatedCall(collection); + }); +} +function convertToTokens(value: bigint, nominal: bigint): number { + return Number((value * 1000n) / nominal) / 1000; +} diff --git a/tests/src/benchmarks/mintFee/proxyContract.sol b/tests/src/benchmarks/mintFee/proxyContract.sol new file mode 100644 index 0000000000..7ef569068a --- /dev/null +++ b/tests/src/benchmarks/mintFee/proxyContract.sol @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: Apache License +pragma solidity >=0.8.0; +import {CollectionHelpers} from "../../eth/api/CollectionHelpers.sol"; +import {ContractHelpers} from "../../eth/api/ContractHelpers.sol"; +import {UniqueRefungibleToken} from "../../eth/api/UniqueRefungibleToken.sol"; +import {UniqueRefungible, Collection, EthCrossAccount as RftCrossAccountId, Tuple20 as RftProperties} from "../../eth/api/UniqueRefungible.sol"; +import {UniqueNFT, EthCrossAccount as NftCrossAccountId, Tuple21 as NftProperty, TokenProperties} from "../../eth/api/UniqueNFT.sol"; + +struct Property { + string key; + bytes value; +} + +contract ProxyMint { + bytes32 constant REFUNGIBLE_COLLECTION_TYPE = keccak256(bytes("ReFungible")); + bytes32 constant NONFUNGIBLE_COLLECTION_TYPE = keccak256(bytes("NFT")); + + modifier checkRestrictions(address _collection) { + Collection commonContract = Collection(_collection); + require(commonContract.isOwnerOrAdmin(msg.sender), "Only collection admin/owner can call this method"); + _; + } + + /// @dev This emits when a mint to a substrate address has been made. + event MintToSub(address _toEth, uint256 _toSub, address _collection, uint256 _tokenId); + + function mintToSubstrate(address _collection, uint256 _substrateReceiver) external checkRestrictions(_collection) { + Collection commonContract = Collection(_collection); + bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType())); + uint256 tokenId; + + if (collectionType == REFUNGIBLE_COLLECTION_TYPE) { + UniqueRefungible rftCollection = UniqueRefungible(_collection); + + tokenId = rftCollection.mint(address(this)); + + rftCollection.transferFromCross( + RftCrossAccountId(address(this), 0), + RftCrossAccountId(address(0), _substrateReceiver), + tokenId + ); + } else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) { + UniqueNFT nftCollection = UniqueNFT(_collection); + tokenId = nftCollection.mint(address(this)); + + nftCollection.transferFromCross( + NftCrossAccountId(address(this), 0), + NftCrossAccountId(address(0), _substrateReceiver), + tokenId + ); + } else { + revert("Wrong collection type. Works only with NFT or RFT"); + } + + emit MintToSub(address(0), _substrateReceiver, _collection, tokenId); + } + + function mintToSubstrateWithProperty( + address _collection, + uint256 _substrateReceiver, + Property[] calldata properties + ) external checkRestrictions(_collection) { + uint256 propertiesLength = properties.length; + require(propertiesLength > 0, "Properies is empty"); + + Collection commonContract = Collection(_collection); + bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType())); + uint256 tokenId; + + if (collectionType == REFUNGIBLE_COLLECTION_TYPE) { + UniqueRefungible rftCollection = UniqueRefungible(_collection); + tokenId = rftCollection.nextTokenId(); + rftCollection.mint(address(this)); + for (uint256 i = 0; i < propertiesLength; ++i) { + rftCollection.setProperty(tokenId, properties[i].key, properties[i].value); + } + rftCollection.transferFromCross( + RftCrossAccountId(address(this), 0), + RftCrossAccountId(address(0), _substrateReceiver), + tokenId + ); + } else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) { + UniqueNFT nftCollection = UniqueNFT(_collection); + tokenId = nftCollection.mint(address(this)); + for (uint256 i = 0; i < propertiesLength; ++i) { + nftCollection.setProperty(tokenId, properties[i].key, properties[i].value); + } + nftCollection.transferFromCross( + NftCrossAccountId(address(this), 0), + NftCrossAccountId(address(0), _substrateReceiver), + tokenId + ); + } else { + revert("Wrong collection type. Works only with NFT or RFT"); + } + + emit MintToSub(address(0), _substrateReceiver, _collection, tokenId); + } + + function mintToSubstrateBulkProperty( + address _collection, + uint256 _substrateReceiver, + NftProperty[] calldata _properties + ) external checkRestrictions(_collection) { + uint256 propertiesLength = _properties.length; + require(propertiesLength > 0, "Properies is empty"); + + Collection commonContract = Collection(_collection); + bytes32 collectionType = keccak256(bytes(commonContract.uniqueCollectionType())); + uint256 tokenId; + + if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {} else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) { + UniqueNFT nftCollection = UniqueNFT(_collection); + tokenId = nftCollection.mint(address(this)); + + nftCollection.setProperties(tokenId, _properties); + + nftCollection.transferFromCross( + NftCrossAccountId(address(this), 0), + NftCrossAccountId(address(0), _substrateReceiver), + tokenId + ); + } else { + revert("Wrong collection type. Works only with NFT or RFT"); + } + + emit MintToSub(address(0), _substrateReceiver, _collection, tokenId); + } +} diff --git a/tests/src/block-production.test.ts b/tests/src/block-production.seqtest.ts similarity index 100% rename from tests/src/block-production.test.ts rename to tests/src/block-production.seqtest.ts diff --git a/tests/src/burnItem.test.ts b/tests/src/burnItem.test.ts index a3f330f985..d28b698901 100644 --- a/tests/src/burnItem.test.ts +++ b/tests/src/burnItem.test.ts @@ -185,7 +185,7 @@ describe('Negative integration test: ext. burnItem():', () => { const collection = await helper.nft.mintCollection(alice, {name: 'Coll', description: 'Desc', tokenPrefix: 'T'}); const tokenAlice = await collection.mintToken(alice, {Substrate: alice.address}); const tokenBob = await collection.mintToken(alice, {Substrate: bob.address}); - + // 1. Zero burn of own tokens allowed: await helper.executeExtrinsic(alice, 'api.tx.unique.burnItem', [collection.collectionId, tokenAlice.tokenId, 0]); // 2. Zero burn of non-owned tokens not allowed: diff --git a/tests/src/calibrate.ts b/tests/src/calibrate.ts index 390a7b4e8d..8eff159aab 100644 --- a/tests/src/calibrate.ts +++ b/tests/src/calibrate.ts @@ -1,59 +1,186 @@ import {IKeyringPair} from '@polkadot/types/types'; - import {usingEthPlaygrounds, EthUniqueHelper} from './eth/util'; +class Fract { + static ZERO = new Fract(0n); + constructor(public readonly a: bigint, public readonly b: bigint = 1n) { + if (b === 0n) throw new Error('division by zero'); + if (b < 0n) throw new Error('missing normalization'); + } -function linearRegression(points: { x: bigint, y: bigint }[]) { - let sumxy = 0n; - let sumx = 0n; - let sumy = 0n; - let sumx2 = 0n; - const n = points.length; - for (let i = 0; i < n; i++) { - const p = points[i]; - sumxy += p.x * p.y; - sumx += p.x; - sumy += p.y; - sumx2 += p.x * p.x; + mul(other: Fract) { + return new Fract(this.a * other.a, this.b * other.b).optimize(); } - const nb = BigInt(n); + div(other: Fract) { + return this.mul(other.inv()); + } - const a = (nb * sumxy - sumx * sumy) / (nb * sumx2 - sumx * sumx); - const b = (sumy - a * sumx) / nb; + plus(other: Fract) { + if (this.b === other.b) { + return new Fract(this.a + other.a, this.b); + } + return new Fract(this.a * other.b + other.a * this.b, this.b * other.b).optimize(); + } - return {a, b}; -} + minus(other: Fract) { + return this.plus(other.neg()); + } + + neg() { + return new Fract(-this.a, this.b); + } + inv() { + if (this.a < 0) { + return new Fract(-this.b, -this.a); + } else { + return new Fract(this.b, this.a); + } + } + + optimize() { + function gcd(x: bigint, y: bigint) { + if (x < 0n) + x = -x; + if (y < 0n) + y = -y; + while(y) { + const t = y; + y = x % y; + x = t; + } + return x; + } + const v = gcd(this.a, this.b); + return new Fract(this.a / v, this.b / v); + } + + toBigInt() { + return this.a / this.b; + } + toNumber() { + const v = this.optimize(); + return Number(v.a) / Number(v.b); + } + toString() { + const v = this.optimize(); + return `${v.a} / ${v.b}`; + } -// JS has no builtin function to calculate sqrt of bigint -// https://stackoverflow.com/a/53684036/6190169 -function sqrt(value: bigint) { - if (value < 0n) { - throw 'square root of negative numbers is not supported'; + lt(other: Fract) { + return this.a * other.b < other.a * this.b; } + eq(other: Fract) { + return this.a * other.b === other.a * this.b; + } + + sqrt() { + if (this.a < 0n) { + throw 'square root of negative numbers is not supported'; + } - if (value < 2n) { - return value; + if (this.lt(new Fract(2n))) { + return this; + } + + function newtonIteration(n: Fract, x0: Fract): Fract { + const x1 = rpn(n, x0, '/', x0, '+', new Fract(2n), '/'); + if (x0.eq(x1) || x0.eq(x1.minus(new Fract(1n)))) { + return x0; + } + return newtonIteration(n, x1); + } + + return newtonIteration(this, new Fract(1n)); } +} - function newtonIteration(n: bigint, x0: bigint): bigint { - const x1 = ((n / x0) + x0) >> 1n; - if (x0 === x1 || x0 === (x1 - 1n)) { - return x0; +type Op = Fract | '+' | '-' | '*' | '/' | 'dup' | Op[]; +function rpn(...ops: (Op)[]) { + const stack: Fract[] = []; + for (const op of ops) { + if (op instanceof Fract) { + stack.push(op); + } else if (op === '+') { + if (stack.length < 2) + throw new Error('stack underflow'); + const b = stack.pop()!; + const a = stack.pop()!; + stack.push(a.plus(b)); + } else if (op === '*') { + if (stack.length < 2) + throw new Error('stack underflow'); + const b = stack.pop()!; + const a = stack.pop()!; + stack.push(a.mul(b)); + } else if (op === '-') { + if (stack.length < 2) + throw new Error('stack underflow'); + const b = stack.pop()!; + const a = stack.pop()!; + stack.push(a.minus(b)); + } else if (op === '/') { + if (stack.length < 2) + throw new Error('stack underflow'); + const b = stack.pop()!; + const a = stack.pop()!; + stack.push(a.div(b)); + } else if (op === 'dup') { + if (stack.length < 1) + throw new Error('stack underflow'); + const a = stack.pop()!; + stack.push(a); + stack.push(a); + } else if (Array.isArray(op)) { + stack.push(rpn(...op)); + } else { + throw new Error(`unknown operand: ${op}`); } - return newtonIteration(n, x1); + } + if (stack.length != 1) + throw new Error('one element should be left on stack'); + return stack[0]!; +} + +function linearRegression(points: { x: Fract, y: Fract }[]) { + let sumxy = Fract.ZERO; + let sumx = Fract.ZERO; + let sumy = Fract.ZERO; + let sumx2 = Fract.ZERO; + const n = points.length; + for (let i = 0; i < n; i++) { + const p = points[i]; + sumxy = rpn(p.x, p.y, '*', sumxy, '+'); + sumx = sumx.plus(p.x); + sumy = sumy.plus(p.y); + sumx2 = rpn(p.x, p.x, '*', sumx2, '+'); } - return newtonIteration(value, 1n); + const nb = new Fract(BigInt(n)); + + const a = rpn( + [nb, sumxy, '*', sumx, sumy, '*', '-'], + [nb, sumx2, '*', sumx, sumx, '*', '-'], + '/', + ); + const b = rpn( + [sumy, a, sumx, '*', '-'], + nb, + '/', + ); + + return {a, b}; } -function _error(points: { x: bigint, y: bigint }[], hypothesis: (a: bigint) => bigint) { - return sqrt(points.map(p => { +const hypothesisLinear = (a: Fract, b: Fract) => (x: Fract) => rpn(x, a, '*', b, '+'); + +function _error(points: { x: Fract, y: Fract }[], hypothesis: (a: Fract) => Fract) { + return points.map(p => { const v = hypothesis(p.x); const vv = p.y; - return (v - vv) ** 2n; - }).reduce((a, b) => a + b, 0n) / BigInt(points.length)); + return rpn(v, vv, '-', 'dup', '*'); + }).reduce((a, b) => a.plus(b), Fract.ZERO).sqrt().div(new Fract(BigInt(points.length))); } async function calibrateWeightToFee(helper: EthUniqueHelper, privateKey: (account: string) => Promise) { @@ -68,15 +195,15 @@ async function calibrateWeightToFee(helper: EthUniqueHelper, privateKey: (accoun await token.transfer(alice, {Substrate: bob.address}); const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address); - console.log(`Original price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`); + console.log(`\t[NFT transfer] Original price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`); } const api = helper.getApi(); - const defaultCoeff = (api.consts.configuration.defaultWeightToFeeCoefficient as any).toBigInt(); + const base = (await api.query.configuration.weightToFeeCoefficientOverride() as any).toBigInt(); for (let i = -5; i < 5; i++) { - await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(defaultCoeff + defaultCoeff / 1000n * BigInt(i)))); + await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(base + base / 1000n * BigInt(i)))); - const coefficient = (await api.query.configuration.weightToFeeCoefficientOverride() as any).toBigInt(); + const coefficient = new Fract((await api.query.configuration.weightToFeeCoefficientOverride() as any).toBigInt()); const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'}); const token = await collection.mintToken(alice, {Substrate: alice.address}); @@ -84,16 +211,18 @@ async function calibrateWeightToFee(helper: EthUniqueHelper, privateKey: (accoun await token.transfer(alice, {Substrate: bob.address}); const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address); - const transferPrice = aliceBalanceBefore - aliceBalanceAfter; + const transferPrice = new Fract(aliceBalanceBefore - aliceBalanceAfter); dataPoints.push({x: transferPrice, y: coefficient}); } const {a, b} = linearRegression(dataPoints); - // console.log(`Error: ${error(dataPoints, x => a*x+b)}`); + const hyp = hypothesisLinear(a, b); + // console.log(`\t[NFT transfer] Error: ${_error(dataPoints, hyp).toNumber()}`); - const perfectValue = a * helper.balance.getOneTokenNominal() / 10n + b; - await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(perfectValue.toString()))); + // 0.1 UNQ + const perfectValue = hyp(rpn(new Fract(helper.balance.getOneTokenNominal()), new Fract(1n, 10n), '*')); + await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setWeightToFeeCoefficientOverride(perfectValue.toBigInt()))); { const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'}); @@ -102,7 +231,7 @@ async function calibrateWeightToFee(helper: EthUniqueHelper, privateKey: (accoun await token.transfer(alice, {Substrate: bob.address}); const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address); - console.log(`Calibrated price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`); + console.log(`\t[NFT transfer] Calibrated price: ${Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal())} UNQ`); } } @@ -117,61 +246,72 @@ async function calibrateMinGasPrice(helper: EthUniqueHelper, privateKey: (accoun const token = await collection.mintToken(alice, {Ethereum: caller}); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'nft', caller); + const contract = await helper.ethNativeContract.collection(address, 'nft', caller); const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gas: helper.eth.DEFAULT_GAS})); - console.log(`Original price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`); + console.log(`\t[ETH NFT transfer] Original price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`); } const api = helper.getApi(); - const defaultCoeff = (api.consts.configuration.defaultMinGasPrice as any).toBigInt(); + // const defaultCoeff = (api.consts.configuration.defaultMinGasPrice as any).toBigInt(); + const base = (await api.query.configuration.minGasPriceOverride() as any).toBigInt(); for (let i = -8; i < 8; i++) { - const gasPrice = defaultCoeff + defaultCoeff / 100000n * BigInt(i); + const gasPrice = base + base / 100000n * BigInt(i); const gasPriceStr = '0x' + gasPrice.toString(16); await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(gasPrice))); - const coefficient = (await api.query.configuration.minGasPriceOverride() as any).toBigInt(); + const coefficient = new Fract((await api.query.configuration.minGasPriceOverride() as any).toBigInt()); const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'}); const token = await collection.mintToken(alice, {Ethereum: caller}); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'nft', caller); + const contract = await helper.ethNativeContract.collection(address, 'nft', caller); - const transferPrice = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gasPrice: gasPriceStr, gas: helper.eth.DEFAULT_GAS})); + const transferPrice = new Fract(await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gasPrice: gasPriceStr, gas: helper.eth.DEFAULT_GAS}))); dataPoints.push({x: transferPrice, y: coefficient}); } const {a, b} = linearRegression(dataPoints); - // console.log(`Error: ${error(dataPoints, x => a*x+b)}`); + const hyp = hypothesisLinear(a, b); + // console.log(`\t[ETH NFT transfer] Error: ${_error(dataPoints, hyp).toNumber()}`); - // * 0.15 = * 10000 / 66666 - const perfectValue = a * helper.balance.getOneTokenNominal() * 1000000n / 6666666n + b; - await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(perfectValue.toString()))); + // 0.15 UNQ + const perfectValue = hyp(rpn(new Fract(helper.balance.getOneTokenNominal()), new Fract(15n, 100n), '*')); + await helper.signTransaction(alice, api.tx.sudo.sudo(api.tx.configuration.setMinGasPriceOverride(perfectValue.toBigInt()))); { const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New collection', tokenPrefix: 'NEW'}); const token = await collection.mintToken(alice, {Ethereum: caller}); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'nft', caller); + const contract = await helper.ethNativeContract.collection(address, 'nft', caller); const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, token.tokenId).send({from: caller, gas: helper.eth.DEFAULT_GAS})); - console.log(`Calibrated price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`); + console.log(`\t[ETH NFT transfer] Calibrated price: ${Number(cost) / Number(helper.balance.getOneTokenNominal())} UNQ`); } } +// eslint-disable-next-line @typescript-eslint/no-floating-promises (async () => { await usingEthPlaygrounds(async (helper: EthUniqueHelper, privateKey) => { - // Second run slightly reduces error sometimes, as price line is not actually straight, this is a curve + // Subsequent runs reduce error, as price line is not actually straight, this is a curve + + const iterations = 3; - await calibrateWeightToFee(helper, privateKey); - await calibrateWeightToFee(helper, privateKey); + console.log('[Calibrate WeightToFee]'); + for (let i = 0; i < iterations; i++) { + await calibrateWeightToFee(helper, privateKey); + } - await calibrateMinGasPrice(helper, privateKey); - await calibrateMinGasPrice(helper, privateKey); + console.log(); + + console.log('[Calibrate MinGasPrice]'); + for (let i = 0; i < iterations; i++) { + await calibrateMinGasPrice(helper, privateKey); + } }); })(); diff --git a/tests/src/calibrateApply.ts b/tests/src/calibrateApply.ts index b6566ad7db..f12508ca8c 100644 --- a/tests/src/calibrateApply.ts +++ b/tests/src/calibrateApply.ts @@ -1,6 +1,6 @@ import {readFile, writeFile} from 'fs/promises'; import path from 'path'; -import usingApi from './substrate/substrate-api'; +import usingApi from './.outdated/substrate/substrate-api'; const formatNumber = (num: string): string => num.split('').reverse().join('').replace(/([0-9]{3})/g, '$1_').split('').reverse().join('').replace(/^_/, ''); diff --git a/tests/src/change-collection-owner.test.ts b/tests/src/change-collection-owner.test.ts index 78a860bdc4..41facf0c0b 100644 --- a/tests/src/change-collection-owner.test.ts +++ b/tests/src/change-collection-owner.test.ts @@ -146,7 +146,7 @@ describe('Negative Integration Test changeCollectionOwner(collection_id, new_own const confirmSponsorshipTx = () => collection.confirmSponsorship(alice); const removeSponsorTx = () => collection.removeSponsor(alice); await expect(setSponsorTx()).to.be.rejectedWith(/common\.NoPermission/); - await expect(confirmSponsorshipTx()).to.be.rejectedWith(/unique\.ConfirmUnsetSponsorFail/); + await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/); await expect(removeSponsorTx()).to.be.rejectedWith(/common\.NoPermission/); const limits = { diff --git a/tests/src/config.ts b/tests/src/config.ts index a6ac6b9755..e5247cee22 100644 --- a/tests/src/config.ts +++ b/tests/src/config.ts @@ -25,6 +25,8 @@ const config = { moonbeamUrl: process.env.moonbeamUrl || 'ws://127.0.0.1:9947', moonriverUrl: process.env.moonbeamUrl || 'ws://127.0.0.1:9947', westmintUrl: process.env.westmintUrl || 'ws://127.0.0.1:9948', + statemineUrl: process.env.statemineUrl || 'ws://127.0.0.1:9948', + statemintUrl: process.env.statemintUrl || 'ws://127.0.0.1:9948', }; export default config; diff --git a/tests/src/confirmSponsorship.test.ts b/tests/src/confirmSponsorship.test.ts index 76fea53d6b..85d91c101e 100644 --- a/tests/src/confirmSponsorship.test.ts +++ b/tests/src/confirmSponsorship.test.ts @@ -207,14 +207,14 @@ describe('(!negative test!) integration test: ext. confirmSponsorship():', () => const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); await collection.setSponsor(alice, bob.address); const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie); - await expect(confirmSponsorshipTx()).to.be.rejectedWith(/unique\.ConfirmUnsetSponsorFail/); + await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/); }); itSub('(!negative test!) Confirm sponsorship using owner address', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); await collection.setSponsor(alice, bob.address); const confirmSponsorshipTx = () => collection.confirmSponsorship(alice); - await expect(confirmSponsorshipTx()).to.be.rejectedWith(/unique\.ConfirmUnsetSponsorFail/); + await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/); }); itSub('(!negative test!) Confirm sponsorship by collection admin', async ({helper}) => { @@ -222,13 +222,13 @@ describe('(!negative test!) integration test: ext. confirmSponsorship():', () => await collection.setSponsor(alice, bob.address); await collection.addAdmin(alice, {Substrate: charlie.address}); const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie); - await expect(confirmSponsorshipTx()).to.be.rejectedWith(/unique\.ConfirmUnsetSponsorFail/); + await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/); }); itSub('(!negative test!) Confirm sponsorship without sponsor being set with setCollectionSponsor', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie); - await expect(confirmSponsorshipTx()).to.be.rejectedWith(/unique\.ConfirmUnsetSponsorFail/); + await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/); }); itSub('(!negative test!) Confirm sponsorship in a collection that was destroyed', async ({helper}) => { diff --git a/tests/src/createCollection.test.ts b/tests/src/createCollection.test.ts index b57984a387..e3ce6208fa 100644 --- a/tests/src/createCollection.test.ts +++ b/tests/src/createCollection.test.ts @@ -127,7 +127,7 @@ describe('(!negative test!) integration test: ext. createCollection():', () => { const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'A'.repeat(17)}); await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error'); }); - + itSub('(!negative test!) fails when bad limits are set', async ({helper}) => { const mintCollectionTx = () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL', limits: {tokenLimit: 0}}); await expect(mintCollectionTx()).to.be.rejectedWith(/common\.CollectionTokenLimitExceeded/); diff --git a/tests/src/createMultipleItems.test.ts b/tests/src/createMultipleItems.test.ts index e91eed376e..6bbfc79ffb 100644 --- a/tests/src/createMultipleItems.test.ts +++ b/tests/src/createMultipleItems.test.ts @@ -272,8 +272,8 @@ describe('Negative Integration Test createMultipleItems(collection_id, owner, it const types = ['NFT', 'Fungible', 'ReFungible']; await expect(helper.executeExtrinsic( - alice, - 'api.tx.unique.createMultipleItems', + alice, + 'api.tx.unique.createMultipleItems', [collectionId, {Substrate: alice.address}, types], )).to.be.rejectedWith(/nonfungible\.NotNonfungibleDataUsedToMintFungibleCollectionToken/); }); diff --git a/tests/src/eth/collectionHelpersAbi.json b/tests/src/eth/abi/collectionHelpers.json similarity index 51% rename from tests/src/eth/collectionHelpersAbi.json rename to tests/src/eth/abi/collectionHelpers.json index 3817f09624..daf8c49d22 100644 --- a/tests/src/eth/collectionHelpersAbi.json +++ b/tests/src/eth/abi/collectionHelpers.json @@ -1,4 +1,17 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "collectionId", + "type": "address" + } + ], + "name": "CollectionChanged", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -18,6 +31,47 @@ "name": "CollectionCreated", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "collectionId", + "type": "address" + } + ], + "name": "CollectionDestroyed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "collectionId", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "TokenChanged", + "type": "event" + }, + { + "inputs": [ + { "internalType": "uint32", "name": "collectionId", "type": "uint32" } + ], + "name": "collectionAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "collectionCreationFee", @@ -25,6 +79,31 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "collectionAddress", + "type": "address" + } + ], + "name": "collectionId", + "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "name", "type": "string" }, + { "internalType": "uint8", "name": "decimals", "type": "uint8" }, + { "internalType": "string", "name": "description", "type": "string" }, + { "internalType": "string", "name": "tokenPrefix", "type": "string" } + ], + "name": "createFTCollection", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { "internalType": "string", "name": "name", "type": "string" }, @@ -47,6 +126,19 @@ "stateMutability": "payable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "collectionAddress", + "type": "address" + } + ], + "name": "destroyCollection", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/tests/src/eth/util/contractHelpersAbi.json b/tests/src/eth/abi/contractHelpers.json similarity index 92% rename from tests/src/eth/util/contractHelpersAbi.json rename to tests/src/eth/abi/contractHelpers.json index f10d1e5a83..0c403228ea 100644 --- a/tests/src/eth/util/contractHelpersAbi.json +++ b/tests/src/eth/abi/contractHelpers.json @@ -190,7 +190,11 @@ "name": "contractAddress", "type": "address" }, - { "internalType": "uint8", "name": "mode", "type": "uint8" } + { + "internalType": "enum SponsoringModeT", + "name": "mode", + "type": "uint8" + } ], "name": "setSponsoringMode", "outputs": [], @@ -223,10 +227,18 @@ "outputs": [ { "components": [ - { "internalType": "address", "name": "field_0", "type": "address" }, - { "internalType": "uint256", "name": "field_1", "type": "uint256" } + { "internalType": "bool", "name": "status", "type": "bool" }, + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "value", + "type": "tuple" + } ], - "internalType": "struct Tuple0", + "internalType": "struct OptionCrossAddress", "name": "", "type": "tuple" } diff --git a/tests/src/eth/abi/fungible.json b/tests/src/eth/abi/fungible.json new file mode 100644 index 0000000000..0eeab54ab0 --- /dev/null +++ b/tests/src/eth/abi/fungible.json @@ -0,0 +1,684 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "newAdmin", + "type": "tuple" + } + ], + "name": "addCollectionAdminCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "user", + "type": "tuple" + } + ], + "name": "addToCollectionAllowListCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "address", "name": "spender", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "user", + "type": "tuple" + } + ], + "name": "allowlistedCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "spender", + "type": "tuple" + }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "approveCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" } + ], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "from", + "type": "tuple" + }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "burnFromCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "newOwner", + "type": "tuple" + } + ], + "name": "changeCollectionOwnerCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "collectionAdmins", + "outputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionHelperAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionLimits", + "outputs": [ + { + "components": [ + { + "internalType": "enum CollectionLimitField", + "name": "field", + "type": "uint8" + }, + { + "components": [ + { "internalType": "bool", "name": "status", "type": "bool" }, + { "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "internalType": "struct OptionUint", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct CollectionLimit[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionNestingPermissions", + "outputs": [ + { + "components": [ + { + "internalType": "enum CollectionPermissionField", + "name": "field", + "type": "uint8" + }, + { "internalType": "bool", "name": "value", "type": "bool" } + ], + "internalType": "struct CollectionNestingPermission[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionNestingRestrictedCollectionIds", + "outputs": [ + { + "components": [ + { "internalType": "bool", "name": "token_owner", "type": "bool" }, + { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" } + ], + "internalType": "struct CollectionNesting", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionOwner", + "outputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string[]", "name": "keys", "type": "string[]" } + ], + "name": "collectionProperties", + "outputs": [ + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], + "name": "collectionProperty", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionSponsor", + "outputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "confirmCollectionSponsorship", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "contractAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string[]", "name": "keys", "type": "string[]" } + ], + "name": "deleteCollectionProperties", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "description", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "hasCollectionPendingSponsor", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "user", + "type": "tuple" + } + ], + "name": "isOwnerOrAdminCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "mint", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "field_0", "type": "address" }, + { "internalType": "uint256", "name": "field_1", "type": "uint256" } + ], + "internalType": "struct Tuple9[]", + "name": "amounts", + "type": "tuple[]" + } + ], + "name": "mintBulk", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "to", + "type": "tuple" + }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "mintCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "admin", + "type": "tuple" + } + ], + "name": "removeCollectionAdminCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "removeCollectionSponsor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "user", + "type": "tuple" + } + ], + "name": "removeFromCollectionAllowListCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }], + "name": "setCollectionAccess", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum CollectionLimitField", + "name": "field", + "type": "uint8" + }, + { + "components": [ + { "internalType": "bool", "name": "status", "type": "bool" }, + { "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "internalType": "struct OptionUint", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct CollectionLimit", + "name": "limit", + "type": "tuple" + } + ], + "name": "setCollectionLimit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }], + "name": "setCollectionMintMode", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }], + "name": "setCollectionNesting", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bool", "name": "enable", "type": "bool" }, + { + "internalType": "address[]", + "name": "collections", + "type": "address[]" + } + ], + "name": "setCollectionNesting", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "properties", + "type": "tuple[]" + } + ], + "name": "setCollectionProperties", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "sponsor", + "type": "tuple" + } + ], + "name": "setCollectionSponsorCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" } + ], + "name": "supportsInterface", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transfer", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "to", + "type": "tuple" + }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transferCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "from", + "type": "tuple" + }, + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "to", + "type": "tuple" + }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transferFromCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "uniqueCollectionType", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/tests/src/eth/abi/fungibleDeprecated.json b/tests/src/eth/abi/fungibleDeprecated.json new file mode 100644 index 0000000000..eb20720e98 --- /dev/null +++ b/tests/src/eth/abi/fungibleDeprecated.json @@ -0,0 +1,101 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "newAdmin", "type": "address" } + ], + "name": "addCollectionAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "user", "type": "address" } + ], + "name": "addToCollectionAllowList", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "burnFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "changeCollectionOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], + "name": "deleteCollectionProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "user", "type": "address" } + ], + "name": "isOwnerOrAdmin", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "admin", "type": "address" } + ], + "name": "removeCollectionAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "user", "type": "address" } + ], + "name": "removeFromCollectionAllowList", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "name": "setCollectionProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "sponsor", "type": "address" } + ], + "name": "setCollectionSponsor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "changeCollectionOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/tests/src/eth/abi/nonFungible.json b/tests/src/eth/abi/nonFungible.json new file mode 100644 index 0000000000..cfe04a2ece --- /dev/null +++ b/tests/src/eth/abi/nonFungible.json @@ -0,0 +1,950 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "MintingFinished", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "newAdmin", + "type": "tuple" + } + ], + "name": "addCollectionAdminCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "user", + "type": "tuple" + } + ], + "name": "addToCollectionAllowListCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "user", + "type": "tuple" + } + ], + "name": "allowlistedCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "approved", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "approved", + "type": "tuple" + }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "approveCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" } + ], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "from", + "type": "tuple" + }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "burnFromCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "newOwner", + "type": "tuple" + } + ], + "name": "changeCollectionOwnerCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "collectionAdmins", + "outputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionHelperAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionLimits", + "outputs": [ + { + "components": [ + { + "internalType": "enum CollectionLimitField", + "name": "field", + "type": "uint8" + }, + { + "components": [ + { "internalType": "bool", "name": "status", "type": "bool" }, + { "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "internalType": "struct OptionUint", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct CollectionLimit[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionNestingPermissions", + "outputs": [ + { + "components": [ + { + "internalType": "enum CollectionPermissionField", + "name": "field", + "type": "uint8" + }, + { "internalType": "bool", "name": "value", "type": "bool" } + ], + "internalType": "struct CollectionNestingPermission[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionNestingRestrictedCollectionIds", + "outputs": [ + { + "components": [ + { "internalType": "bool", "name": "token_owner", "type": "bool" }, + { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" } + ], + "internalType": "struct CollectionNesting", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionOwner", + "outputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string[]", "name": "keys", "type": "string[]" } + ], + "name": "collectionProperties", + "outputs": [ + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], + "name": "collectionProperty", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionSponsor", + "outputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "confirmCollectionSponsorship", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "contractAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "crossOwnerOf", + "outputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string[]", "name": "keys", "type": "string[]" } + ], + "name": "deleteCollectionProperties", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string[]", "name": "keys", "type": "string[]" } + ], + "name": "deleteProperties", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "description", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "finishMinting", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "getApproved", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "hasCollectionPendingSponsor", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "address", "name": "operator", "type": "address" } + ], + "name": "isApprovedForAll", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "user", + "type": "tuple" + } + ], + "name": "isOwnerOrAdminCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "to", "type": "address" }], + "name": "mint", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "to", + "type": "tuple" + }, + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "properties", + "type": "tuple[]" + } + ], + "name": "mintCross", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "string", "name": "tokenUri", "type": "string" } + ], + "name": "mintWithTokenURI", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "mintingFinished", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nextTokenId", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "ownerOf", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string[]", "name": "keys", "type": "string[]" } + ], + "name": "properties", + "outputs": [ + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string", "name": "key", "type": "string" } + ], + "name": "property", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "admin", + "type": "tuple" + } + ], + "name": "removeCollectionAdminCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "removeCollectionSponsor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "user", + "type": "tuple" + } + ], + "name": "removeFromCollectionAllowListCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "operator", "type": "address" }, + { "internalType": "bool", "name": "approved", "type": "bool" } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }], + "name": "setCollectionAccess", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum CollectionLimitField", + "name": "field", + "type": "uint8" + }, + { + "components": [ + { "internalType": "bool", "name": "status", "type": "bool" }, + { "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "internalType": "struct OptionUint", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct CollectionLimit", + "name": "limit", + "type": "tuple" + } + ], + "name": "setCollectionLimit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }], + "name": "setCollectionMintMode", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }], + "name": "setCollectionNesting", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bool", "name": "enable", "type": "bool" }, + { + "internalType": "address[]", + "name": "collections", + "type": "address[]" + } + ], + "name": "setCollectionNesting", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "properties", + "type": "tuple[]" + } + ], + "name": "setCollectionProperties", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "sponsor", + "type": "tuple" + } + ], + "name": "setCollectionSponsorCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "properties", + "type": "tuple[]" + } + ], + "name": "setProperties", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { + "components": [ + { + "internalType": "enum TokenPermissionField", + "name": "code", + "type": "uint8" + }, + { "internalType": "bool", "name": "value", "type": "bool" } + ], + "internalType": "struct PropertyPermission[]", + "name": "permissions", + "type": "tuple[]" + } + ], + "internalType": "struct TokenPropertyPermission[]", + "name": "permissions", + "type": "tuple[]" + } + ], + "name": "setTokenPropertyPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" } + ], + "name": "supportsInterface", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "index", "type": "uint256" } + ], + "name": "tokenByIndex", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "uint256", "name": "index", "type": "uint256" } + ], + "name": "tokenOfOwnerByIndex", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tokenPropertyPermissions", + "outputs": [ + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { + "components": [ + { + "internalType": "enum TokenPermissionField", + "name": "code", + "type": "uint8" + }, + { "internalType": "bool", "name": "value", "type": "bool" } + ], + "internalType": "struct PropertyPermission[]", + "name": "permissions", + "type": "tuple[]" + } + ], + "internalType": "struct TokenPropertyPermission[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "tokenURI", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "transfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "to", + "type": "tuple" + }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "transferCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "from", + "type": "tuple" + }, + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "to", + "type": "tuple" + }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "transferFromCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "uniqueCollectionType", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/tests/src/eth/abi/nonFungibleDeprecated.json b/tests/src/eth/abi/nonFungibleDeprecated.json new file mode 100644 index 0000000000..046b27bc23 --- /dev/null +++ b/tests/src/eth/abi/nonFungibleDeprecated.json @@ -0,0 +1,113 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "newAdmin", "type": "address" } + ], + "name": "addCollectionAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "user", "type": "address" } + ], + "name": "addToCollectionAllowList", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], + "name": "deleteCollectionProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "user", "type": "address" } + ], + "name": "isOwnerOrAdmin", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "admin", "type": "address" } + ], + "name": "removeCollectionAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "user", "type": "address" } + ], + "name": "removeFromCollectionAllowList", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "name": "setCollectionProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "sponsor", "type": "address" } + ], + "name": "setCollectionSponsor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "name": "setProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "changeCollectionOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string", "name": "key", "type": "string" } + ], + "name": "deleteProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/tests/src/eth/reFungibleAbi.json b/tests/src/eth/abi/reFungible.json similarity index 50% rename from tests/src/eth/reFungibleAbi.json rename to tests/src/eth/abi/reFungible.json index a6417973d2..b70ce6572d 100644 --- a/tests/src/eth/reFungibleAbi.json +++ b/tests/src/eth/abi/reFungible.json @@ -82,27 +82,51 @@ }, { "inputs": [ - { "internalType": "address", "name": "newAdmin", "type": "address" } + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "newAdmin", + "type": "tuple" + } ], - "name": "addCollectionAdmin", + "name": "addCollectionAdminCross", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ - { "internalType": "address", "name": "user", "type": "address" } + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "user", + "type": "tuple" + } ], - "name": "addToCollectionAllowList", + "name": "addToCollectionAllowListCross", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ - { "internalType": "address", "name": "user", "type": "address" } + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "user", + "type": "tuple" + } ], - "name": "allowed", + "name": "allowlistedCross", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "view", "type": "function" @@ -137,33 +161,140 @@ }, { "inputs": [ - { "internalType": "address", "name": "from", "type": "address" }, + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "from", + "type": "tuple" + }, { "internalType": "uint256", "name": "tokenId", "type": "uint256" } ], - "name": "burnFrom", + "name": "burnFromCross", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ - { "internalType": "address", "name": "newOwner", "type": "address" } + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "newOwner", + "type": "tuple" + } ], - "name": "changeCollectionOwner", + "name": "changeCollectionOwnerCross", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "collectionAdmins", + "outputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionHelperAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionLimits", + "outputs": [ + { + "components": [ + { + "internalType": "enum CollectionLimitField", + "name": "field", + "type": "uint8" + }, + { + "components": [ + { "internalType": "bool", "name": "status", "type": "bool" }, + { "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "internalType": "struct OptionUint", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct CollectionLimit[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionNestingPermissions", + "outputs": [ + { + "components": [ + { + "internalType": "enum CollectionPermissionField", + "name": "field", + "type": "uint8" + }, + { "internalType": "bool", "name": "value", "type": "bool" } + ], + "internalType": "struct CollectionNestingPermission[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "collectionNestingRestrictedCollectionIds", + "outputs": [ + { + "components": [ + { "internalType": "bool", "name": "token_owner", "type": "bool" }, + { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" } + ], + "internalType": "struct CollectionNesting", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "collectionOwner", "outputs": [ { "components": [ - { "internalType": "address", "name": "field_0", "type": "address" }, - { "internalType": "uint256", "name": "field_1", "type": "uint256" } + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } ], - "internalType": "struct Tuple17", + "internalType": "struct CrossAddress", "name": "", "type": "tuple" } @@ -171,6 +302,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { "internalType": "string[]", "name": "keys", "type": "string[]" } + ], + "name": "collectionProperties", + "outputs": [ + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], "name": "collectionProperty", @@ -184,10 +334,10 @@ "outputs": [ { "components": [ - { "internalType": "address", "name": "field_0", "type": "address" }, - { "internalType": "uint256", "name": "field_1", "type": "uint256" } + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } ], - "internalType": "struct Tuple17", + "internalType": "struct CrossAddress", "name": "", "type": "tuple" } @@ -210,8 +360,29 @@ "type": "function" }, { - "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], - "name": "deleteCollectionProperty", + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "crossOwnerOf", + "outputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string[]", "name": "keys", "type": "string[]" } + ], + "name": "deleteCollectionProperties", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -219,13 +390,20 @@ { "inputs": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, - { "internalType": "string", "name": "key", "type": "string" } + { "internalType": "string[]", "name": "keys", "type": "string[]" } ], - "name": "deleteProperty", + "name": "deleteProperties", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "description", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "finishMinting", @@ -255,15 +433,23 @@ { "internalType": "address", "name": "operator", "type": "address" } ], "name": "isApprovedForAll", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "view", "type": "function" }, { "inputs": [ - { "internalType": "address", "name": "user", "type": "address" } + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "user", + "type": "tuple" + } ], - "name": "isOwnerOrAdmin", + "name": "isOwnerOrAdminCross", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "view", "type": "function" @@ -275,6 +461,32 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "to", + "type": "tuple" + }, + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "properties", + "type": "tuple[]" + } + ], + "name": "mintCross", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { "internalType": "address", "name": "to", "type": "address" }, @@ -315,6 +527,26 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string[]", "name": "keys", "type": "string[]" } + ], + "name": "properties", + "outputs": [ + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, @@ -327,9 +559,17 @@ }, { "inputs": [ - { "internalType": "address", "name": "admin", "type": "address" } + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "admin", + "type": "tuple" + } ], - "name": "removeCollectionAdmin", + "name": "removeCollectionAdminCross", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -343,9 +583,17 @@ }, { "inputs": [ - { "internalType": "address", "name": "user", "type": "address" } + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "user", + "type": "tuple" + } ], - "name": "removeFromCollectionAllowList", + "name": "removeFromCollectionAllowListCross", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -392,18 +640,27 @@ }, { "inputs": [ - { "internalType": "string", "name": "limit", "type": "string" }, - { "internalType": "uint32", "name": "value", "type": "uint32" } - ], - "name": "setCollectionLimit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "string", "name": "limit", "type": "string" }, - { "internalType": "bool", "name": "value", "type": "bool" } + { + "components": [ + { + "internalType": "enum CollectionLimitField", + "name": "field", + "type": "uint8" + }, + { + "components": [ + { "internalType": "bool", "name": "status", "type": "bool" }, + { "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "internalType": "struct OptionUint", + "name": "value", + "type": "tuple" + } + ], + "internalType": "struct CollectionLimit", + "name": "limit", + "type": "tuple" + } ], "name": "setCollectionLimit", "outputs": [], @@ -440,19 +697,34 @@ }, { "inputs": [ - { "internalType": "string", "name": "key", "type": "string" }, - { "internalType": "bytes", "name": "value", "type": "bytes" } + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "properties", + "type": "tuple[]" + } ], - "name": "setCollectionProperty", + "name": "setCollectionProperties", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ - { "internalType": "address", "name": "sponsor", "type": "address" } + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "sponsor", + "type": "tuple" + } ], - "name": "setCollectionSponsor", + "name": "setCollectionSponsorCross", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -460,22 +732,46 @@ { "inputs": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, - { "internalType": "string", "name": "key", "type": "string" }, - { "internalType": "bytes", "name": "value", "type": "bytes" } + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "internalType": "struct Property[]", + "name": "properties", + "type": "tuple[]" + } ], - "name": "setProperty", + "name": "setProperties", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ - { "internalType": "string", "name": "key", "type": "string" }, - { "internalType": "bool", "name": "isMutable", "type": "bool" }, - { "internalType": "bool", "name": "collectionAdmin", "type": "bool" }, - { "internalType": "bool", "name": "tokenOwner", "type": "bool" } + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { + "components": [ + { + "internalType": "enum TokenPermissionField", + "name": "code", + "type": "uint8" + }, + { "internalType": "bool", "name": "value", "type": "bool" } + ], + "internalType": "struct PropertyPermission[]", + "name": "permissions", + "type": "tuple[]" + } + ], + "internalType": "struct TokenPropertyPermission[]", + "name": "permissions", + "type": "tuple[]" + } ], - "name": "setTokenPropertyPermission", + "name": "setTokenPropertyPermissions", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -524,6 +820,35 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "tokenPropertyPermissions", + "outputs": [ + { + "components": [ + { "internalType": "string", "name": "key", "type": "string" }, + { + "components": [ + { + "internalType": "enum TokenPermissionField", + "name": "code", + "type": "uint8" + }, + { "internalType": "bool", "name": "value", "type": "bool" } + ], + "internalType": "struct PropertyPermission[]", + "name": "permissions", + "type": "tuple[]" + } + ], + "internalType": "struct TokenPropertyPermission[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" } @@ -550,6 +875,24 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "to", + "type": "tuple" + }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "transferCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { "internalType": "address", "name": "from", "type": "address" }, @@ -561,6 +904,33 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "from", + "type": "tuple" + }, + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "to", + "type": "tuple" + }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "transferFromCross", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "uniqueCollectionType", diff --git a/tests/src/eth/abi/reFungibleDeprecated.json b/tests/src/eth/abi/reFungibleDeprecated.json new file mode 100644 index 0000000000..4a7313cb10 --- /dev/null +++ b/tests/src/eth/abi/reFungibleDeprecated.json @@ -0,0 +1,130 @@ +[ + { + "inputs": [ + { "internalType": "address", "name": "newAdmin", "type": "address" } + ], + "name": "addCollectionAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "user", "type": "address" } + ], + "name": "addToCollectionAllowList", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "uint256", "name": "tokenId", "type": "uint256" } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], + "name": "deleteCollectionProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "user", "type": "address" } + ], + "name": "isOwnerOrAdmin", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "admin", "type": "address" } + ], + "name": "removeCollectionAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "user", "type": "address" } + ], + "name": "removeFromCollectionAllowList", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "key", "type": "string" }, + { "internalType": "bytes", "name": "value", "type": "bytes" } + ], + "name": "setCollectionProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "sponsor", "type": "address" } + ], + "name": "setCollectionSponsor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "changeCollectionOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, + { "internalType": "string", "name": "key", "type": "string" } + ], + "name": "deleteProperty", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" } + ], + "name": "mintBulk", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { + "components": [ + { "internalType": "uint256", "name": "field_0", "type": "uint256" }, + { "internalType": "string", "name": "field_1", "type": "string" } + ], + "internalType": "struct Tuple0[]", + "name": "tokens", + "type": "tuple[]" + } + ], + "name": "mintBulkWithTokenURI", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/tests/src/eth/reFungibleTokenAbi.json b/tests/src/eth/abi/reFungibleToken.json similarity index 64% rename from tests/src/eth/reFungibleTokenAbi.json rename to tests/src/eth/abi/reFungibleToken.json index 608f4feafc..968a6299ca 100644 --- a/tests/src/eth/reFungibleTokenAbi.json +++ b/tests/src/eth/abi/reFungibleToken.json @@ -69,6 +69,24 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "spender", + "type": "tuple" + }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "approveCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { "internalType": "address", "name": "owner", "type": "address" } @@ -88,6 +106,24 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "from", + "type": "tuple" + }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "burnFromCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "decimals", @@ -158,6 +194,24 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "to", + "type": "tuple" + }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transferCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { "internalType": "address", "name": "from", "type": "address" }, @@ -168,5 +222,32 @@ "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [ + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "from", + "type": "tuple" + }, + { + "components": [ + { "internalType": "address", "name": "eth", "type": "address" }, + { "internalType": "uint256", "name": "sub", "type": "uint256" } + ], + "internalType": "struct CrossAddress", + "name": "to", + "type": "tuple" + }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transferFromCross", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" } ] diff --git a/tests/src/eth/allowlist.test.ts b/tests/src/eth/allowlist.test.ts index 76c5cfbde7..bff98fbdd2 100644 --- a/tests/src/eth/allowlist.test.ts +++ b/tests/src/eth/allowlist.test.ts @@ -15,7 +15,8 @@ // along with Unique Network. If not, see . import {IKeyringPair} from '@polkadot/types/types'; -import {itEth, usingEthPlaygrounds, expect} from './util'; +import {Pallets} from '../util'; +import {itEth, usingEthPlaygrounds, expect, SponsoringMode} from './util'; describe('EVM contract allowlist', () => { let donor: IKeyringPair; @@ -29,7 +30,7 @@ describe('EVM contract allowlist', () => { itEth('Contract allowlist can be toggled', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const flipper = await helper.eth.deployFlipper(owner); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); // Any user is allowed by default expect(await helpers.methods.allowlistEnabled(flipper.options.address).call()).to.be.false; @@ -47,7 +48,7 @@ describe('EVM contract allowlist', () => { const owner = await helper.eth.createAccountWithBalance(donor); const caller = await helper.eth.createAccountWithBalance(donor); const flipper = await helper.eth.deployFlipper(owner); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); // User can flip with allowlist disabled await flipper.methods.flip().send({from: caller}); @@ -74,71 +75,137 @@ describe('EVM collection allowlist', () => { }); }); + // Soft-deprecated itEth('Collection allowlist can be added and removed by [eth] address', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const user = helper.eth.createAccount(); + const crossUser = helper.ethCrossAccount.fromAddress(user); const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true); - expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.false; + expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false; await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner}); - expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.true; + expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.true; await collectionEvm.methods.removeFromCollectionAllowList(user).send({from: owner}); - expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.false; + expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false; }); - // TODO: Temprorary off. Need refactor - // itEth('Collection allowlist can be added and removed by [sub] address', async ({helper}) => { - // const owner = await helper.eth.createAccountWithBalance(donor); - // const user = donor; - // const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - // const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - - // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false; - // await collectionEvm.methods.addToCollectionAllowListSubstrate(user.addressRaw).send({from: owner}); - // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true; - - // await collectionEvm.methods.removeFromCollectionAllowListSubstrate(user.addressRaw).send({from: owner}); - // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false; - // }); - - itEth('Collection allowlist can not be add and remove [eth] address by not owner', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - const notOwner = await helper.eth.createAccountWithBalance(donor); - const user = helper.eth.createAccount(); - - const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - - expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.false; - await expect(collectionEvm.methods.addToCollectionAllowList(user).call({from: notOwner})).to.be.rejectedWith('NoPermission'); - expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.false; - await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner}); - - expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.true; - await expect(collectionEvm.methods.removeFromCollectionAllowList(user).call({from: notOwner})).to.be.rejectedWith('NoPermission'); - expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.true; - }); - - // TODO: Temprorary off. Need refactor - // itEth('Collection allowlist can not be add and remove [sub] address by not owner', async ({helper}) => { - // const owner = await helper.eth.createAccountWithBalance(donor); - // const notOwner = await helper.eth.createAccountWithBalance(donor); - // const user = donor; - - // const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - // const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - - // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false; - // await expect(collectionEvm.methods.addToCollectionAllowListSubstrate(user.addressRaw).call({from: notOwner})).to.be.rejectedWith('NoPermission'); - // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false; - // await collectionEvm.methods.addToCollectionAllowListSubstrate(user.addressRaw).send({from: owner}); - - // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true; - // await expect(collectionEvm.methods.removeFromCollectionAllowListSubstrate(user.addressRaw).call({from: notOwner})).to.be.rejectedWith('NoPermission'); - // expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true; - // }); + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + {mode: 'ft' as const, requiredPallets: []}, + ].map(testCase => + itEth.ifWithPallets(`Collection allowlist can be added and removed by [cross] address for ${testCase.mode}`, testCase.requiredPallets, async ({helper}) => { + const owner = (await helper.eth.createAccountWithBalance(donor)).toLowerCase(); + const [userSub] = await helper.arrange.createAccounts([10n], donor); + const userEth = await helper.eth.createAccountWithBalance(donor); + const mintParams = testCase.mode === 'ft' ? [userEth, 100] : [userEth]; + + const {collectionAddress, collectionId} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner); + const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub); + const userCrossEth = helper.ethCrossAccount.fromAddress(userEth); + const ownerCrossEth = helper.ethCrossAccount.fromAddress(owner); + + // Can addToCollectionAllowListCross: + expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false; + await collectionEvm.methods.addToCollectionAllowListCross(userCrossSub).send({from: owner}); + await collectionEvm.methods.addToCollectionAllowListCross(userCrossEth).send({from: owner}); + await collectionEvm.methods.addToCollectionAllowListCross(ownerCrossEth).send({from: owner}); + + // Accounts are in allowed list: + expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true; + expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true; + expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.true; + expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.true; + + await collectionEvm.methods.mint(...mintParams).send({from: owner}); // token #1 + await collectionEvm.methods.mint(...mintParams).send({from: owner}); // token #2 + await collectionEvm.methods.setCollectionAccess(SponsoringMode.Allowlisted).send({from: owner}); + + // allowlisted account can transfer and transferCross from eth: + await collectionEvm.methods.transfer(owner, 1).send({from: userEth}); + await collectionEvm.methods.transferCross(userCrossSub, 2).send({from: userEth}); + + if (testCase.mode === 'ft') { + expect(await helper.ft.getBalance(collectionId, {Ethereum: owner})).to.eq(1n); + expect(await helper.ft.getBalance(collectionId, {Substrate: userSub.address})).to.eq(2n); + } else { + expect(await helper.nft.getTokenOwner(collectionId, 1)).to.deep.eq({Ethereum: owner}); + expect(await helper.nft.getTokenOwner(collectionId, 2)).to.deep.eq({Substrate: userSub.address}); + } + + // allowlisted cross substrate accounts can transfer from Substrate: + testCase.mode === 'ft' + ? await helper.ft.transfer(userSub, collectionId, {Ethereum: userEth}, 2n) + : await helper.collection.transferToken(userSub, collectionId, 2, {Ethereum: userEth}); + + // can removeFromCollectionAllowListCross: + await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossSub).send({from: owner}); + await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossEth).send({from: owner}); + expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false; + expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false; + expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.false; + expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.false; + + // cannot transfer anymore + await collectionEvm.methods.mint(...mintParams).send({from: owner}); + await expect(collectionEvm.methods.transfer(owner, 2).send({from: userEth})).to.be.rejectedWith(/Transaction has been reverted/); + })); + + [ + // cross-methods + {mode: 'nft' as const, cross: true, requiredPallets: []}, + {mode: 'rft' as const, cross: true, requiredPallets: [Pallets.ReFungible]}, + {mode: 'ft' as const, cross: true, requiredPallets: []}, + // soft-deprecated + {mode: 'nft' as const, cross: false, requiredPallets: []}, + {mode: 'rft' as const, cross: false, requiredPallets: [Pallets.ReFungible]}, + {mode: 'ft' as const, cross: false, requiredPallets: []}, + ].map(testCase => + itEth.ifWithPallets(`Non-owner cannot add or remove from collection allowlist ${testCase.cross ? 'cross ' : ''}${testCase.mode}`, testCase.requiredPallets, async ({helper}) => { + // Select methods: + const addToAllowList = testCase.cross ? 'addToCollectionAllowListCross' : 'addToCollectionAllowList'; + const removeFromAllowList = testCase.cross ? 'removeFromCollectionAllowListCross' : 'removeFromCollectionAllowList'; + + const owner = await helper.eth.createAccountWithBalance(donor); + const notOwner = await helper.eth.createAccountWithBalance(donor); + const userSub = donor; + const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub); + const userEth = helper.eth.createAccount(); + const userCrossEth = helper.ethCrossAccount.fromAddress(userEth); + + const {collectionAddress, collectionId} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, !testCase.cross); + + expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false; + expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false; + + // 1. notOwner cannot add to allow list: + // 1.1 plain ethereum or cross address: + await expect(collectionEvm.methods[addToAllowList](testCase.cross ? userCrossEth : userEth).call({from: notOwner})).to.be.rejectedWith('NoPermission'); + // 1.2 cross-substrate address: + if (testCase.cross) + await expect(collectionEvm.methods[addToAllowList](userCrossSub).call({from: notOwner})).to.be.rejectedWith('NoPermission'); + + // 2. owner can add to allow list: + // 2.1 plain ethereum or cross address: + await collectionEvm.methods[addToAllowList](testCase.cross ? userCrossEth : userEth).send({from: owner}); + // 2.2 cross-substrate address: + if (testCase.cross) { + await collectionEvm.methods[addToAllowList](userCrossSub).send({from: owner}); + expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true; + } + expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true; + + // 3. notOwner cannot remove from allow list: + // 3.1 plain ethereum or cross address: + await expect(collectionEvm.methods[removeFromAllowList](testCase.cross ? userCrossEth : userEth).call({from: notOwner})).to.be.rejectedWith('NoPermission'); + // 3.2 cross-substrate address: + if (testCase.cross) + await expect(collectionEvm.methods[removeFromAllowList](userCrossSub).call({from: notOwner})).to.be.rejectedWith('NoPermission'); + })); }); diff --git a/tests/src/eth/api/CollectionHelpers.sol b/tests/src/eth/api/CollectionHelpers.sol index 327c86159a..4b7f2eef97 100644 --- a/tests/src/eth/api/CollectionHelpers.sol +++ b/tests/src/eth/api/CollectionHelpers.sol @@ -15,10 +15,13 @@ interface ERC165 is Dummy { /// @dev inlined interface interface CollectionHelpersEvents { event CollectionCreated(address indexed owner, address indexed collectionId); + event CollectionDestroyed(address indexed collectionId); + event CollectionChanged(address indexed collectionId); + event TokenChanged(address indexed collectionId, uint256 tokenId); } /// @title Contract, which allows users to operate with collections -/// @dev the ERC-165 identifier for this interface is 0x58918631 +/// @dev the ERC-165 identifier for this interface is 0xe65011aa interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents { /// Create an NFT collection /// @param name Name of the collection @@ -50,10 +53,23 @@ interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents { string memory tokenPrefix ) external payable returns (address); + /// @dev EVM selector for this function is: 0x7335b79f, + /// or in textual repr: createFTCollection(string,uint8,string,string) + function createFTCollection( + string memory name, + uint8 decimals, + string memory description, + string memory tokenPrefix + ) external payable returns (address); + /// @dev EVM selector for this function is: 0x85624258, /// or in textual repr: makeCollectionERC721MetadataCompatible(address,string) function makeCollectionERC721MetadataCompatible(address collection, string memory baseUri) external; + /// @dev EVM selector for this function is: 0x564e321f, + /// or in textual repr: destroyCollection(address) + function destroyCollection(address collectionAddress) external; + /// Check if a collection exists /// @param collectionAddress Address of the collection in question /// @return bool Does the collection exist? @@ -64,4 +80,18 @@ interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents { /// @dev EVM selector for this function is: 0xd23a7ab1, /// or in textual repr: collectionCreationFee() function collectionCreationFee() external view returns (uint256); + + /// Returns address of a collection. + /// @param collectionId - CollectionId of the collection + /// @return eth mirror address of the collection + /// @dev EVM selector for this function is: 0x2e716683, + /// or in textual repr: collectionAddress(uint32) + function collectionAddress(uint32 collectionId) external view returns (address); + + /// Returns collectionId of a collection. + /// @param collectionAddress - Eth address of the collection + /// @return collectionId of the collection + /// @dev EVM selector for this function is: 0xb5cb7498, + /// or in textual repr: collectionId(address) + function collectionId(address collectionAddress) external view returns (uint32); } diff --git a/tests/src/eth/api/ContractHelpers.sol b/tests/src/eth/api/ContractHelpers.sol index dd0970b96b..578c588576 100644 --- a/tests/src/eth/api/ContractHelpers.sol +++ b/tests/src/eth/api/ContractHelpers.sol @@ -69,7 +69,7 @@ interface ContractHelpers is Dummy, ERC165, ContractHelpersEvents { /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x766c4f37, /// or in textual repr: sponsor(address) - function sponsor(address contractAddress) external view returns (Tuple0 memory); + function sponsor(address contractAddress) external view returns (OptionCrossAddress memory); /// Check tat contract has confirmed sponsor. /// @@ -93,7 +93,7 @@ interface ContractHelpers is Dummy, ERC165, ContractHelpersEvents { /// @dev EVM selector for this function is: 0xfde8a560, /// or in textual repr: setSponsoringMode(address,uint8) - function setSponsoringMode(address contractAddress, uint8 mode) external; + function setSponsoringMode(address contractAddress, SponsoringModeT mode) external; /// Get current contract sponsoring rate limit /// @param contractAddress Contract to get sponsoring rate limit of @@ -171,8 +171,26 @@ interface ContractHelpers is Dummy, ERC165, ContractHelpersEvents { function toggleAllowlist(address contractAddress, bool enabled) external; } -/// @dev anonymous struct -struct Tuple0 { - address field_0; - uint256 field_1; +/// Available contract sponsoring modes +enum SponsoringModeT { + /// Sponsoring is disabled + Disabled, + /// Only users from allowlist will be sponsored + Allowlisted, + /// All users will be sponsored + Generous +} + +/// Ethereum representation of Optional value with CrossAddress. +struct OptionCrossAddress { + /// TODO: field description + bool status; + /// TODO: field description + CrossAddress value; +} + +/// Cross account struct +struct CrossAddress { + address eth; + uint256 sub; } diff --git a/tests/src/eth/api/UniqueFungible.sol b/tests/src/eth/api/UniqueFungible.sol index a0445eb0cf..cdeaca0fc0 100644 --- a/tests/src/eth/api/UniqueFungible.sol +++ b/tests/src/eth/api/UniqueFungible.sol @@ -13,22 +13,36 @@ interface ERC165 is Dummy { } /// @title A contract that allows you to work with collections. -/// @dev the ERC-165 identifier for this interface is 0x62e22290 +/// @dev the ERC-165 identifier for this interface is 0x2a14cfd1 interface Collection is Dummy, ERC165 { - /// Set collection property. + // /// Set collection property. + // /// + // /// @param key Property key. + // /// @param value Propery value. + // /// @dev EVM selector for this function is: 0x2f073f66, + // /// or in textual repr: setCollectionProperty(string,bytes) + // function setCollectionProperty(string memory key, bytes memory value) external; + + /// Set collection properties. /// - /// @param key Property key. - /// @param value Propery value. - /// @dev EVM selector for this function is: 0x2f073f66, - /// or in textual repr: setCollectionProperty(string,bytes) - function setCollectionProperty(string memory key, bytes memory value) external; - - /// Delete collection property. + /// @param properties Vector of properties key/value pair. + /// @dev EVM selector for this function is: 0x50b26b2a, + /// or in textual repr: setCollectionProperties((string,bytes)[]) + function setCollectionProperties(Property[] memory properties) external; + + // /// Delete collection property. + // /// + // /// @param key Property key. + // /// @dev EVM selector for this function is: 0x7b7debce, + // /// or in textual repr: deleteCollectionProperty(string) + // function deleteCollectionProperty(string memory key) external; + + /// Delete collection properties. /// - /// @param key Property key. - /// @dev EVM selector for this function is: 0x7b7debce, - /// or in textual repr: deleteCollectionProperty(string) - function deleteCollectionProperty(string memory key) external; + /// @param keys Properties keys. + /// @dev EVM selector for this function is: 0xee206ee3, + /// or in textual repr: deleteCollectionProperties(string[]) + function deleteCollectionProperties(string[] memory keys) external; /// Get collection property. /// @@ -40,14 +54,31 @@ interface Collection is Dummy, ERC165 { /// or in textual repr: collectionProperty(string) function collectionProperty(string memory key) external view returns (bytes memory); + /// Get collection properties. + /// + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0x285fb8e6, + /// or in textual repr: collectionProperties(string[]) + function collectionProperties(string[] memory keys) external view returns (Property[] memory); + + // /// Set the sponsor of the collection. + // /// + // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. + // /// + // /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. + // /// @dev EVM selector for this function is: 0x7623402e, + // /// or in textual repr: setCollectionSponsor(address) + // function setCollectionSponsor(address sponsor) external; + /// Set the sponsor of the collection. /// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. /// - /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. - /// @dev EVM selector for this function is: 0x7623402e, - /// or in textual repr: setCollectionSponsor(address) - function setCollectionSponsor(address sponsor) external; + /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract. + /// @dev EVM selector for this function is: 0x84a1d5a8, + /// or in textual repr: setCollectionSponsorCross((address,uint256)) + function setCollectionSponsorCross(CrossAddress memory sponsor) external; /// Whether there is a pending sponsor. /// @dev EVM selector for this function is: 0x058ac185, @@ -71,32 +102,21 @@ interface Collection is Dummy, ERC165 { /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x6ec0a9f1, /// or in textual repr: collectionSponsor() - function collectionSponsor() external view returns (Tuple6 memory); + function collectionSponsor() external view returns (CrossAddress memory); - /// Set limits for the collection. - /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "accountTokenOwnershipLimit", - /// "sponsoredDataSize", - /// "sponsoredDataRateLimit", - /// "tokenLimit", - /// "sponsorTransferTimeout", - /// "sponsorApproveTimeout" - /// @param value Value of the limit. - /// @dev EVM selector for this function is: 0x6a3841db, - /// or in textual repr: setCollectionLimit(string,uint32) - function setCollectionLimit(string memory limit, uint32 value) external; + /// Get current collection limits. + /// + /// @return Array of collection limits + /// @dev EVM selector for this function is: 0xf63bc572, + /// or in textual repr: collectionLimits() + function collectionLimits() external view returns (CollectionLimit[] memory); /// Set limits for the collection. /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "ownerCanTransfer", - /// "ownerCanDestroy", - /// "transfersEnabled" - /// @param value Value of the limit. - /// @dev EVM selector for this function is: 0x993b7fba, - /// or in textual repr: setCollectionLimit(string,bool) - function setCollectionLimit(string memory limit, bool value) external; + /// @param limit Some limit. + /// @dev EVM selector for this function is: 0x2316ee74, + /// or in textual repr: setCollectionLimit((uint8,(bool,uint256))) + function setCollectionLimit(CollectionLimit memory limit) external; /// Get contract address. /// @dev EVM selector for this function is: 0xf6b4dfb4, @@ -104,17 +124,29 @@ interface Collection is Dummy, ERC165 { function contractAddress() external view returns (address); /// Add collection admin. - /// @param newAdmin Address of the added administrator. - /// @dev EVM selector for this function is: 0x92e462c7, - /// or in textual repr: addCollectionAdmin(address) - function addCollectionAdmin(address newAdmin) external; + /// @param newAdmin Cross account administrator address. + /// @dev EVM selector for this function is: 0x859aa7d6, + /// or in textual repr: addCollectionAdminCross((address,uint256)) + function addCollectionAdminCross(CrossAddress memory newAdmin) external; /// Remove collection admin. - /// - /// @param admin Address of the removed administrator. - /// @dev EVM selector for this function is: 0xfafd7b42, - /// or in textual repr: removeCollectionAdmin(address) - function removeCollectionAdmin(address admin) external; + /// @param admin Cross account administrator address. + /// @dev EVM selector for this function is: 0x6c0cd173, + /// or in textual repr: removeCollectionAdminCross((address,uint256)) + function removeCollectionAdminCross(CrossAddress memory admin) external; + + // /// Add collection admin. + // /// @param newAdmin Address of the added administrator. + // /// @dev EVM selector for this function is: 0x92e462c7, + // /// or in textual repr: addCollectionAdmin(address) + // function addCollectionAdmin(address newAdmin) external; + + // /// Remove collection admin. + // /// + // /// @param admin Address of the removed administrator. + // /// @dev EVM selector for this function is: 0xfafd7b42, + // /// or in textual repr: removeCollectionAdmin(address) + // function removeCollectionAdmin(address admin) external; /// Toggle accessibility of collection nesting. /// @@ -131,6 +163,16 @@ interface Collection is Dummy, ERC165 { /// or in textual repr: setCollectionNesting(bool,address[]) function setCollectionNesting(bool enable, address[] memory collections) external; + /// Returns nesting for a collection + /// @dev EVM selector for this function is: 0x22d25bfe, + /// or in textual repr: collectionNestingRestrictedCollectionIds() + function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory); + + /// Returns permissions for a collection + /// @dev EVM selector for this function is: 0x5b2eaf4b, + /// or in textual repr: collectionNestingPermissions() + function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory); + /// Set the collection access method. /// @param mode Access mode /// 0 for Normal @@ -142,23 +184,37 @@ interface Collection is Dummy, ERC165 { /// Checks that user allowed to operate with collection. /// /// @param user User address to check. - /// @dev EVM selector for this function is: 0xd63a8e11, - /// or in textual repr: allowed(address) - function allowed(address user) external view returns (bool); - - /// Add the user to the allowed list. + /// @dev EVM selector for this function is: 0x91b6df49, + /// or in textual repr: allowlistedCross((address,uint256)) + function allowlistedCross(CrossAddress memory user) external view returns (bool); + + // /// Add the user to the allowed list. + // /// + // /// @param user Address of a trusted user. + // /// @dev EVM selector for this function is: 0x67844fe6, + // /// or in textual repr: addToCollectionAllowList(address) + // function addToCollectionAllowList(address user) external; + + /// Add user to allowed list. /// - /// @param user Address of a trusted user. - /// @dev EVM selector for this function is: 0x67844fe6, - /// or in textual repr: addToCollectionAllowList(address) - function addToCollectionAllowList(address user) external; - - /// Remove the user from the allowed list. + /// @param user User cross account address. + /// @dev EVM selector for this function is: 0xa0184a3a, + /// or in textual repr: addToCollectionAllowListCross((address,uint256)) + function addToCollectionAllowListCross(CrossAddress memory user) external; + + // /// Remove the user from the allowed list. + // /// + // /// @param user Address of a removed user. + // /// @dev EVM selector for this function is: 0x85c51acb, + // /// or in textual repr: removeFromCollectionAllowList(address) + // function removeFromCollectionAllowList(address user) external; + + /// Remove user from allowed list. /// - /// @param user Address of a removed user. - /// @dev EVM selector for this function is: 0x85c51acb, - /// or in textual repr: removeFromCollectionAllowList(address) - function removeFromCollectionAllowList(address user) external; + /// @param user User cross account address. + /// @dev EVM selector for this function is: 0x09ba452a, + /// or in textual repr: removeFromCollectionAllowListCross((address,uint256)) + function removeFromCollectionAllowListCross(CrossAddress memory user) external; /// Switch permission for minting. /// @@ -167,13 +223,21 @@ interface Collection is Dummy, ERC165 { /// or in textual repr: setCollectionMintMode(bool) function setCollectionMintMode(bool mode) external; + // /// Check that account is the owner or admin of the collection + // /// + // /// @param user account to verify + // /// @return "true" if account is the owner or admin + // /// @dev EVM selector for this function is: 0x9811b0c7, + // /// or in textual repr: isOwnerOrAdmin(address) + // function isOwnerOrAdmin(address user) external view returns (bool); + /// Check that account is the owner or admin of the collection /// - /// @param user account to verify + /// @param user User cross account to verify /// @return "true" if account is the owner or admin - /// @dev EVM selector for this function is: 0x9811b0c7, - /// or in textual repr: isOwnerOrAdmin(address) - function isOwnerOrAdmin(address user) external view returns (bool); + /// @dev EVM selector for this function is: 0x3e75a905, + /// or in textual repr: isOwnerOrAdminCross((address,uint256)) + function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool); /// Returns collection type /// @@ -188,37 +252,153 @@ interface Collection is Dummy, ERC165 { /// If address is canonical then substrate mirror is zero and vice versa. /// @dev EVM selector for this function is: 0xdf727d3b, /// or in textual repr: collectionOwner() - function collectionOwner() external view returns (Tuple6 memory); + function collectionOwner() external view returns (CrossAddress memory); + + // /// Changes collection owner to another account + // /// + // /// @dev Owner can be changed only by current owner + // /// @param newOwner new owner account + // /// @dev EVM selector for this function is: 0x4f53e226, + // /// or in textual repr: changeCollectionOwner(address) + // function changeCollectionOwner(address newOwner) external; + + /// Get collection administrators + /// + /// @return Vector of tuples with admins address and his substrate mirror. + /// If address is canonical then substrate mirror is zero and vice versa. + /// @dev EVM selector for this function is: 0x5813216b, + /// or in textual repr: collectionAdmins() + function collectionAdmins() external view returns (CrossAddress[] memory); /// Changes collection owner to another account /// /// @dev Owner can be changed only by current owner - /// @param newOwner new owner account - /// @dev EVM selector for this function is: 0x4f53e226, - /// or in textual repr: changeCollectionOwner(address) - function changeCollectionOwner(address newOwner) external; + /// @param newOwner new owner cross account + /// @dev EVM selector for this function is: 0x6496c497, + /// or in textual repr: changeCollectionOwnerCross((address,uint256)) + function changeCollectionOwnerCross(CrossAddress memory newOwner) external; +} + +/// Cross account struct +struct CrossAddress { + address eth; + uint256 sub; } -/// @dev the ERC-165 identifier for this interface is 0x63034ac5 +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field. +struct CollectionNestingPermission { + CollectionPermissionField field; + bool value; +} + +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration. +enum CollectionPermissionField { + /// Owner of token can nest tokens under it. + TokenOwner, + /// Admin of token collection can nest tokens under token. + CollectionAdmin +} + +/// Nested collections. +struct CollectionNesting { + bool token_owner; + uint256[] ids; +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM. +struct CollectionLimit { + CollectionLimitField field; + OptionUint value; +} + +/// Ethereum representation of Optional value with uint256. +struct OptionUint { + bool status; + uint256 value; +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM. +enum CollectionLimitField { + /// How many tokens can a user have on one account. + AccountTokenOwnership, + /// How many bytes of data are available for sponsorship. + SponsoredDataSize, + /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`] + SponsoredDataRateLimit, + /// How many tokens can be mined into this collection. + TokenLimit, + /// Timeouts for transfer sponsoring. + SponsorTransferTimeout, + /// Timeout for sponsoring an approval in passed blocks. + SponsorApproveTimeout, + /// Whether the collection owner of the collection can send tokens (which belong to other users). + OwnerCanTransfer, + /// Can the collection owner burn other people's tokens. + OwnerCanDestroy, + /// Is it possible to send tokens from this collection between users. + TransferEnabled +} + +/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue). +struct Property { + string key; + bytes value; +} + +/// @dev the ERC-165 identifier for this interface is 0x7dee5997 interface ERC20UniqueExtensions is Dummy, ERC165 { + /// @notice A description for the collection. + /// @dev EVM selector for this function is: 0x7284e416, + /// or in textual repr: description() + function description() external view returns (string memory); + + /// @dev EVM selector for this function is: 0x269e6158, + /// or in textual repr: mintCross((address,uint256),uint256) + function mintCross(CrossAddress memory to, uint256 amount) external returns (bool); + + /// @dev EVM selector for this function is: 0x0ecd0ab0, + /// or in textual repr: approveCross((address,uint256),uint256) + function approveCross(CrossAddress memory spender, uint256 amount) external returns (bool); + + // /// Burn tokens from account + // /// @dev Function that burns an `amount` of the tokens of a given account, + // /// deducting from the sender's allowance for said account. + // /// @param from The account whose tokens will be burnt. + // /// @param amount The amount that will be burnt. + // /// @dev EVM selector for this function is: 0x79cc6790, + // /// or in textual repr: burnFrom(address,uint256) + // function burnFrom(address from, uint256 amount) external returns (bool); + /// Burn tokens from account /// @dev Function that burns an `amount` of the tokens of a given account, /// deducting from the sender's allowance for said account. /// @param from The account whose tokens will be burnt. /// @param amount The amount that will be burnt. - /// @dev EVM selector for this function is: 0x79cc6790, - /// or in textual repr: burnFrom(address,uint256) - function burnFrom(address from, uint256 amount) external returns (bool); + /// @dev EVM selector for this function is: 0xbb2f5a58, + /// or in textual repr: burnFromCross((address,uint256),uint256) + function burnFromCross(CrossAddress memory from, uint256 amount) external returns (bool); /// Mint tokens for multiple accounts. /// @param amounts array of pairs of account address and amount /// @dev EVM selector for this function is: 0x1acf2d55, /// or in textual repr: mintBulk((address,uint256)[]) - function mintBulk(Tuple6[] memory amounts) external returns (bool); + function mintBulk(Tuple9[] memory amounts) external returns (bool); + + /// @dev EVM selector for this function is: 0x2ada85ff, + /// or in textual repr: transferCross((address,uint256),uint256) + function transferCross(CrossAddress memory to, uint256 amount) external returns (bool); + + /// @dev EVM selector for this function is: 0xd5cf430b, + /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256) + function transferFromCross( + CrossAddress memory from, + CrossAddress memory to, + uint256 amount + ) external returns (bool); } /// @dev anonymous struct -struct Tuple6 { +struct Tuple9 { address field_0; uint256 field_1; } @@ -239,7 +419,7 @@ interface ERC20Events { event Approval(address indexed owner, address indexed spender, uint256 value); } -/// @dev the ERC-165 identifier for this interface is 0x942e8b22 +/// @dev the ERC-165 identifier for this interface is 0x8cb847c4 interface ERC20 is Dummy, ERC165, ERC20Events { /// @dev EVM selector for this function is: 0x06fdde03, /// or in textual repr: name() @@ -280,6 +460,11 @@ interface ERC20 is Dummy, ERC165, ERC20Events { /// @dev EVM selector for this function is: 0xdd62ed3e, /// or in textual repr: allowance(address,address) function allowance(address owner, address spender) external view returns (uint256); + + /// @notice Returns collection helper contract address + /// @dev EVM selector for this function is: 0x1896cce6, + /// or in textual repr: collectionHelperAddress() + function collectionHelperAddress() external view returns (address); } interface UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {} diff --git a/tests/src/eth/api/UniqueNFT.sol b/tests/src/eth/api/UniqueNFT.sol index fc19cd00b6..989dd09bcf 100644 --- a/tests/src/eth/api/UniqueNFT.sol +++ b/tests/src/eth/api/UniqueNFT.sol @@ -13,43 +13,62 @@ interface ERC165 is Dummy { } /// @title A contract that allows to set and delete token properties and change token property permissions. -/// @dev the ERC-165 identifier for this interface is 0x41369377 +/// @dev the ERC-165 identifier for this interface is 0xde0695c2 interface TokenProperties is Dummy, ERC165 { + // /// @notice Set permissions for token property. + // /// @dev Throws error if `msg.sender` is not admin or owner of the collection. + // /// @param key Property key. + // /// @param isMutable Permission to mutate property. + // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable. + // /// @param tokenOwner Permission to mutate property by token owner if property is mutable. + // /// @dev EVM selector for this function is: 0x222d97fa, + // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool) + // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external; + /// @notice Set permissions for token property. /// @dev Throws error if `msg.sender` is not admin or owner of the collection. - /// @param key Property key. - /// @param isMutable Permission to mutate property. - /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable. - /// @param tokenOwner Permission to mutate property by token owner if property is mutable. - /// @dev EVM selector for this function is: 0x222d97fa, - /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool) - function setTokenPropertyPermission( - string memory key, - bool isMutable, - bool collectionAdmin, - bool tokenOwner - ) external; - - /// @notice Set token property value. + /// @param permissions Permissions for keys. + /// @dev EVM selector for this function is: 0xbd92983a, + /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[]) + function setTokenPropertyPermissions(TokenPropertyPermission[] memory permissions) external; + + /// @notice Get permissions for token properties. + /// @dev EVM selector for this function is: 0xf23d7790, + /// or in textual repr: tokenPropertyPermissions() + function tokenPropertyPermissions() external view returns (TokenPropertyPermission[] memory); + + // /// @notice Set token property value. + // /// @dev Throws error if `msg.sender` has no permission to edit the property. + // /// @param tokenId ID of the token. + // /// @param key Property key. + // /// @param value Property value. + // /// @dev EVM selector for this function is: 0x1752d67b, + // /// or in textual repr: setProperty(uint256,string,bytes) + // function setProperty(uint256 tokenId, string memory key, bytes memory value) external; + + /// @notice Set token properties value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. - /// @param key Property key. - /// @param value Property value. - /// @dev EVM selector for this function is: 0x1752d67b, - /// or in textual repr: setProperty(uint256,string,bytes) - function setProperty( - uint256 tokenId, - string memory key, - bytes memory value - ) external; - - /// @notice Delete token property value. + /// @param properties settable properties + /// @dev EVM selector for this function is: 0x14ed3a6e, + /// or in textual repr: setProperties(uint256,(string,bytes)[]) + function setProperties(uint256 tokenId, Property[] memory properties) external; + + // /// @notice Delete token property value. + // /// @dev Throws error if `msg.sender` has no permission to edit the property. + // /// @param tokenId ID of the token. + // /// @param key Property key. + // /// @dev EVM selector for this function is: 0x066111d1, + // /// or in textual repr: deleteProperty(uint256,string) + // function deleteProperty(uint256 tokenId, string memory key) external; + + /// @notice Delete token properties value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. - /// @param key Property key. - /// @dev EVM selector for this function is: 0x066111d1, - /// or in textual repr: deleteProperty(uint256,string) - function deleteProperty(uint256 tokenId, string memory key) external; + /// @param keys Properties key. + /// @dev EVM selector for this function is: 0xc472d371, + /// or in textual repr: deleteProperties(uint256,string[]) + function deleteProperties(uint256 tokenId, string[] memory keys) external; /// @notice Get token property value. /// @dev Throws error if key not found @@ -61,23 +80,69 @@ interface TokenProperties is Dummy, ERC165 { function property(uint256 tokenId, string memory key) external view returns (bytes memory); } +/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue). +struct Property { + string key; + bytes value; +} + +/// Ethereum representation of Token Property Permissions. +struct TokenPropertyPermission { + /// Token property key. + string key; + /// Token property permissions. + PropertyPermission[] permissions; +} + +/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value. +struct PropertyPermission { + /// TokenPermission field. + TokenPermissionField code; + /// TokenPermission value. + bool value; +} + +/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration. +enum TokenPermissionField { + /// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`] + Mutable, + /// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`] + TokenOwner, + /// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`] + CollectionAdmin +} + /// @title A contract that allows you to work with collections. -/// @dev the ERC-165 identifier for this interface is 0x62e22290 +/// @dev the ERC-165 identifier for this interface is 0x2a14cfd1 interface Collection is Dummy, ERC165 { - /// Set collection property. + // /// Set collection property. + // /// + // /// @param key Property key. + // /// @param value Propery value. + // /// @dev EVM selector for this function is: 0x2f073f66, + // /// or in textual repr: setCollectionProperty(string,bytes) + // function setCollectionProperty(string memory key, bytes memory value) external; + + /// Set collection properties. /// - /// @param key Property key. - /// @param value Propery value. - /// @dev EVM selector for this function is: 0x2f073f66, - /// or in textual repr: setCollectionProperty(string,bytes) - function setCollectionProperty(string memory key, bytes memory value) external; - - /// Delete collection property. + /// @param properties Vector of properties key/value pair. + /// @dev EVM selector for this function is: 0x50b26b2a, + /// or in textual repr: setCollectionProperties((string,bytes)[]) + function setCollectionProperties(Property[] memory properties) external; + + // /// Delete collection property. + // /// + // /// @param key Property key. + // /// @dev EVM selector for this function is: 0x7b7debce, + // /// or in textual repr: deleteCollectionProperty(string) + // function deleteCollectionProperty(string memory key) external; + + /// Delete collection properties. /// - /// @param key Property key. - /// @dev EVM selector for this function is: 0x7b7debce, - /// or in textual repr: deleteCollectionProperty(string) - function deleteCollectionProperty(string memory key) external; + /// @param keys Properties keys. + /// @dev EVM selector for this function is: 0xee206ee3, + /// or in textual repr: deleteCollectionProperties(string[]) + function deleteCollectionProperties(string[] memory keys) external; /// Get collection property. /// @@ -89,14 +154,31 @@ interface Collection is Dummy, ERC165 { /// or in textual repr: collectionProperty(string) function collectionProperty(string memory key) external view returns (bytes memory); + /// Get collection properties. + /// + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0x285fb8e6, + /// or in textual repr: collectionProperties(string[]) + function collectionProperties(string[] memory keys) external view returns (Property[] memory); + + // /// Set the sponsor of the collection. + // /// + // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. + // /// + // /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. + // /// @dev EVM selector for this function is: 0x7623402e, + // /// or in textual repr: setCollectionSponsor(address) + // function setCollectionSponsor(address sponsor) external; + /// Set the sponsor of the collection. /// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. /// - /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. - /// @dev EVM selector for this function is: 0x7623402e, - /// or in textual repr: setCollectionSponsor(address) - function setCollectionSponsor(address sponsor) external; + /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract. + /// @dev EVM selector for this function is: 0x84a1d5a8, + /// or in textual repr: setCollectionSponsorCross((address,uint256)) + function setCollectionSponsorCross(CrossAddress memory sponsor) external; /// Whether there is a pending sponsor. /// @dev EVM selector for this function is: 0x058ac185, @@ -120,32 +202,21 @@ interface Collection is Dummy, ERC165 { /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x6ec0a9f1, /// or in textual repr: collectionSponsor() - function collectionSponsor() external view returns (Tuple17 memory); + function collectionSponsor() external view returns (CrossAddress memory); - /// Set limits for the collection. - /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "accountTokenOwnershipLimit", - /// "sponsoredDataSize", - /// "sponsoredDataRateLimit", - /// "tokenLimit", - /// "sponsorTransferTimeout", - /// "sponsorApproveTimeout" - /// @param value Value of the limit. - /// @dev EVM selector for this function is: 0x6a3841db, - /// or in textual repr: setCollectionLimit(string,uint32) - function setCollectionLimit(string memory limit, uint32 value) external; + /// Get current collection limits. + /// + /// @return Array of collection limits + /// @dev EVM selector for this function is: 0xf63bc572, + /// or in textual repr: collectionLimits() + function collectionLimits() external view returns (CollectionLimit[] memory); /// Set limits for the collection. /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "ownerCanTransfer", - /// "ownerCanDestroy", - /// "transfersEnabled" - /// @param value Value of the limit. - /// @dev EVM selector for this function is: 0x993b7fba, - /// or in textual repr: setCollectionLimit(string,bool) - function setCollectionLimit(string memory limit, bool value) external; + /// @param limit Some limit. + /// @dev EVM selector for this function is: 0x2316ee74, + /// or in textual repr: setCollectionLimit((uint8,(bool,uint256))) + function setCollectionLimit(CollectionLimit memory limit) external; /// Get contract address. /// @dev EVM selector for this function is: 0xf6b4dfb4, @@ -153,17 +224,29 @@ interface Collection is Dummy, ERC165 { function contractAddress() external view returns (address); /// Add collection admin. - /// @param newAdmin Address of the added administrator. - /// @dev EVM selector for this function is: 0x92e462c7, - /// or in textual repr: addCollectionAdmin(address) - function addCollectionAdmin(address newAdmin) external; + /// @param newAdmin Cross account administrator address. + /// @dev EVM selector for this function is: 0x859aa7d6, + /// or in textual repr: addCollectionAdminCross((address,uint256)) + function addCollectionAdminCross(CrossAddress memory newAdmin) external; /// Remove collection admin. - /// - /// @param admin Address of the removed administrator. - /// @dev EVM selector for this function is: 0xfafd7b42, - /// or in textual repr: removeCollectionAdmin(address) - function removeCollectionAdmin(address admin) external; + /// @param admin Cross account administrator address. + /// @dev EVM selector for this function is: 0x6c0cd173, + /// or in textual repr: removeCollectionAdminCross((address,uint256)) + function removeCollectionAdminCross(CrossAddress memory admin) external; + + // /// Add collection admin. + // /// @param newAdmin Address of the added administrator. + // /// @dev EVM selector for this function is: 0x92e462c7, + // /// or in textual repr: addCollectionAdmin(address) + // function addCollectionAdmin(address newAdmin) external; + + // /// Remove collection admin. + // /// + // /// @param admin Address of the removed administrator. + // /// @dev EVM selector for this function is: 0xfafd7b42, + // /// or in textual repr: removeCollectionAdmin(address) + // function removeCollectionAdmin(address admin) external; /// Toggle accessibility of collection nesting. /// @@ -180,6 +263,16 @@ interface Collection is Dummy, ERC165 { /// or in textual repr: setCollectionNesting(bool,address[]) function setCollectionNesting(bool enable, address[] memory collections) external; + /// Returns nesting for a collection + /// @dev EVM selector for this function is: 0x22d25bfe, + /// or in textual repr: collectionNestingRestrictedCollectionIds() + function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory); + + /// Returns permissions for a collection + /// @dev EVM selector for this function is: 0x5b2eaf4b, + /// or in textual repr: collectionNestingPermissions() + function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory); + /// Set the collection access method. /// @param mode Access mode /// 0 for Normal @@ -191,23 +284,37 @@ interface Collection is Dummy, ERC165 { /// Checks that user allowed to operate with collection. /// /// @param user User address to check. - /// @dev EVM selector for this function is: 0xd63a8e11, - /// or in textual repr: allowed(address) - function allowed(address user) external view returns (bool); - - /// Add the user to the allowed list. + /// @dev EVM selector for this function is: 0x91b6df49, + /// or in textual repr: allowlistedCross((address,uint256)) + function allowlistedCross(CrossAddress memory user) external view returns (bool); + + // /// Add the user to the allowed list. + // /// + // /// @param user Address of a trusted user. + // /// @dev EVM selector for this function is: 0x67844fe6, + // /// or in textual repr: addToCollectionAllowList(address) + // function addToCollectionAllowList(address user) external; + + /// Add user to allowed list. /// - /// @param user Address of a trusted user. - /// @dev EVM selector for this function is: 0x67844fe6, - /// or in textual repr: addToCollectionAllowList(address) - function addToCollectionAllowList(address user) external; - - /// Remove the user from the allowed list. + /// @param user User cross account address. + /// @dev EVM selector for this function is: 0xa0184a3a, + /// or in textual repr: addToCollectionAllowListCross((address,uint256)) + function addToCollectionAllowListCross(CrossAddress memory user) external; + + // /// Remove the user from the allowed list. + // /// + // /// @param user Address of a removed user. + // /// @dev EVM selector for this function is: 0x85c51acb, + // /// or in textual repr: removeFromCollectionAllowList(address) + // function removeFromCollectionAllowList(address user) external; + + /// Remove user from allowed list. /// - /// @param user Address of a removed user. - /// @dev EVM selector for this function is: 0x85c51acb, - /// or in textual repr: removeFromCollectionAllowList(address) - function removeFromCollectionAllowList(address user) external; + /// @param user User cross account address. + /// @dev EVM selector for this function is: 0x09ba452a, + /// or in textual repr: removeFromCollectionAllowListCross((address,uint256)) + function removeFromCollectionAllowListCross(CrossAddress memory user) external; /// Switch permission for minting. /// @@ -216,13 +323,21 @@ interface Collection is Dummy, ERC165 { /// or in textual repr: setCollectionMintMode(bool) function setCollectionMintMode(bool mode) external; + // /// Check that account is the owner or admin of the collection + // /// + // /// @param user account to verify + // /// @return "true" if account is the owner or admin + // /// @dev EVM selector for this function is: 0x9811b0c7, + // /// or in textual repr: isOwnerOrAdmin(address) + // function isOwnerOrAdmin(address user) external view returns (bool); + /// Check that account is the owner or admin of the collection /// - /// @param user account to verify + /// @param user User cross account to verify /// @return "true" if account is the owner or admin - /// @dev EVM selector for this function is: 0x9811b0c7, - /// or in textual repr: isOwnerOrAdmin(address) - function isOwnerOrAdmin(address user) external view returns (bool); + /// @dev EVM selector for this function is: 0x3e75a905, + /// or in textual repr: isOwnerOrAdminCross((address,uint256)) + function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool); /// Returns collection type /// @@ -237,21 +352,91 @@ interface Collection is Dummy, ERC165 { /// If address is canonical then substrate mirror is zero and vice versa. /// @dev EVM selector for this function is: 0xdf727d3b, /// or in textual repr: collectionOwner() - function collectionOwner() external view returns (Tuple17 memory); + function collectionOwner() external view returns (CrossAddress memory); + + // /// Changes collection owner to another account + // /// + // /// @dev Owner can be changed only by current owner + // /// @param newOwner new owner account + // /// @dev EVM selector for this function is: 0x4f53e226, + // /// or in textual repr: changeCollectionOwner(address) + // function changeCollectionOwner(address newOwner) external; + + /// Get collection administrators + /// + /// @return Vector of tuples with admins address and his substrate mirror. + /// If address is canonical then substrate mirror is zero and vice versa. + /// @dev EVM selector for this function is: 0x5813216b, + /// or in textual repr: collectionAdmins() + function collectionAdmins() external view returns (CrossAddress[] memory); /// Changes collection owner to another account /// /// @dev Owner can be changed only by current owner - /// @param newOwner new owner account - /// @dev EVM selector for this function is: 0x4f53e226, - /// or in textual repr: changeCollectionOwner(address) - function changeCollectionOwner(address newOwner) external; + /// @param newOwner new owner cross account + /// @dev EVM selector for this function is: 0x6496c497, + /// or in textual repr: changeCollectionOwnerCross((address,uint256)) + function changeCollectionOwnerCross(CrossAddress memory newOwner) external; } -/// @dev anonymous struct -struct Tuple17 { - address field_0; - uint256 field_1; +/// Cross account struct +struct CrossAddress { + address eth; + uint256 sub; +} + +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field. +struct CollectionNestingPermission { + CollectionPermissionField field; + bool value; +} + +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration. +enum CollectionPermissionField { + /// Owner of token can nest tokens under it. + TokenOwner, + /// Admin of token collection can nest tokens under token. + CollectionAdmin +} + +/// Nested collections. +struct CollectionNesting { + bool token_owner; + uint256[] ids; +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM. +struct CollectionLimit { + CollectionLimitField field; + OptionUint value; +} + +/// Ethereum representation of Optional value with uint256. +struct OptionUint { + bool status; + uint256 value; +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM. +enum CollectionLimitField { + /// How many tokens can a user have on one account. + AccountTokenOwnership, + /// How many bytes of data are available for sponsorship. + SponsoredDataSize, + /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`] + SponsoredDataRateLimit, + /// How many tokens can be mined into this collection. + TokenLimit, + /// Timeouts for transfer sponsoring. + SponsorTransferTimeout, + /// Timeout for sponsoring an approval in passed blocks. + SponsorApproveTimeout, + /// Whether the collection owner of the collection can send tokens (which belong to other users). + OwnerCanTransfer, + /// Can the collection owner burn other people's tokens. + OwnerCanDestroy, + /// Is it possible to send tokens from this collection between users. + TransferEnabled } /// @title ERC-721 Non-Fungible Token Standard, optional metadata extension @@ -308,14 +493,14 @@ interface ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents { /// or in textual repr: mintingFinished() function mintingFinished() external view returns (bool); - /// @notice Function to mint token. + /// @notice Function to mint a token. /// @param to The new owner /// @return uint256 The id of the newly minted token /// @dev EVM selector for this function is: 0x6a627842, /// or in textual repr: mint(address) function mint(address to) external returns (uint256); - // /// @notice Function to mint token. + // /// @notice Function to mint a token. // /// @dev `tokenId` should be obtained with `nextTokenId` method, // /// unlike standard, you can't specify it manually // /// @param to The new owner @@ -349,7 +534,7 @@ interface ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents { } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0x4468500d +/// @dev the ERC-165 identifier for this interface is 0x0e48fdb4 interface ERC721UniqueExtensions is Dummy, ERC165 { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev EVM selector for this function is: 0x06fdde03, @@ -361,6 +546,37 @@ interface ERC721UniqueExtensions is Dummy, ERC165 { /// or in textual repr: symbol() function symbol() external view returns (string memory); + /// @notice A description for the collection. + /// @dev EVM selector for this function is: 0x7284e416, + /// or in textual repr: description() + function description() external view returns (string memory); + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + /// @dev EVM selector for this function is: 0x2b29dace, + /// or in textual repr: crossOwnerOf(uint256) + function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory); + + /// Returns the token properties. + /// + /// @param tokenId Id for the token. + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0xe07ede7e, + /// or in textual repr: properties(uint256,string[]) + function properties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory); + + /// @notice Set or reaffirm the approved address for an NFT + /// @dev The zero address indicates there is no approved address. + /// @dev Throws unless `msg.sender` is the current NFT owner, or an authorized + /// operator of the current owner. + /// @param approved The new substrate address approved NFT controller + /// @param tokenId The NFT to approve + /// @dev EVM selector for this function is: 0x0ecd0ab0, + /// or in textual repr: approveCross((address,uint256),uint256) + function approveCross(CrossAddress memory approved, uint256 tokenId) external; + /// @notice Transfer ownership of an NFT /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` /// is the zero address. Throws if `tokenId` is not a valid NFT. @@ -370,20 +586,54 @@ interface ERC721UniqueExtensions is Dummy, ERC165 { /// or in textual repr: transfer(address,uint256) function transfer(address to, uint256 tokenId) external; + /// @notice Transfer ownership of an NFT + /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` + /// is the zero address. Throws if `tokenId` is not a valid NFT. + /// @param to The new owner + /// @param tokenId The NFT to transfer + /// @dev EVM selector for this function is: 0x2ada85ff, + /// or in textual repr: transferCross((address,uint256),uint256) + function transferCross(CrossAddress memory to, uint256 tokenId) external; + + /// @notice Transfer ownership of an NFT from cross account address to cross account address + /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` + /// is the zero address. Throws if `tokenId` is not a valid NFT. + /// @param from Cross acccount address of current owner + /// @param to Cross acccount address of new owner + /// @param tokenId The NFT to transfer + /// @dev EVM selector for this function is: 0xd5cf430b, + /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256) + function transferFromCross( + CrossAddress memory from, + CrossAddress memory to, + uint256 tokenId + ) external; + + // /// @notice Burns a specific ERC721 token. + // /// @dev Throws unless `msg.sender` is the current owner or an authorized + // /// operator for this NFT. Throws if `from` is not the current owner. Throws + // /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT. + // /// @param from The current owner of the NFT + // /// @param tokenId The NFT to transfer + // /// @dev EVM selector for this function is: 0x79cc6790, + // /// or in textual repr: burnFrom(address,uint256) + // function burnFrom(address from, uint256 tokenId) external; + /// @notice Burns a specific ERC721 token. /// @dev Throws unless `msg.sender` is the current owner or an authorized /// operator for this NFT. Throws if `from` is not the current owner. Throws /// if `to` is the zero address. Throws if `tokenId` is not a valid NFT. /// @param from The current owner of the NFT /// @param tokenId The NFT to transfer - /// @dev EVM selector for this function is: 0x79cc6790, - /// or in textual repr: burnFrom(address,uint256) - function burnFrom(address from, uint256 tokenId) external; + /// @dev EVM selector for this function is: 0xbb2f5a58, + /// or in textual repr: burnFromCross((address,uint256),uint256) + function burnFromCross(CrossAddress memory from, uint256 tokenId) external; /// @notice Returns next free NFT ID. /// @dev EVM selector for this function is: 0x75794a3c, /// or in textual repr: nextTokenId() function nextTokenId() external view returns (uint256); + // /// @notice Function to mint multiple tokens. // /// @dev `tokenIds` should be an array of consecutive numbers and first number // /// should be obtained with `nextTokenId` method @@ -400,12 +650,19 @@ interface ERC721UniqueExtensions is Dummy, ERC165 { // /// @param tokens array of pairs of token ID and token URI for minted tokens // /// @dev EVM selector for this function is: 0x36543006, // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[]) - // function mintBulkWithTokenURI(address to, Tuple6[] memory tokens) external returns (bool); + // function mintBulkWithTokenURI(address to, Tuple13[] memory tokens) external returns (bool); + /// @notice Function to mint a token. + /// @param to The new owner crossAccountId + /// @param properties Properties of minted token + /// @return uint256 The id of the newly minted token + /// @dev EVM selector for this function is: 0xb904db03, + /// or in textual repr: mintCross((address,uint256),(string,bytes)[]) + function mintCross(CrossAddress memory to, Property[] memory properties) external returns (uint256); } /// @dev anonymous struct -struct Tuple6 { +struct Tuple13 { uint256 field_0; string field_1; } @@ -444,7 +701,7 @@ interface ERC721Events { /// @title ERC-721 Non-Fungible Token Standard /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md -/// @dev the ERC-165 identifier for this interface is 0x80ac58cd +/// @dev the ERC-165 identifier for this interface is 0x983a942b interface ERC721 is Dummy, ERC165, ERC721Events { /// @notice Count all NFTs assigned to an owner /// @dev NFTs assigned to the zero address are considered invalid, and this @@ -510,7 +767,10 @@ interface ERC721 is Dummy, ERC165, ERC721Events { /// or in textual repr: approve(address,uint256) function approve(address approved, uint256 tokenId) external; - /// @dev Not implemented + /// @notice Sets or unsets the approval of a given operator. + /// The `operator` is allowed to transfer all tokens of the `caller` on their behalf. + /// @param operator Operator + /// @param approved Should operator status be granted or revoked? /// @dev EVM selector for this function is: 0xa22cb465, /// or in textual repr: setApprovalForAll(address,bool) function setApprovalForAll(address operator, bool approved) external; @@ -520,10 +780,15 @@ interface ERC721 is Dummy, ERC165, ERC721Events { /// or in textual repr: getApproved(uint256) function getApproved(uint256 tokenId) external view returns (address); - /// @dev Not implemented + /// @notice Tells whether the given `owner` approves the `operator`. /// @dev EVM selector for this function is: 0xe985e9c5, /// or in textual repr: isApprovedForAll(address,address) - function isApprovedForAll(address owner, address operator) external view returns (address); + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /// @notice Returns collection helper contract address + /// @dev EVM selector for this function is: 0x1896cce6, + /// or in textual repr: collectionHelperAddress() + function collectionHelperAddress() external view returns (address); } interface UniqueNFT is diff --git a/tests/src/eth/api/UniqueRefungible.sol b/tests/src/eth/api/UniqueRefungible.sol index 7ffb9d302e..ddf4f03a9b 100644 --- a/tests/src/eth/api/UniqueRefungible.sol +++ b/tests/src/eth/api/UniqueRefungible.sol @@ -13,43 +13,62 @@ interface ERC165 is Dummy { } /// @title A contract that allows to set and delete token properties and change token property permissions. -/// @dev the ERC-165 identifier for this interface is 0x41369377 +/// @dev the ERC-165 identifier for this interface is 0xde0695c2 interface TokenProperties is Dummy, ERC165 { + // /// @notice Set permissions for token property. + // /// @dev Throws error if `msg.sender` is not admin or owner of the collection. + // /// @param key Property key. + // /// @param isMutable Permission to mutate property. + // /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable. + // /// @param tokenOwner Permission to mutate property by token owner if property is mutable. + // /// @dev EVM selector for this function is: 0x222d97fa, + // /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool) + // function setTokenPropertyPermission(string memory key, bool isMutable, bool collectionAdmin, bool tokenOwner) external; + /// @notice Set permissions for token property. /// @dev Throws error if `msg.sender` is not admin or owner of the collection. - /// @param key Property key. - /// @param isMutable Permission to mutate property. - /// @param collectionAdmin Permission to mutate property by collection admin if property is mutable. - /// @param tokenOwner Permission to mutate property by token owner if property is mutable. - /// @dev EVM selector for this function is: 0x222d97fa, - /// or in textual repr: setTokenPropertyPermission(string,bool,bool,bool) - function setTokenPropertyPermission( - string memory key, - bool isMutable, - bool collectionAdmin, - bool tokenOwner - ) external; - - /// @notice Set token property value. + /// @param permissions Permissions for keys. + /// @dev EVM selector for this function is: 0xbd92983a, + /// or in textual repr: setTokenPropertyPermissions((string,(uint8,bool)[])[]) + function setTokenPropertyPermissions(TokenPropertyPermission[] memory permissions) external; + + /// @notice Get permissions for token properties. + /// @dev EVM selector for this function is: 0xf23d7790, + /// or in textual repr: tokenPropertyPermissions() + function tokenPropertyPermissions() external view returns (TokenPropertyPermission[] memory); + + // /// @notice Set token property value. + // /// @dev Throws error if `msg.sender` has no permission to edit the property. + // /// @param tokenId ID of the token. + // /// @param key Property key. + // /// @param value Property value. + // /// @dev EVM selector for this function is: 0x1752d67b, + // /// or in textual repr: setProperty(uint256,string,bytes) + // function setProperty(uint256 tokenId, string memory key, bytes memory value) external; + + /// @notice Set token properties value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. - /// @param key Property key. - /// @param value Property value. - /// @dev EVM selector for this function is: 0x1752d67b, - /// or in textual repr: setProperty(uint256,string,bytes) - function setProperty( - uint256 tokenId, - string memory key, - bytes memory value - ) external; - - /// @notice Delete token property value. + /// @param properties settable properties + /// @dev EVM selector for this function is: 0x14ed3a6e, + /// or in textual repr: setProperties(uint256,(string,bytes)[]) + function setProperties(uint256 tokenId, Property[] memory properties) external; + + // /// @notice Delete token property value. + // /// @dev Throws error if `msg.sender` has no permission to edit the property. + // /// @param tokenId ID of the token. + // /// @param key Property key. + // /// @dev EVM selector for this function is: 0x066111d1, + // /// or in textual repr: deleteProperty(uint256,string) + // function deleteProperty(uint256 tokenId, string memory key) external; + + /// @notice Delete token properties value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. - /// @param key Property key. - /// @dev EVM selector for this function is: 0x066111d1, - /// or in textual repr: deleteProperty(uint256,string) - function deleteProperty(uint256 tokenId, string memory key) external; + /// @param keys Properties key. + /// @dev EVM selector for this function is: 0xc472d371, + /// or in textual repr: deleteProperties(uint256,string[]) + function deleteProperties(uint256 tokenId, string[] memory keys) external; /// @notice Get token property value. /// @dev Throws error if key not found @@ -61,23 +80,69 @@ interface TokenProperties is Dummy, ERC165 { function property(uint256 tokenId, string memory key) external view returns (bytes memory); } +/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue). +struct Property { + string key; + bytes value; +} + +/// Ethereum representation of Token Property Permissions. +struct TokenPropertyPermission { + /// Token property key. + string key; + /// Token property permissions. + PropertyPermission[] permissions; +} + +/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value. +struct PropertyPermission { + /// TokenPermission field. + TokenPermissionField code; + /// TokenPermission value. + bool value; +} + +/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration. +enum TokenPermissionField { + /// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`] + Mutable, + /// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`] + TokenOwner, + /// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`] + CollectionAdmin +} + /// @title A contract that allows you to work with collections. -/// @dev the ERC-165 identifier for this interface is 0x62e22290 +/// @dev the ERC-165 identifier for this interface is 0x2a14cfd1 interface Collection is Dummy, ERC165 { - /// Set collection property. + // /// Set collection property. + // /// + // /// @param key Property key. + // /// @param value Propery value. + // /// @dev EVM selector for this function is: 0x2f073f66, + // /// or in textual repr: setCollectionProperty(string,bytes) + // function setCollectionProperty(string memory key, bytes memory value) external; + + /// Set collection properties. /// - /// @param key Property key. - /// @param value Propery value. - /// @dev EVM selector for this function is: 0x2f073f66, - /// or in textual repr: setCollectionProperty(string,bytes) - function setCollectionProperty(string memory key, bytes memory value) external; - - /// Delete collection property. + /// @param properties Vector of properties key/value pair. + /// @dev EVM selector for this function is: 0x50b26b2a, + /// or in textual repr: setCollectionProperties((string,bytes)[]) + function setCollectionProperties(Property[] memory properties) external; + + // /// Delete collection property. + // /// + // /// @param key Property key. + // /// @dev EVM selector for this function is: 0x7b7debce, + // /// or in textual repr: deleteCollectionProperty(string) + // function deleteCollectionProperty(string memory key) external; + + /// Delete collection properties. /// - /// @param key Property key. - /// @dev EVM selector for this function is: 0x7b7debce, - /// or in textual repr: deleteCollectionProperty(string) - function deleteCollectionProperty(string memory key) external; + /// @param keys Properties keys. + /// @dev EVM selector for this function is: 0xee206ee3, + /// or in textual repr: deleteCollectionProperties(string[]) + function deleteCollectionProperties(string[] memory keys) external; /// Get collection property. /// @@ -89,14 +154,31 @@ interface Collection is Dummy, ERC165 { /// or in textual repr: collectionProperty(string) function collectionProperty(string memory key) external view returns (bytes memory); + /// Get collection properties. + /// + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0x285fb8e6, + /// or in textual repr: collectionProperties(string[]) + function collectionProperties(string[] memory keys) external view returns (Property[] memory); + + // /// Set the sponsor of the collection. + // /// + // /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. + // /// + // /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. + // /// @dev EVM selector for this function is: 0x7623402e, + // /// or in textual repr: setCollectionSponsor(address) + // function setCollectionSponsor(address sponsor) external; + /// Set the sponsor of the collection. /// /// @dev In order for sponsorship to work, it must be confirmed on behalf of the sponsor. /// - /// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract. - /// @dev EVM selector for this function is: 0x7623402e, - /// or in textual repr: setCollectionSponsor(address) - function setCollectionSponsor(address sponsor) external; + /// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract. + /// @dev EVM selector for this function is: 0x84a1d5a8, + /// or in textual repr: setCollectionSponsorCross((address,uint256)) + function setCollectionSponsorCross(CrossAddress memory sponsor) external; /// Whether there is a pending sponsor. /// @dev EVM selector for this function is: 0x058ac185, @@ -120,32 +202,21 @@ interface Collection is Dummy, ERC165 { /// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw. /// @dev EVM selector for this function is: 0x6ec0a9f1, /// or in textual repr: collectionSponsor() - function collectionSponsor() external view returns (Tuple17 memory); + function collectionSponsor() external view returns (CrossAddress memory); - /// Set limits for the collection. - /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "accountTokenOwnershipLimit", - /// "sponsoredDataSize", - /// "sponsoredDataRateLimit", - /// "tokenLimit", - /// "sponsorTransferTimeout", - /// "sponsorApproveTimeout" - /// @param value Value of the limit. - /// @dev EVM selector for this function is: 0x6a3841db, - /// or in textual repr: setCollectionLimit(string,uint32) - function setCollectionLimit(string memory limit, uint32 value) external; + /// Get current collection limits. + /// + /// @return Array of collection limits + /// @dev EVM selector for this function is: 0xf63bc572, + /// or in textual repr: collectionLimits() + function collectionLimits() external view returns (CollectionLimit[] memory); /// Set limits for the collection. /// @dev Throws error if limit not found. - /// @param limit Name of the limit. Valid names: - /// "ownerCanTransfer", - /// "ownerCanDestroy", - /// "transfersEnabled" - /// @param value Value of the limit. - /// @dev EVM selector for this function is: 0x993b7fba, - /// or in textual repr: setCollectionLimit(string,bool) - function setCollectionLimit(string memory limit, bool value) external; + /// @param limit Some limit. + /// @dev EVM selector for this function is: 0x2316ee74, + /// or in textual repr: setCollectionLimit((uint8,(bool,uint256))) + function setCollectionLimit(CollectionLimit memory limit) external; /// Get contract address. /// @dev EVM selector for this function is: 0xf6b4dfb4, @@ -153,17 +224,29 @@ interface Collection is Dummy, ERC165 { function contractAddress() external view returns (address); /// Add collection admin. - /// @param newAdmin Address of the added administrator. - /// @dev EVM selector for this function is: 0x92e462c7, - /// or in textual repr: addCollectionAdmin(address) - function addCollectionAdmin(address newAdmin) external; + /// @param newAdmin Cross account administrator address. + /// @dev EVM selector for this function is: 0x859aa7d6, + /// or in textual repr: addCollectionAdminCross((address,uint256)) + function addCollectionAdminCross(CrossAddress memory newAdmin) external; /// Remove collection admin. - /// - /// @param admin Address of the removed administrator. - /// @dev EVM selector for this function is: 0xfafd7b42, - /// or in textual repr: removeCollectionAdmin(address) - function removeCollectionAdmin(address admin) external; + /// @param admin Cross account administrator address. + /// @dev EVM selector for this function is: 0x6c0cd173, + /// or in textual repr: removeCollectionAdminCross((address,uint256)) + function removeCollectionAdminCross(CrossAddress memory admin) external; + + // /// Add collection admin. + // /// @param newAdmin Address of the added administrator. + // /// @dev EVM selector for this function is: 0x92e462c7, + // /// or in textual repr: addCollectionAdmin(address) + // function addCollectionAdmin(address newAdmin) external; + + // /// Remove collection admin. + // /// + // /// @param admin Address of the removed administrator. + // /// @dev EVM selector for this function is: 0xfafd7b42, + // /// or in textual repr: removeCollectionAdmin(address) + // function removeCollectionAdmin(address admin) external; /// Toggle accessibility of collection nesting. /// @@ -180,6 +263,16 @@ interface Collection is Dummy, ERC165 { /// or in textual repr: setCollectionNesting(bool,address[]) function setCollectionNesting(bool enable, address[] memory collections) external; + /// Returns nesting for a collection + /// @dev EVM selector for this function is: 0x22d25bfe, + /// or in textual repr: collectionNestingRestrictedCollectionIds() + function collectionNestingRestrictedCollectionIds() external view returns (CollectionNesting memory); + + /// Returns permissions for a collection + /// @dev EVM selector for this function is: 0x5b2eaf4b, + /// or in textual repr: collectionNestingPermissions() + function collectionNestingPermissions() external view returns (CollectionNestingPermission[] memory); + /// Set the collection access method. /// @param mode Access mode /// 0 for Normal @@ -191,23 +284,37 @@ interface Collection is Dummy, ERC165 { /// Checks that user allowed to operate with collection. /// /// @param user User address to check. - /// @dev EVM selector for this function is: 0xd63a8e11, - /// or in textual repr: allowed(address) - function allowed(address user) external view returns (bool); - - /// Add the user to the allowed list. + /// @dev EVM selector for this function is: 0x91b6df49, + /// or in textual repr: allowlistedCross((address,uint256)) + function allowlistedCross(CrossAddress memory user) external view returns (bool); + + // /// Add the user to the allowed list. + // /// + // /// @param user Address of a trusted user. + // /// @dev EVM selector for this function is: 0x67844fe6, + // /// or in textual repr: addToCollectionAllowList(address) + // function addToCollectionAllowList(address user) external; + + /// Add user to allowed list. /// - /// @param user Address of a trusted user. - /// @dev EVM selector for this function is: 0x67844fe6, - /// or in textual repr: addToCollectionAllowList(address) - function addToCollectionAllowList(address user) external; - - /// Remove the user from the allowed list. + /// @param user User cross account address. + /// @dev EVM selector for this function is: 0xa0184a3a, + /// or in textual repr: addToCollectionAllowListCross((address,uint256)) + function addToCollectionAllowListCross(CrossAddress memory user) external; + + // /// Remove the user from the allowed list. + // /// + // /// @param user Address of a removed user. + // /// @dev EVM selector for this function is: 0x85c51acb, + // /// or in textual repr: removeFromCollectionAllowList(address) + // function removeFromCollectionAllowList(address user) external; + + /// Remove user from allowed list. /// - /// @param user Address of a removed user. - /// @dev EVM selector for this function is: 0x85c51acb, - /// or in textual repr: removeFromCollectionAllowList(address) - function removeFromCollectionAllowList(address user) external; + /// @param user User cross account address. + /// @dev EVM selector for this function is: 0x09ba452a, + /// or in textual repr: removeFromCollectionAllowListCross((address,uint256)) + function removeFromCollectionAllowListCross(CrossAddress memory user) external; /// Switch permission for minting. /// @@ -216,13 +323,21 @@ interface Collection is Dummy, ERC165 { /// or in textual repr: setCollectionMintMode(bool) function setCollectionMintMode(bool mode) external; + // /// Check that account is the owner or admin of the collection + // /// + // /// @param user account to verify + // /// @return "true" if account is the owner or admin + // /// @dev EVM selector for this function is: 0x9811b0c7, + // /// or in textual repr: isOwnerOrAdmin(address) + // function isOwnerOrAdmin(address user) external view returns (bool); + /// Check that account is the owner or admin of the collection /// - /// @param user account to verify + /// @param user User cross account to verify /// @return "true" if account is the owner or admin - /// @dev EVM selector for this function is: 0x9811b0c7, - /// or in textual repr: isOwnerOrAdmin(address) - function isOwnerOrAdmin(address user) external view returns (bool); + /// @dev EVM selector for this function is: 0x3e75a905, + /// or in textual repr: isOwnerOrAdminCross((address,uint256)) + function isOwnerOrAdminCross(CrossAddress memory user) external view returns (bool); /// Returns collection type /// @@ -237,21 +352,91 @@ interface Collection is Dummy, ERC165 { /// If address is canonical then substrate mirror is zero and vice versa. /// @dev EVM selector for this function is: 0xdf727d3b, /// or in textual repr: collectionOwner() - function collectionOwner() external view returns (Tuple17 memory); + function collectionOwner() external view returns (CrossAddress memory); + + // /// Changes collection owner to another account + // /// + // /// @dev Owner can be changed only by current owner + // /// @param newOwner new owner account + // /// @dev EVM selector for this function is: 0x4f53e226, + // /// or in textual repr: changeCollectionOwner(address) + // function changeCollectionOwner(address newOwner) external; + + /// Get collection administrators + /// + /// @return Vector of tuples with admins address and his substrate mirror. + /// If address is canonical then substrate mirror is zero and vice versa. + /// @dev EVM selector for this function is: 0x5813216b, + /// or in textual repr: collectionAdmins() + function collectionAdmins() external view returns (CrossAddress[] memory); /// Changes collection owner to another account /// /// @dev Owner can be changed only by current owner - /// @param newOwner new owner account - /// @dev EVM selector for this function is: 0x4f53e226, - /// or in textual repr: changeCollectionOwner(address) - function changeCollectionOwner(address newOwner) external; + /// @param newOwner new owner cross account + /// @dev EVM selector for this function is: 0x6496c497, + /// or in textual repr: changeCollectionOwnerCross((address,uint256)) + function changeCollectionOwnerCross(CrossAddress memory newOwner) external; } -/// @dev anonymous struct -struct Tuple17 { - address field_0; - uint256 field_1; +/// Cross account struct +struct CrossAddress { + address eth; + uint256 sub; +} + +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field. +struct CollectionNestingPermission { + CollectionPermissionField field; + bool value; +} + +/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration. +enum CollectionPermissionField { + /// Owner of token can nest tokens under it. + TokenOwner, + /// Admin of token collection can nest tokens under token. + CollectionAdmin +} + +/// Nested collections. +struct CollectionNesting { + bool token_owner; + uint256[] ids; +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM. +struct CollectionLimit { + CollectionLimitField field; + OptionUint value; +} + +/// Ethereum representation of Optional value with uint256. +struct OptionUint { + bool status; + uint256 value; +} + +/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM. +enum CollectionLimitField { + /// How many tokens can a user have on one account. + AccountTokenOwnership, + /// How many bytes of data are available for sponsorship. + SponsoredDataSize, + /// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`] + SponsoredDataRateLimit, + /// How many tokens can be mined into this collection. + TokenLimit, + /// Timeouts for transfer sponsoring. + SponsorTransferTimeout, + /// Timeout for sponsoring an approval in passed blocks. + SponsorApproveTimeout, + /// Whether the collection owner of the collection can send tokens (which belong to other users). + OwnerCanTransfer, + /// Can the collection owner burn other people's tokens. + OwnerCanDestroy, + /// Is it possible to send tokens from this collection between users. + TransferEnabled } /// @dev the ERC-165 identifier for this interface is 0x5b5e139f @@ -306,14 +491,14 @@ interface ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents { /// or in textual repr: mintingFinished() function mintingFinished() external view returns (bool); - /// @notice Function to mint token. + /// @notice Function to mint a token. /// @param to The new owner /// @return uint256 The id of the newly minted token /// @dev EVM selector for this function is: 0x6a627842, /// or in textual repr: mint(address) function mint(address to) external returns (uint256); - // /// @notice Function to mint token. + // /// @notice Function to mint a token. // /// @dev `tokenId` should be obtained with `nextTokenId` method, // /// unlike standard, you can't specify it manually // /// @param to The new owner @@ -347,7 +532,7 @@ interface ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents { } /// @title Unique extensions for ERC721. -/// @dev the ERC-165 identifier for this interface is 0xef1eaacb +/// @dev the ERC-165 identifier for this interface is 0xabf30dc2 interface ERC721UniqueExtensions is Dummy, ERC165 { /// @notice A descriptive name for a collection of NFTs in this contract /// @dev EVM selector for this function is: 0x06fdde03, @@ -359,6 +544,27 @@ interface ERC721UniqueExtensions is Dummy, ERC165 { /// or in textual repr: symbol() function symbol() external view returns (string memory); + /// @notice A description for the collection. + /// @dev EVM selector for this function is: 0x7284e416, + /// or in textual repr: description() + function description() external view returns (string memory); + + /// Returns the owner (in cross format) of the token. + /// + /// @param tokenId Id for the token. + /// @dev EVM selector for this function is: 0x2b29dace, + /// or in textual repr: crossOwnerOf(uint256) + function crossOwnerOf(uint256 tokenId) external view returns (CrossAddress memory); + + /// Returns the token properties. + /// + /// @param tokenId Id for the token. + /// @param keys Properties keys. Empty keys for all propertyes. + /// @return Vector of properties key/value pairs. + /// @dev EVM selector for this function is: 0xe07ede7e, + /// or in textual repr: properties(uint256,string[]) + function properties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory); + /// @notice Transfer ownership of an RFT /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` /// is the zero address. Throws if `tokenId` is not a valid RFT. @@ -369,6 +575,41 @@ interface ERC721UniqueExtensions is Dummy, ERC165 { /// or in textual repr: transfer(address,uint256) function transfer(address to, uint256 tokenId) external; + /// @notice Transfer ownership of an RFT + /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` + /// is the zero address. Throws if `tokenId` is not a valid RFT. + /// Throws if RFT pieces have multiple owners. + /// @param to The new owner + /// @param tokenId The RFT to transfer + /// @dev EVM selector for this function is: 0x2ada85ff, + /// or in textual repr: transferCross((address,uint256),uint256) + function transferCross(CrossAddress memory to, uint256 tokenId) external; + + /// @notice Transfer ownership of an RFT + /// @dev Throws unless `msg.sender` is the current owner. Throws if `to` + /// is the zero address. Throws if `tokenId` is not a valid RFT. + /// Throws if RFT pieces have multiple owners. + /// @param to The new owner + /// @param tokenId The RFT to transfer + /// @dev EVM selector for this function is: 0xd5cf430b, + /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256) + function transferFromCross( + CrossAddress memory from, + CrossAddress memory to, + uint256 tokenId + ) external; + + // /// @notice Burns a specific ERC721 token. + // /// @dev Throws unless `msg.sender` is the current owner or an authorized + // /// operator for this RFT. Throws if `from` is not the current owner. Throws + // /// if `to` is the zero address. Throws if `tokenId` is not a valid RFT. + // /// Throws if RFT pieces have multiple owners. + // /// @param from The current owner of the RFT + // /// @param tokenId The RFT to transfer + // /// @dev EVM selector for this function is: 0x79cc6790, + // /// or in textual repr: burnFrom(address,uint256) + // function burnFrom(address from, uint256 tokenId) external; + /// @notice Burns a specific ERC721 token. /// @dev Throws unless `msg.sender` is the current owner or an authorized /// operator for this RFT. Throws if `from` is not the current owner. Throws @@ -376,9 +617,9 @@ interface ERC721UniqueExtensions is Dummy, ERC165 { /// Throws if RFT pieces have multiple owners. /// @param from The current owner of the RFT /// @param tokenId The RFT to transfer - /// @dev EVM selector for this function is: 0x79cc6790, - /// or in textual repr: burnFrom(address,uint256) - function burnFrom(address from, uint256 tokenId) external; + /// @dev EVM selector for this function is: 0xbb2f5a58, + /// or in textual repr: burnFromCross((address,uint256),uint256) + function burnFromCross(CrossAddress memory from, uint256 tokenId) external; /// @notice Returns next free RFT ID. /// @dev EVM selector for this function is: 0x75794a3c, @@ -401,7 +642,15 @@ interface ERC721UniqueExtensions is Dummy, ERC165 { // /// @param tokens array of pairs of token ID and token URI for minted tokens // /// @dev EVM selector for this function is: 0x36543006, // /// or in textual repr: mintBulkWithTokenURI(address,(uint256,string)[]) - // function mintBulkWithTokenURI(address to, Tuple6[] memory tokens) external returns (bool); + // function mintBulkWithTokenURI(address to, Tuple12[] memory tokens) external returns (bool); + + /// @notice Function to mint a token. + /// @param to The new owner crossAccountId + /// @param properties Properties of minted token + /// @return uint256 The id of the newly minted token + /// @dev EVM selector for this function is: 0xb904db03, + /// or in textual repr: mintCross((address,uint256),(string,bytes)[]) + function mintCross(CrossAddress memory to, Property[] memory properties) external returns (uint256); /// Returns EVM address for refungible token /// @@ -412,7 +661,7 @@ interface ERC721UniqueExtensions is Dummy, ERC165 { } /// @dev anonymous struct -struct Tuple6 { +struct Tuple12 { uint256 field_0; string field_1; } @@ -451,7 +700,7 @@ interface ERC721Events { /// @title ERC-721 Non-Fungible Token Standard /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md -/// @dev the ERC-165 identifier for this interface is 0x58800161 +/// @dev the ERC-165 identifier for this interface is 0x4016cd87 interface ERC721 is Dummy, ERC165, ERC721Events { /// @notice Count all RFTs assigned to an owner /// @dev RFTs assigned to the zero address are considered invalid, and this @@ -515,7 +764,10 @@ interface ERC721 is Dummy, ERC165, ERC721Events { /// or in textual repr: approve(address,uint256) function approve(address approved, uint256 tokenId) external; - /// @dev Not implemented + /// @notice Sets or unsets the approval of a given operator. + /// The `operator` is allowed to transfer all token pieces of the `caller` on their behalf. + /// @param operator Operator + /// @param approved Should operator status be granted or revoked? /// @dev EVM selector for this function is: 0xa22cb465, /// or in textual repr: setApprovalForAll(address,bool) function setApprovalForAll(address operator, bool approved) external; @@ -525,10 +777,15 @@ interface ERC721 is Dummy, ERC165, ERC721Events { /// or in textual repr: getApproved(uint256) function getApproved(uint256 tokenId) external view returns (address); - /// @dev Not implemented + /// @notice Tells whether the given `owner` approves the `operator`. /// @dev EVM selector for this function is: 0xe985e9c5, /// or in textual repr: isApprovedForAll(address,address) - function isApprovedForAll(address owner, address operator) external view returns (address); + function isApprovedForAll(address owner, address operator) external view returns (bool); + + /// @notice Returns collection helper contract address + /// @dev EVM selector for this function is: 0x1896cce6, + /// or in textual repr: collectionHelperAddress() + function collectionHelperAddress() external view returns (address); } interface UniqueRefungible is diff --git a/tests/src/eth/api/UniqueRefungibleToken.sol b/tests/src/eth/api/UniqueRefungibleToken.sol index eb5058127f..4bfc5aea73 100644 --- a/tests/src/eth/api/UniqueRefungibleToken.sol +++ b/tests/src/eth/api/UniqueRefungibleToken.sol @@ -23,7 +23,7 @@ interface ERC1633 is Dummy, ERC165 { function parentTokenId() external view returns (uint256); } -/// @dev the ERC-165 identifier for this interface is 0xab8deb37 +/// @dev the ERC-165 identifier for this interface is 0xe17a7d2b interface ERC20UniqueExtensions is Dummy, ERC165 { /// @dev Function that burns an amount of the token of a given account, /// deducting from the sender's allowance for said account. @@ -33,12 +33,56 @@ interface ERC20UniqueExtensions is Dummy, ERC165 { /// or in textual repr: burnFrom(address,uint256) function burnFrom(address from, uint256 amount) external returns (bool); + /// @dev Function that burns an amount of the token of a given account, + /// deducting from the sender's allowance for said account. + /// @param from The account whose tokens will be burnt. + /// @param amount The amount that will be burnt. + /// @dev EVM selector for this function is: 0xbb2f5a58, + /// or in textual repr: burnFromCross((address,uint256),uint256) + function burnFromCross(CrossAddress memory from, uint256 amount) external returns (bool); + + /// @dev Approve the passed address to spend the specified amount of tokens on behalf of `msg.sender`. + /// Beware that changing an allowance with this method brings the risk that someone may use both the old + /// and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this + /// race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: + /// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + /// @param spender The crossaccount which will spend the funds. + /// @param amount The amount of tokens to be spent. + /// @dev EVM selector for this function is: 0x0ecd0ab0, + /// or in textual repr: approveCross((address,uint256),uint256) + function approveCross(CrossAddress memory spender, uint256 amount) external returns (bool); + /// @dev Function that changes total amount of the tokens. /// Throws if `msg.sender` doesn't owns all of the tokens. /// @param amount New total amount of the tokens. /// @dev EVM selector for this function is: 0xd2418ca7, /// or in textual repr: repartition(uint256) function repartition(uint256 amount) external returns (bool); + + /// @dev Transfer token for a specified address + /// @param to The crossaccount to transfer to. + /// @param amount The amount to be transferred. + /// @dev EVM selector for this function is: 0x2ada85ff, + /// or in textual repr: transferCross((address,uint256),uint256) + function transferCross(CrossAddress memory to, uint256 amount) external returns (bool); + + /// @dev Transfer tokens from one address to another + /// @param from The address which you want to send tokens from + /// @param to The address which you want to transfer to + /// @param amount the amount of tokens to be transferred + /// @dev EVM selector for this function is: 0xd5cf430b, + /// or in textual repr: transferFromCross((address,uint256),(address,uint256),uint256) + function transferFromCross( + CrossAddress memory from, + CrossAddress memory to, + uint256 amount + ) external returns (bool); +} + +/// Cross account struct +struct CrossAddress { + address eth; + uint256 sub; } /// @dev inlined interface diff --git a/tests/src/eth/base.test.ts b/tests/src/eth/base.test.ts index af1fcb1718..8bb20ab58e 100644 --- a/tests/src/eth/base.test.ts +++ b/tests/src/eth/base.test.ts @@ -57,7 +57,7 @@ describe('Contract calls', () => { const {tokenId} = await collection.mintToken(alice, {Ethereum: caller}); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'nft', caller); + const contract = await helper.ethNativeContract.collection(address, 'nft', caller); const cost = await helper.eth.calculateFee({Ethereum: caller}, () => contract.methods.transfer(receiver, tokenId).send(caller)); @@ -79,8 +79,8 @@ describe('ERC165 tests', () => { const BASE_URI = 'base/'; async function checkInterface(helper: EthUniqueHelper, interfaceId: string, simpleResult: boolean, compatibleResult: boolean) { - const simple = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(simpleNftCollectionId), 'nft', minter); - const compatible = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(erc721MetadataCompatibleNftCollectionId), 'nft', minter); + const simple = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(simpleNftCollectionId), 'nft', minter); + const compatible = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(erc721MetadataCompatibleNftCollectionId), 'nft', minter); expect(await simple.methods.supportsInterface(interfaceId).call()).to.equal(simpleResult, `empty (not ERC721Metadata compatible) NFT collection returns not ${simpleResult}`); expect(await compatible.methods.supportsInterface(interfaceId).call()).to.equal(compatibleResult, `ERC721Metadata compatible NFT collection returns not ${compatibleResult}`); @@ -116,8 +116,8 @@ describe('ERC165 tests', () => { await checkInterface(helper, '0x780e9d63', true, true); }); - itEth('ERC721UniqueExtensions - 0x4468500d - support', async ({helper}) => { - await checkInterface(helper, '0x4468500d', true, true); + itEth.skip('ERC721UniqueExtensions support', async ({helper}) => { + await checkInterface(helper, '0xb74c26b7', true, true); }); itEth('ERC721Burnable - 0x42966c68 - support', async ({helper}) => { diff --git a/tests/src/eth/collectionAdmin.test.ts b/tests/src/eth/collectionAdmin.test.ts index f30b2b2222..51c99db446 100644 --- a/tests/src/eth/collectionAdmin.test.ts +++ b/tests/src/eth/collectionAdmin.test.ts @@ -14,7 +14,11 @@ // along with Unique Network. If not, see . import {IKeyringPair} from '@polkadot/types/types'; -import {usingEthPlaygrounds, itEth, expect, EthUniqueHelper} from './util'; +import {expect} from 'chai'; +import {Pallets} from '../util'; +import {IEthCrossAccountId} from '../util/playgrounds/types'; +import {usingEthPlaygrounds, itEth} from './util'; +import {EthUniqueHelper} from './util/playgrounds/unique.dev'; async function recordEthFee(helper: EthUniqueHelper, userAddress: string, call: () => Promise) { const before = await helper.balance.getSubstrate(helper.address.ethToSubstrate(userAddress)); @@ -36,49 +40,123 @@ describe('Add collection admins', () => { }); }); - itEth('Add admin by owner', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - - const newAdmin = helper.eth.createAccount(); + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + {mode: 'ft' as const, requiredPallets: []}, + ].map(testCase => { + itEth.ifWithPallets(`can add account admin by owner for ${testCase.mode}`, testCase.requiredPallets, async ({helper, privateKey}) => { + // arrange + const owner = await helper.eth.createAccountWithBalance(donor); + const adminSub = await privateKey('//admin2'); + const adminEth = helper.eth.createAccount().toLowerCase(); + + const adminDeprecated = helper.eth.createAccount().toLowerCase(); + const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub); + const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth); + + const {collectionAddress, collectionId} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner, true); + + // Check isOwnerOrAdminCross returns false: + expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossSub).call()).to.be.false; + expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossEth).call()).to.be.false; + expect(await collectionEvm.methods.isOwnerOrAdminCross(helper.ethCrossAccount.fromAddress(adminDeprecated)).call()).to.be.false; + + // Soft-deprecated: can addCollectionAdmin + await collectionEvm.methods.addCollectionAdmin(adminDeprecated).send(); + // Can addCollectionAdminCross for substrate and ethereum address + await collectionEvm.methods.addCollectionAdminCross(adminCrossSub).send(); + await collectionEvm.methods.addCollectionAdminCross(adminCrossEth).send(); + + // 1. Expect api.rpc.unique.adminlist returns admins: + const adminListRpc = await helper.collection.getAdmins(collectionId); + expect(adminListRpc).to.has.length(3); + expect(adminListRpc).to.be.deep.contain.members([{Substrate: adminSub.address}, {Ethereum: adminEth}, {Ethereum: adminDeprecated}]); + + // 2. Expect methods.collectionAdmins == api.rpc.unique.adminlist + let adminListEth = await collectionEvm.methods.collectionAdmins().call(); + adminListEth = adminListEth.map((element: IEthCrossAccountId) => { + return helper.address.convertCrossAccountFromEthCrossAccount(element); + }); + expect(adminListRpc).to.be.like(adminListEth); + + // 3. check isOwnerOrAdminCross returns true: + expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossSub).call()).to.be.true; + expect(await collectionEvm.methods.isOwnerOrAdminCross(adminCrossEth).call()).to.be.true; + expect(await collectionEvm.methods.isOwnerOrAdminCross(helper.ethCrossAccount.fromAddress(adminDeprecated)).call()).to.be.true; + }); + }); - await collectionEvm.methods.addCollectionAdmin(newAdmin).send(); - const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]); - expect(adminList[0].asEthereum.toString().toLocaleLowerCase()) - .to.be.eq(newAdmin.toLocaleLowerCase()); + itEth('cross account admin can mint', async ({helper}) => { + // arrange: create collection and accounts + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', 'a', 'b', 'uri'); + const adminEth = (await helper.eth.createAccountWithBalance(donor)).toLowerCase(); + const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth); + const [adminSub] = await helper.arrange.createAccounts([100n], donor); + const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true); + + // cannot mint while not admin + await expect(collectionEvm.methods.mint(owner).send({from: adminEth})).to.be.rejected; + await expect(helper.nft.mintToken(adminSub, {collectionId, owner: {Ethereum: owner}})).to.be.rejectedWith(/common.PublicMintingNotAllowed/); + + // admin (sub and eth) can mint token: + await collectionEvm.methods.addCollectionAdminCross(adminCrossEth).send(); + await collectionEvm.methods.addCollectionAdminCross(adminCrossSub).send(); + await collectionEvm.methods.mint(owner).send({from: adminEth}); + await helper.nft.mintToken(adminSub, {collectionId, owner: {Ethereum: owner}}); + + expect(await helper.collection.getLastTokenId(collectionId)).to.eq(2); }); - itEth.skip('Add substrate admin by owner', async ({helper}) => { + itEth('cannot add invalid cross account admin', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const [admin] = await helper.arrange.createAccounts([100n, 100n], donor); - const [newAdmin] = await helper.arrange.createAccounts([10n], donor); - await collectionEvm.methods.addCollectionAdminSubstrate(newAdmin.addressRaw).send(); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]); - expect(adminList[0].asSubstrate.toString().toLocaleLowerCase()) - .to.be.eq(newAdmin.address.toLocaleLowerCase()); + const adminCross = { + eth: helper.address.substrateToEth(admin.address), + sub: admin.addressRaw, + }; + await expect(collectionEvm.methods.addCollectionAdminCross(adminCross).send()).to.be.rejected; }); - itEth('Verify owner or admin', async ({helper}) => { + itEth('can verify owner with methods.isOwnerOrAdmin[Cross]', async ({helper, privateKey}) => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const newAdmin = helper.eth.createAccount(); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - expect(await collectionEvm.methods.isOwnerOrAdmin(newAdmin).call()).to.be.false; - await collectionEvm.methods.addCollectionAdmin(newAdmin).send(); - expect(await collectionEvm.methods.isOwnerOrAdmin(newAdmin).call()).to.be.true; + const adminDeprecated = helper.eth.createAccount(); + const admin1Cross = helper.ethCrossAccount.fromKeyringPair(await privateKey('admin')); + const admin2Cross = helper.ethCrossAccount.fromAddress(helper.address.substrateToEth((await privateKey('admin3')).address)); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true); + + // Soft-deprecated: + expect(await collectionEvm.methods.isOwnerOrAdmin(adminDeprecated).call()).to.be.false; + expect(await collectionEvm.methods.isOwnerOrAdminCross(admin1Cross).call()).to.be.false; + expect(await collectionEvm.methods.isOwnerOrAdminCross(admin2Cross).call()).to.be.false; + + await collectionEvm.methods.addCollectionAdmin(adminDeprecated).send(); + await collectionEvm.methods.addCollectionAdminCross(admin1Cross).send(); + await collectionEvm.methods.addCollectionAdminCross(admin2Cross).send(); + + // Soft-deprecated: isOwnerOrAdmin returns true + expect(await collectionEvm.methods.isOwnerOrAdmin(adminDeprecated).call()).to.be.true; + // Expect isOwnerOrAdminCross return true + expect(await collectionEvm.methods.isOwnerOrAdminCross(admin1Cross).call()).to.be.true; + expect(await collectionEvm.methods.isOwnerOrAdminCross(admin2Cross).call()).to.be.true; }); + // Soft-deprecated itEth('(!negative tests!) Add admin by ADMIN is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const admin = await helper.eth.createAccountWithBalance(donor); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true); await collectionEvm.methods.addCollectionAdmin(admin).send(); const user = helper.eth.createAccount(); @@ -91,12 +169,13 @@ describe('Add collection admins', () => { .to.be.eq(admin.toLocaleLowerCase()); }); + // Soft-deprecated itEth('(!negative tests!) Add admin by USER is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const notAdmin = await helper.eth.createAccountWithBalance(donor); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true); const user = helper.eth.createAccount(); await expect(collectionEvm.methods.addCollectionAdmin(user).call({from: notAdmin})) @@ -106,32 +185,36 @@ describe('Add collection admins', () => { expect(adminList.length).to.be.eq(0); }); - itEth.skip('(!negative tests!) Add substrate admin by ADMIN is not allowed', async ({helper}) => { + itEth('(!negative tests!) Add [cross] admin by ADMIN is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const admin = await helper.eth.createAccountWithBalance(donor); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - await collectionEvm.methods.addCollectionAdmin(admin).send(); + const [admin, notAdmin] = await helper.arrange.createAccounts([10n, 10n], donor); + const adminCross = helper.ethCrossAccount.fromKeyringPair(admin); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + await collectionEvm.methods.addCollectionAdminCross(adminCross).send(); - const [notAdmin] = await helper.arrange.createAccounts([10n], donor); - await expect(collectionEvm.methods.addCollectionAdminSubstrate(notAdmin.addressRaw).call({from: admin})) + const notAdminCross = helper.ethCrossAccount.fromKeyringPair(notAdmin); + await expect(collectionEvm.methods.addCollectionAdminCross(notAdminCross).call({from: adminCross.eth})) .to.be.rejectedWith('NoPermission'); const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]); expect(adminList.length).to.be.eq(1); - expect(adminList[0].asEthereum.toString().toLocaleLowerCase()) - .to.be.eq(admin.toLocaleLowerCase()); + + const admin0Cross = helper.ethCrossAccount.fromKeyringPair(adminList[0]); + expect(admin0Cross.eth.toLocaleLowerCase()) + .to.be.eq(adminCross.eth.toLocaleLowerCase()); }); - itEth.skip('(!negative tests!) Add substrate admin by USER is not allowed', async ({helper}) => { + itEth('(!negative tests!) Add [cross] admin by USER is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const notAdmin0 = await helper.eth.createAccountWithBalance(donor); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); const [notAdmin1] = await helper.arrange.createAccounts([10n], donor); - await expect(collectionEvm.methods.addCollectionAdminSubstrate(notAdmin1.addressRaw).call({from: notAdmin0})) + const notAdmin1Cross = helper.ethCrossAccount.fromKeyringPair(notAdmin1); + await expect(collectionEvm.methods.addCollectionAdminCross(notAdmin1Cross).call({from: notAdmin0})) .to.be.rejectedWith('NoPermission'); const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]); @@ -148,12 +231,13 @@ describe('Remove collection admins', () => { }); }); + // Soft-deprecated itEth('Remove admin by owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const newAdmin = helper.eth.createAccount(); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true); await collectionEvm.methods.addCollectionAdmin(newAdmin).send(); { @@ -168,29 +252,41 @@ describe('Remove collection admins', () => { expect(adminList.length).to.be.eq(0); }); - itEth.skip('Remove substrate admin by owner', async ({helper}) => { + itEth('Remove [cross] admin by owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const [newAdmin] = await helper.arrange.createAccounts([10n], donor); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - await collectionEvm.methods.addCollectionAdminSubstrate(newAdmin.addressRaw).send(); + const [adminSub] = await helper.arrange.createAccounts([10n], donor); + const adminEth = (await helper.eth.createAccountWithBalance(donor)).toLowerCase(); + const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub); + const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth); + + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + await collectionEvm.methods.addCollectionAdminCross(adminCrossSub).send(); + await collectionEvm.methods.addCollectionAdminCross(adminCrossEth).send(); + { - const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]); - expect(adminList[0].asSubstrate.toString().toLocaleLowerCase()) - .to.be.eq(newAdmin.address.toLocaleLowerCase()); + const adminList = await helper.collection.getAdmins(collectionId); + expect(adminList).to.deep.include({Substrate: adminSub.address}); + expect(adminList).to.deep.include({Ethereum: adminEth}); } - await collectionEvm.methods.removeCollectionAdminSubstrate(newAdmin.addressRaw).send(); - const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]); + await collectionEvm.methods.removeCollectionAdminCross(adminCrossSub).send(); + await collectionEvm.methods.removeCollectionAdminCross(adminCrossEth).send(); + const adminList = await helper.collection.getAdmins(collectionId); expect(adminList.length).to.be.eq(0); + + // Non admin cannot mint: + await expect(helper.nft.mintToken(adminSub, {collectionId, owner: {Substrate: adminSub.address}})).to.be.rejectedWith(/common.PublicMintingNotAllowed/); + await expect(collectionEvm.methods.mint(adminEth).send({from: adminEth})).to.be.rejected; }); + // Soft-deprecated itEth('(!negative tests!) Remove admin by ADMIN is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true); const admin0 = await helper.eth.createAccountWithBalance(donor); await collectionEvm.methods.addCollectionAdmin(admin0).send(); @@ -208,11 +304,12 @@ describe('Remove collection admins', () => { } }); + // Soft-deprecated itEth('(!negative tests!) Remove admin by USER is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true); const admin = await helper.eth.createAccountWithBalance(donor); await collectionEvm.methods.addCollectionAdmin(admin).send(); @@ -228,36 +325,40 @@ describe('Remove collection admins', () => { } }); - itEth.skip('(!negative tests!) Remove substrate admin by ADMIN is not allowed', async ({helper}) => { + itEth('(!negative tests!) Remove [cross] admin by ADMIN is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const [adminSub] = await helper.arrange.createAccounts([10n], donor); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - await collectionEvm.methods.addCollectionAdminSubstrate(adminSub.addressRaw).send(); - const adminEth = await helper.eth.createAccountWithBalance(donor); - await collectionEvm.methods.addCollectionAdmin(adminEth).send(); + const [admin1] = await helper.arrange.createAccounts([10n], donor); + const admin1Cross = helper.ethCrossAccount.fromKeyringPair(admin1); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + await collectionEvm.methods.addCollectionAdminCross(admin1Cross).send(); - await expect(collectionEvm.methods.removeCollectionAdminSubstrate(adminSub.addressRaw).call({from: adminEth})) + const [admin2] = await helper.arrange.createAccounts([10n], donor); + const admin2Cross = helper.ethCrossAccount.fromKeyringPair(admin2); + await collectionEvm.methods.addCollectionAdminCross(admin2Cross).send(); + + await expect(collectionEvm.methods.removeCollectionAdminCross(admin1Cross).call({from: admin2Cross.eth})) .to.be.rejectedWith('NoPermission'); const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]); expect(adminList.length).to.be.eq(2); expect(adminList.toString().toLocaleLowerCase()) - .to.be.deep.contains(adminSub.address.toLocaleLowerCase()) - .to.be.deep.contains(adminEth.toLocaleLowerCase()); + .to.be.deep.contains(admin1.address.toLocaleLowerCase()) + .to.be.deep.contains(admin2.address.toLocaleLowerCase()); }); - itEth.skip('(!negative tests!) Remove substrate admin by USER is not allowed', async ({helper}) => { + itEth('(!negative tests!) Remove [cross] admin by USER is not allowed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); const [adminSub] = await helper.arrange.createAccounts([10n], donor); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - await collectionEvm.methods.addCollectionAdminSubstrate(adminSub.addressRaw).send(); + const adminSubCross = helper.ethCrossAccount.fromKeyringPair(adminSub); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + await collectionEvm.methods.addCollectionAdminCross(adminSubCross).send(); const notAdminEth = await helper.eth.createAccountWithBalance(donor); - await expect(collectionEvm.methods.removeCollectionAdminSubstrate(adminSub.addressRaw).call({from: notAdminEth})) + await expect(collectionEvm.methods.removeCollectionAdminCross(adminSubCross).call({from: notAdminEth})) .to.be.rejectedWith('NoPermission'); const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]); @@ -267,6 +368,7 @@ describe('Remove collection admins', () => { }); }); +// Soft-deprecated describe('Change owner tests', () => { let donor: IKeyringPair; @@ -280,7 +382,7 @@ describe('Change owner tests', () => { const owner = await helper.eth.createAccountWithBalance(donor); const newOwner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true); await collectionEvm.methods.changeCollectionOwner(newOwner).send(); @@ -292,7 +394,7 @@ describe('Change owner tests', () => { const owner = await helper.eth.createAccountWithBalance(donor); const newOwner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true); const cost = await recordEthFee(helper, owner, () => collectionEvm.methods.changeCollectionOwner(newOwner).send()); expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))); expect(cost > 0); @@ -302,7 +404,7 @@ describe('Change owner tests', () => { const owner = await helper.eth.createAccountWithBalance(donor); const newOwner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true); await expect(collectionEvm.methods.changeCollectionOwner(newOwner).send({from: newOwner})).to.be.rejected; expect(await collectionEvm.methods.isOwnerOrAdmin(newOwner).call()).to.be.false; @@ -318,40 +420,51 @@ describe('Change substrate owner tests', () => { }); }); - itEth.skip('Change owner', async ({helper}) => { + itEth('Change owner [cross]', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const [newOwner] = await helper.arrange.createAccounts([10n], donor); - const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const ownerEth = await helper.eth.createAccountWithBalance(donor); + const ownerCrossEth = helper.ethCrossAccount.fromAddress(ownerEth); + const [ownerSub] = await helper.arrange.createAccounts([10n], donor); + const ownerCrossSub = helper.ethCrossAccount.fromKeyringPair(ownerSub); + + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.true; - expect(await collectionEvm.methods.isOwnerOrAdminSubstrate(newOwner.addressRaw).call()).to.be.false; + expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossSub).call()).to.be.false; - await collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send(); + // Can set ethereum owner: + await collectionEvm.methods.changeCollectionOwnerCross(ownerCrossEth).send({from: owner}); + expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossEth).call()).to.be.true; + expect(await helper.collection.getData(collectionId)) + .to.have.property('normalizedOwner').that.is.eq(helper.address.ethToSubstrate(ownerEth)); - expect(await collectionEvm.methods.isOwnerOrAdmin(owner).call()).to.be.false; - expect(await collectionEvm.methods.isOwnerOrAdminSubstrate(newOwner.addressRaw).call()).to.be.true; + // Can set Substrate owner: + await collectionEvm.methods.changeCollectionOwnerCross(ownerCrossSub).send({from: ownerEth}); + expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossSub).call()).to.be.true; + expect(await helper.collection.getData(collectionId)) + .to.have.property('normalizedOwner').that.is.eq(helper.address.normalizeSubstrate(ownerSub.address)); }); itEth.skip('change owner call fee', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const [newOwner] = await helper.arrange.createAccounts([10n], donor); const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); const cost = await recordEthFee(helper, owner, () => collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send()); expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))); expect(cost > 0); }); - itEth.skip('(!negative tests!) call setOwner by non owner', async ({helper}) => { + itEth('(!negative tests!) call setOwner by non owner [cross]', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const otherReceiver = await helper.eth.createAccountWithBalance(donor); const [newOwner] = await helper.arrange.createAccounts([10n], donor); + const newOwnerCross = helper.ethCrossAccount.fromKeyringPair(newOwner); const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - await expect(collectionEvm.methods.setOwnerSubstrate(newOwner.addressRaw).send({from: otherReceiver})).to.be.rejected; - expect(await collectionEvm.methods.isOwnerOrAdminSubstrate(newOwner.addressRaw).call()).to.be.false; + await expect(collectionEvm.methods.changeCollectionOwnerCross(newOwnerCross).send({from: otherReceiver})).to.be.rejected; + expect(await collectionEvm.methods.isOwnerOrAdminCross(newOwnerCross).call()).to.be.false; }); }); diff --git a/tests/src/eth/collectionHelperAddress.test.ts b/tests/src/eth/collectionHelperAddress.test.ts new file mode 100644 index 0000000000..de3de74362 --- /dev/null +++ b/tests/src/eth/collectionHelperAddress.test.ts @@ -0,0 +1,72 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {itEth, usingEthPlaygrounds, expect} from './util'; +import {IKeyringPair} from '@polkadot/types/types'; +import {Pallets} from '../util'; + +const EVM_COLLECTION_HELPERS_ADDRESS = '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f'; + +describe('[eth]CollectionHelperAddress test: ERC20/ERC721 ', () => { + let donor: IKeyringPair; + + before(async function() { + await usingEthPlaygrounds(async (helper, privateKey) => { + donor = await privateKey({filename: __filename}); + }); + }); + + itEth('NFT', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionAddress: nftCollectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC'); + const nftCollection = await helper.ethNativeContract.collection(nftCollectionAddress, 'nft', owner); + + expect((await nftCollection.methods.collectionHelperAddress().call()) + .toString().toLowerCase()).to.be.equal(EVM_COLLECTION_HELPERS_ADDRESS); + }); + + itEth.ifWithPallets('RFT ', [Pallets.ReFungible], async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionAddress: rftCollectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC'); + + const rftCollection = await helper.ethNativeContract.collection(rftCollectionAddress, 'rft', owner); + expect((await rftCollection.methods.collectionHelperAddress().call()) + .toString().toLowerCase()).to.be.equal(EVM_COLLECTION_HELPERS_ADDRESS); + }); + + itEth('FT', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', 18, 'absolutely anything', 'ROC'); + const collection = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner); + + expect((await collection.methods.collectionHelperAddress().call()) + .toString().toLowerCase()).to.be.equal(EVM_COLLECTION_HELPERS_ADDRESS); + }); + + itEth('[collectionHelpers] convert collectionId into address', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const collectionId = 7; + const collectionAddress = helper.ethAddress.fromCollectionId(collectionId); + const helperContract = await helper.ethNativeContract.collectionHelpers(owner); + + expect(await helperContract.methods.collectionAddress(collectionId).call()).to.be.equal(collectionAddress); + expect(parseInt(await helperContract.methods.collectionId(collectionAddress).call())).to.be.equal(collectionId); + }); + +}); diff --git a/tests/src/eth/collectionLimits.test.ts b/tests/src/eth/collectionLimits.test.ts new file mode 100644 index 0000000000..9bd542c71f --- /dev/null +++ b/tests/src/eth/collectionLimits.test.ts @@ -0,0 +1,145 @@ +import {IKeyringPair} from '@polkadot/types/types'; +import {Pallets} from '../util'; +import {expect, itEth, usingEthPlaygrounds} from './util'; +import {CollectionLimitField} from './util/playgrounds/types'; + + +describe('Can set collection limits', () => { + let donor: IKeyringPair; + + before(async () => { + await usingEthPlaygrounds(async (_helper, privateKey) => { + donor = await privateKey({filename: __filename}); + }); + }); + + [ + {case: 'nft' as const}, + {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + {case: 'ft' as const}, + ].map(testCase => + itEth.ifWithPallets(`for ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.case, owner, 'Limits', 'absolutely anything', 'FLO', 18); + const limits = { + accountTokenOwnershipLimit: 1000, + sponsoredDataSize: 1024, + sponsoredDataRateLimit: 30, + tokenLimit: 1000000, + sponsorTransferTimeout: 6, + sponsorApproveTimeout: 6, + ownerCanTransfer: 1, + ownerCanDestroy: 0, + transfersEnabled: 0, + }; + + const expectedLimits = { + accountTokenOwnershipLimit: 1000, + sponsoredDataSize: 1024, + sponsoredDataRateLimit: {blocks: 30}, + tokenLimit: 1000000, + sponsorTransferTimeout: 6, + sponsorApproveTimeout: 6, + ownerCanTransfer: true, + ownerCanDestroy: false, + transfersEnabled: false, + }; + + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.case, owner); + await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: limits.accountTokenOwnershipLimit}}).send(); + await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsoredDataSize, value: {status: true, value: limits.sponsoredDataSize}}).send(); + await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsoredDataRateLimit, value: {status: true, value: limits.sponsoredDataRateLimit}}).send(); + await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.TokenLimit, value: {status: true, value: limits.tokenLimit}}).send(); + await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsorTransferTimeout, value: {status: true, value: limits.sponsorTransferTimeout}}).send(); + await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.SponsorApproveTimeout, value: {status: true, value: limits.sponsorApproveTimeout}}).send(); + await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.OwnerCanTransfer, value: {status: true, value: limits.ownerCanTransfer}}).send(); + await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.OwnerCanDestroy, value: {status: true, value: limits.ownerCanDestroy}}).send(); + await collectionEvm.methods.setCollectionLimit({field: CollectionLimitField.TransferEnabled, value: {status: true, value: limits.transfersEnabled}}).send(); + + // Check limits from sub: + const data = (await helper.rft.getData(collectionId))!; + expect(data.raw.limits).to.deep.eq(expectedLimits); + expect(await helper.collection.getEffectiveLimits(collectionId)).to.deep.eq(expectedLimits); + // Check limits from eth: + const limitsEvm = await collectionEvm.methods.collectionLimits().call({from: owner}); + expect(limitsEvm).to.have.length(9); + expect(limitsEvm[0]).to.deep.eq([CollectionLimitField.AccountTokenOwnership.toString(), [true, limits.accountTokenOwnershipLimit.toString()]]); + expect(limitsEvm[1]).to.deep.eq([CollectionLimitField.SponsoredDataSize.toString(), [true, limits.sponsoredDataSize.toString()]]); + expect(limitsEvm[2]).to.deep.eq([CollectionLimitField.SponsoredDataRateLimit.toString(), [true, limits.sponsoredDataRateLimit.toString()]]); + expect(limitsEvm[3]).to.deep.eq([CollectionLimitField.TokenLimit.toString(), [true, limits.tokenLimit.toString()]]); + expect(limitsEvm[4]).to.deep.eq([CollectionLimitField.SponsorTransferTimeout.toString(), [true, limits.sponsorTransferTimeout.toString()]]); + expect(limitsEvm[5]).to.deep.eq([CollectionLimitField.SponsorApproveTimeout.toString(), [true, limits.sponsorApproveTimeout.toString()]]); + expect(limitsEvm[6]).to.deep.eq([CollectionLimitField.OwnerCanTransfer.toString(), [true, limits.ownerCanTransfer.toString()]]); + expect(limitsEvm[7]).to.deep.eq([CollectionLimitField.OwnerCanDestroy.toString(), [true, limits.ownerCanDestroy.toString()]]); + expect(limitsEvm[8]).to.deep.eq([CollectionLimitField.TransferEnabled.toString(), [true, limits.transfersEnabled.toString()]]); + })); +}); + +describe('Cannot set invalid collection limits', () => { + let donor: IKeyringPair; + + before(async () => { + await usingEthPlaygrounds(async (_helper, privateKey) => { + donor = await privateKey({filename: __filename}); + }); + }); + + [ + {case: 'nft' as const}, + {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + {case: 'ft' as const}, + ].map(testCase => + itEth.ifWithPallets(`for ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => { + const invalidLimits = { + accountTokenOwnershipLimit: BigInt(Number.MAX_SAFE_INTEGER), + transfersEnabled: 3, + }; + + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionAddress} = await helper.eth.createCollection(testCase.case, owner, 'Limits', 'absolutely anything', 'ISNI', 18); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.case, owner); + + // Cannot set non-existing limit + await expect(collectionEvm.methods + .setCollectionLimit({field: 9, value: {status: true, value: 1}}) + .call()).to.be.rejectedWith('Returned error: VM Exception while processing transaction: revert Value not convertible into enum "CollectionLimitField"'); + + // Cannot disable limits + await expect(collectionEvm.methods + .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: false, value: 200}}) + .call()).to.be.rejectedWith('user can\'t disable limits'); + + await expect(collectionEvm.methods + .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: invalidLimits.accountTokenOwnershipLimit}}) + .call()).to.be.rejectedWith(`can't convert value to u32 "${invalidLimits.accountTokenOwnershipLimit}"`); + + await expect(collectionEvm.methods + .setCollectionLimit({field: CollectionLimitField.TransferEnabled, value: {status: true, value: 3}}) + .call()).to.be.rejectedWith(`can't convert value to boolean "${invalidLimits.transfersEnabled}"`); + + expect(() => collectionEvm.methods + .setCollectionLimit({field: CollectionLimitField.SponsoredDataSize, value: {status: true, value: -1}}).send()).to.throw('value out-of-bounds'); + })); + + [ + {case: 'nft' as const, requiredPallets: []}, + {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + {case: 'ft' as const, requiredPallets: []}, + ].map(testCase => + itEth.ifWithPallets(`Non-owner and non-admin cannot set collection limits for ${testCase.case}`, testCase.requiredPallets || [], async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const nonOwner = await helper.eth.createAccountWithBalance(donor); + const {collectionAddress} = await helper.eth.createCollection(testCase.case, owner, 'Limits', 'absolutely anything', 'FLO', 18); + + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, testCase.case, owner); + await expect(collectionEvm.methods + .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}) + .call({from: nonOwner})) + .to.be.rejectedWith('NoPermission'); + + await expect(collectionEvm.methods + .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}) + .send({from: nonOwner})) + .to.be.rejected; + })); +}); diff --git a/tests/src/eth/collectionProperties.test.ts b/tests/src/eth/collectionProperties.test.ts index 6829627da2..d9aa14470b 100644 --- a/tests/src/eth/collectionProperties.test.ts +++ b/tests/src/eth/collectionProperties.test.ts @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util'; +import {itEth, usingEthPlaygrounds, expect} from './util'; import {Pallets} from '../util'; import {IProperty, ITokenPropertyPermission} from '../util/playgrounds/types'; import {IKeyringPair} from '@polkadot/types/types'; @@ -26,47 +26,108 @@ describe('EVM collection properties', () => { before(async function() { await usingEthPlaygrounds(async (_helper, privateKey) => { donor = await privateKey({filename: __filename}); - [alice] = await _helper.arrange.createAccounts([10n], donor); + [alice] = await _helper.arrange.createAccounts([50n], donor); }); }); - itEth('Can be set', async({helper}) => { - const caller = await helper.eth.createAccountWithBalance(donor); - const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties: []}); - await collection.addAdmin(alice, {Ethereum: caller}); + // Soft-deprecated: setCollectionProperty + [ + {method: 'setCollectionProperties', mode: 'nft' as const, methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]}, + {method: 'setCollectionProperties', mode: 'rft' as const, methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]}, + {method: 'setCollectionProperties', mode: 'ft' as const, methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}]}, + {method: 'setCollectionProperty', mode: 'nft' as const, methodParams: ['testKey', Buffer.from('testValue')], expectedProps: [{key: 'testKey', value: 'testValue'}]}, + ].map(testCase => + itEth.ifWithPallets(`Collection properties can be set: ${testCase.method}() for ${testCase.mode}`, testCase.mode === 'rft' ? [Pallets.ReFungible] : [], async({helper}) => { + const caller = await helper.eth.createAccountWithBalance(donor); + const collection = await helper[testCase.mode].mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties: []}); + await collection.addAdmin(alice, {Ethereum: caller}); - const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'nft', caller); + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(address, 'nft', caller, testCase.method === 'setCollectionProperty'); - await contract.methods.setCollectionProperty('testKey', Buffer.from('testValue')).send({from: caller}); + // collectionProperties returns an empty array if no properties: + expect(await collectionEvm.methods.collectionProperties([]).call()).to.be.like([]); + expect(await collectionEvm.methods.collectionProperties(['NonExistingKey']).call()).to.be.like([]); - const raw = (await collection.getData())?.raw; + await collectionEvm.methods[testCase.method](...testCase.methodParams).send({from: caller}); - expect(raw.properties[0].value).to.equal('testValue'); - }); + const raw = (await collection.getData())?.raw; + expect(raw.properties).to.deep.equal(testCase.expectedProps); - itEth('Can be deleted', async({helper}) => { - const caller = await helper.eth.createAccountWithBalance(donor); - const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties: [{key: 'testKey', value: 'testValue'}]}); + // collectionProperties returns properties: + expect(await collectionEvm.methods.collectionProperties([]).call()).to.be.like(testCase.expectedProps.map(prop => helper.ethProperty.property(prop.key, prop.value))); + })); + itEth('Cannot set invalid properties', async({helper}) => { + const caller = await helper.eth.createAccountWithBalance(donor); + const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties: []}); await collection.addAdmin(alice, {Ethereum: caller}); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'nft', caller); - - await contract.methods.deleteCollectionProperty('testKey').send({from: caller}); + const contract = await helper.ethNativeContract.collection(address, 'nft', caller); + await expect(contract.methods.setCollectionProperties([{key: '', value: Buffer.from('val1')}]).send({from: caller})).to.be.rejected; + await expect(contract.methods.setCollectionProperties([{key: 'déjà vu', value: Buffer.from('hmm...')}]).send({from: caller})).to.be.rejected; + await expect(contract.methods.setCollectionProperties([{key: 'a'.repeat(257), value: Buffer.from('val3')}]).send({from: caller})).to.be.rejected; + // TODO add more expects const raw = (await collection.getData())?.raw; - - expect(raw.properties.length).to.equal(0); + expect(raw.properties).to.deep.equal([]); }); + + // Soft-deprecated: deleteCollectionProperty + [ + {method: 'deleteCollectionProperties', mode: 'nft' as const, methodParams: [['testKey1', 'testKey2']], expectedProps: [{key: 'testKey3', value: 'testValue3'}]}, + {method: 'deleteCollectionProperties', mode: 'rft' as const, methodParams: [['testKey1', 'testKey2']], expectedProps: [{key: 'testKey3', value: 'testValue3'}]}, + {method: 'deleteCollectionProperties', mode: 'ft' as const, methodParams: [['testKey1', 'testKey2']], expectedProps: [{key: 'testKey3', value: 'testValue3'}]}, + {method: 'deleteCollectionProperty', mode: 'nft' as const, methodParams: ['testKey1'], expectedProps: [{key: 'testKey2', value: 'testValue2'}, {key: 'testKey3', value: 'testValue3'}]}, + ].map(testCase => + itEth.ifWithPallets(`Collection properties can be deleted: ${testCase.method}() for ${testCase.mode}`, testCase.mode === 'rft' ? [Pallets.ReFungible] : [], async({helper}) => { + const properties = [ + {key: 'testKey1', value: 'testValue1'}, + {key: 'testKey2', value: 'testValue2'}, + {key: 'testKey3', value: 'testValue3'}]; + const caller = await helper.eth.createAccountWithBalance(donor); + const collection = await helper[testCase.mode].mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties}); + + await collection.addAdmin(alice, {Ethereum: caller}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'nft', caller, testCase.method === 'deleteCollectionProperty'); + + await contract.methods[testCase.method](...testCase.methodParams).send({from: caller}); + + const raw = (await collection.getData())?.raw; + + expect(raw.properties.length).to.equal(testCase.expectedProps.length); + expect(raw.properties).to.deep.equal(testCase.expectedProps); + })); + + [ + {method: 'deleteCollectionProperties', methodParams: [['testKey2']]}, + {method: 'deleteCollectionProperty', methodParams: ['testKey2']}, + ].map(testCase => + itEth(`cannot ${testCase.method}() of non-owned collections`, async ({helper}) => { + const properties = [ + {key: 'testKey1', value: 'testValue1'}, + {key: 'testKey2', value: 'testValue2'}, + ]; + const caller = await helper.eth.createAccountWithBalance(donor); + const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(address, 'nft', caller, testCase.method === 'deleteCollectionProperty'); + + await expect(collectionEvm.methods[testCase.method](...testCase.methodParams).send({from: caller})).to.be.rejected; + expect(await collection.getProperties()).to.deep.eq(properties); + })); + itEth('Can be read', async({helper}) => { const caller = helper.eth.createAccount(); const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'test', tokenPrefix: 'test', properties: [{key: 'testKey', value: 'testValue'}]}); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'nft', caller); + const contract = await helper.ethNativeContract.collection(address, 'nft', caller); const value = await contract.methods.collectionProperty('testKey').call(); expect(value).to.equal(helper.getWeb3().utils.toHex('testValue')); @@ -82,82 +143,79 @@ describe('Supports ERC721Metadata', () => { }); }); - const checkERC721Metadata = async (helper: EthUniqueHelper, mode: 'nft' | 'rft') => { - const caller = await helper.eth.createAccountWithBalance(donor); - const bruh = await helper.eth.createAccountWithBalance(donor); + [ + {case: 'nft' as const}, + {case: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`ERC721Metadata property can be set for ${testCase.case} collection`, testCase.requiredPallets || [], async ({helper}) => { + const caller = await helper.eth.createAccountWithBalance(donor); + const bruh = await helper.eth.createAccountWithBalance(donor); - const BASE_URI = 'base/'; - const SUFFIX = 'suffix1'; - const URI = 'uri1'; + const BASE_URI = 'base/'; + const SUFFIX = 'suffix1'; + const URI = 'uri1'; - const collectionHelpers = helper.ethNativeContract.collectionHelpers(caller); - const creatorMethod = mode === 'rft' ? 'createRFTCollection' : 'createNFTCollection'; + const collectionHelpers = await helper.ethNativeContract.collectionHelpers(caller); + const creatorMethod = testCase.case === 'rft' ? 'createRFTCollection' : 'createNFTCollection'; - const {collectionId, collectionAddress} = await helper.eth[creatorMethod](caller, 'n', 'd', 'p'); + const {collectionId, collectionAddress} = await helper.eth[creatorMethod](caller, 'n', 'd', 'p'); + const bruhCross = helper.ethCrossAccount.fromAddress(bruh); - const contract = helper.ethNativeContract.collectionById(collectionId, mode, caller); - await contract.methods.addCollectionAdmin(bruh).send(); // to check that admin will work too + const contract = await helper.ethNativeContract.collectionById(collectionId, testCase.case, caller); + await contract.methods.addCollectionAdminCross(bruhCross).send(); // to check that admin will work too - const collection1 = helper.nft.getCollectionObject(collectionId); - const data1 = await collection1.getData(); - expect(data1?.raw.flags.erc721metadata).to.be.false; - expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.false; + const collection1 = helper.nft.getCollectionObject(collectionId); + const data1 = await collection1.getData(); + expect(data1?.raw.flags.erc721metadata).to.be.false; + expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.false; - await collectionHelpers.methods.makeCollectionERC721MetadataCompatible(collectionAddress, BASE_URI) - .send({from: bruh}); + await collectionHelpers.methods.makeCollectionERC721MetadataCompatible(collectionAddress, BASE_URI) + .send({from: bruh}); - expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.true; + expect(await contract.methods.supportsInterface('0x5b5e139f').call()).to.be.true; - const collection2 = helper.nft.getCollectionObject(collectionId); - const data2 = await collection2.getData(); - expect(data2?.raw.flags.erc721metadata).to.be.true; + const collection2 = helper.nft.getCollectionObject(collectionId); + const data2 = await collection2.getData(); + expect(data2?.raw.flags.erc721metadata).to.be.true; - const propertyPermissions = data2?.raw.tokenPropertyPermissions; - expect(propertyPermissions?.length).to.equal(2); + const propertyPermissions = data2?.raw.tokenPropertyPermissions; + expect(propertyPermissions?.length).to.equal(2); - expect(propertyPermissions.find((tpp: ITokenPropertyPermission) => { - return tpp.key === 'URI' && tpp.permission.mutable && tpp.permission.collectionAdmin && !tpp.permission.tokenOwner; - })).to.be.not.null; + expect(propertyPermissions.find((tpp: ITokenPropertyPermission) => { + return tpp.key === 'URI' && tpp.permission.mutable && tpp.permission.collectionAdmin && !tpp.permission.tokenOwner; + })).to.be.not.null; - expect(propertyPermissions.find((tpp: ITokenPropertyPermission) => { - return tpp.key === 'URISuffix' && tpp.permission.mutable && tpp.permission.collectionAdmin && !tpp.permission.tokenOwner; - })).to.be.not.null; + expect(propertyPermissions.find((tpp: ITokenPropertyPermission) => { + return tpp.key === 'URISuffix' && tpp.permission.mutable && tpp.permission.collectionAdmin && !tpp.permission.tokenOwner; + })).to.be.not.null; - expect(data2?.raw.properties?.find((property: IProperty) => { - return property.key === 'baseURI' && property.value === BASE_URI; - })).to.be.not.null; + expect(data2?.raw.properties?.find((property: IProperty) => { + return property.key === 'baseURI' && property.value === BASE_URI; + })).to.be.not.null; - const token1Result = await contract.methods.mint(bruh).send(); - const tokenId1 = token1Result.events.Transfer.returnValues.tokenId; + const token1Result = await contract.methods.mint(bruh).send(); + const tokenId1 = token1Result.events.Transfer.returnValues.tokenId; - expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI); + expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI); - await contract.methods.setProperty(tokenId1, 'URISuffix', Buffer.from(SUFFIX)).send(); - expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI + SUFFIX); + await contract.methods.setProperties(tokenId1, [{key: 'URISuffix', value: Buffer.from(SUFFIX)}]).send(); + expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI + SUFFIX); - await contract.methods.setProperty(tokenId1, 'URI', Buffer.from(URI)).send(); - expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(URI); + await contract.methods.setProperties(tokenId1, [{key: 'URI', value: Buffer.from(URI)}]).send(); + expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(URI); - await contract.methods.deleteProperty(tokenId1, 'URI').send(); - expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI + SUFFIX); + await contract.methods.deleteProperties(tokenId1, ['URI']).send(); + expect(await contract.methods.tokenURI(tokenId1).call()).to.equal(BASE_URI + SUFFIX); - const token2Result = await contract.methods.mintWithTokenURI(bruh, URI).send(); - const tokenId2 = token2Result.events.Transfer.returnValues.tokenId; + const token2Result = await contract.methods.mintWithTokenURI(bruh, URI).send(); + const tokenId2 = token2Result.events.Transfer.returnValues.tokenId; - expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(URI); + expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(URI); - await contract.methods.deleteProperty(tokenId2, 'URI').send(); - expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(BASE_URI); + await contract.methods.deleteProperties(tokenId2, ['URI']).send(); + expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(BASE_URI); - await contract.methods.setProperty(tokenId2, 'URISuffix', Buffer.from(SUFFIX)).send(); - expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(BASE_URI + SUFFIX); - }; - - itEth('ERC721Metadata property can be set for NFT collection', async({helper}) => { - await checkERC721Metadata(helper, 'nft'); - }); - - itEth.ifWithPallets('ERC721Metadata property can be set for RFT collection', [Pallets.ReFungible], async({helper}) => { - await checkERC721Metadata(helper, 'rft'); - }); + await contract.methods.setProperties(tokenId2, [{key: 'URISuffix', value: Buffer.from(SUFFIX)}]).send(); + expect(await contract.methods.tokenURI(tokenId2).call()).to.equal(BASE_URI + SUFFIX); + })); }); diff --git a/tests/src/eth/collectionSponsoring.test.ts b/tests/src/eth/collectionSponsoring.test.ts index df04d80d8d..80d77eb533 100644 --- a/tests/src/eth/collectionSponsoring.test.ts +++ b/tests/src/eth/collectionSponsoring.test.ts @@ -15,10 +15,10 @@ // along with Unique Network. If not, see . import {IKeyringPair} from '@polkadot/types/types'; -import {usingPlaygrounds} from '../util/index'; +import {Pallets, requirePalletsOrSkip, usingPlaygrounds} from '../util/index'; import {itEth, expect} from './util'; -describe('evm collection sponsoring', () => { +describe('evm nft collection sponsoring', () => { let donor: IKeyringPair; let alice: IKeyringPair; let nominal: bigint; @@ -30,7 +30,8 @@ describe('evm collection sponsoring', () => { nominal = helper.balance.getOneTokenNominal(); }); }); - + + // TODO: move to substrate tests itEth('sponsors mint transactions', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}}); await collection.setSponsor(alice, alice.address); @@ -40,7 +41,7 @@ describe('evm collection sponsoring', () => { expect(await helper.balance.getEthereum(minter)).to.equal(0n); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', minter); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', minter); await collection.addToAllowList(alice, {Ethereum: minter}); @@ -81,71 +82,91 @@ describe('evm collection sponsoring', () => { // expect(bigIntToSub(api, BigInt(sponsorTuple[1]))).to.be.eq(sponsor.address); // }); - itEth('Remove sponsor', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner); - - let result = await collectionHelpers.methods.createNFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)}); - const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); - const sponsor = await helper.eth.createAccountWithBalance(donor); - const collectionEvm = helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner); - - expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false; - result = await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner}); - expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true; - - await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor}); - expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false; - - await collectionEvm.methods.removeCollectionSponsor().send({from: owner}); - - const sponsorTuple = await collectionEvm.methods.collectionSponsor().call({from: owner}); - expect(sponsorTuple.field_0).to.be.eq('0x0000000000000000000000000000000000000000'); - }); - - itEth('Sponsoring collection from evm address via access list', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - - const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Sponsor collection', '1', '1', ''); - - const collection = helper.nft.getCollectionObject(collectionId); - const sponsor = await helper.eth.createAccountWithBalance(donor); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - - await collectionEvm.methods.setCollectionSponsor(sponsor).send({from: owner}); - let collectionData = (await collection.getData())!; - expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); - await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor'); - - await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor}); - collectionData = (await collection.getData())!; - expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); - - const user = helper.eth.createAccount(); - const nextTokenId = await collectionEvm.methods.nextTokenId().call(); - expect(nextTokenId).to.be.equal('1'); - - const oldPermissions = (await collection.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman(); - expect(oldPermissions.mintMode).to.be.false; - expect(oldPermissions.access).to.be.equal('Normal'); - - await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner}); - await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner}); - await collectionEvm.methods.setCollectionMintMode(true).send({from: owner}); - - const newPermissions = (await collection.getData())!.raw.permissions; // (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman(); - expect(newPermissions.mintMode).to.be.true; - expect(newPermissions.access).to.be.equal('AllowList'); - - const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); - const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); - - { - const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user}); - const events = helper.eth.normalizeEvents(result.events); + [ + 'setCollectionSponsorCross', + 'setCollectionSponsor', // Soft-deprecated + ].map(testCase => + itEth(`[${testCase}] can remove collection sponsor`, async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner); + + let result = await collectionHelpers.methods.createNFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)}); + const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); + const collectionEvm = await helper.ethNativeContract.collection(collectionIdAddress, 'nft', owner, testCase === 'setCollectionSponsor'); + + expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false; + result = await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send({from: owner}); + expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true; + + await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor}); + let sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner}); + expect(helper.address.restoreCrossAccountFromBigInt(BigInt(sponsorStruct.sub))).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); + expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false; + + await collectionEvm.methods.removeCollectionSponsor().send({from: owner}); + + sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner}); + expect(sponsorStruct.eth).to.be.eq('0x0000000000000000000000000000000000000000'); + })); + + [ + 'setCollectionSponsorCross', + 'setCollectionSponsor', // Soft-deprecated + ].map(testCase => + itEth(`[${testCase}] Can sponsor from evm address via access list`, async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsorEth = await helper.eth.createAccountWithBalance(donor); + const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth); + + const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Sponsor collection', '1', '1', ''); + + const collectionSub = helper.nft.getCollectionObject(collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, testCase === 'setCollectionSponsor'); + + // Set collection sponsor: + await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsorEth : sponsorCrossEth).send({from: owner}); + let sponsorship = (await collectionSub.getData())!.raw.sponsorship; + expect(sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true)); + // Account cannot confirm sponsorship if it is not set as a sponsor + await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail'); + + // Sponsor can confirm sponsorship: + await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth}); + sponsorship = (await collectionSub.getData())!.raw.sponsorship; + expect(sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true)); + + // Create user with no balance: + const user = helper.eth.createAccount(); + const userCross = helper.ethCrossAccount.fromAddress(user); + const nextTokenId = await collectionEvm.methods.nextTokenId().call(); + expect(nextTokenId).to.be.equal('1'); + + // Set collection permissions: + const oldPermissions = (await collectionSub.getData())!.raw.permissions; + expect(oldPermissions.mintMode).to.be.false; + expect(oldPermissions.access).to.be.equal('Normal'); + + await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner}); + await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner}); + await collectionEvm.methods.setCollectionMintMode(true).send({from: owner}); + + const newPermissions = (await collectionSub.getData())!.raw.permissions; + expect(newPermissions.mintMode).to.be.true; + expect(newPermissions.access).to.be.equal('AllowList'); + + const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth)); + const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user)); + + // User can mint token without balance: + { + const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user}); + const event = helper.eth.normalizeEvents(result.events) + .find(event => event.event === 'Transfer'); - expect(events).to.be.deep.equal([ - { + expect(event).to.be.deep.equal({ address: collectionAddress, event: 'Transfer', args: { @@ -153,17 +174,18 @@ describe('evm collection sponsoring', () => { to: user, tokenId: '1', }, - }, - ]); + }); - const ownerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(owner)); - const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); + const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth)); + const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user)); - expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); - expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter); - expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true; - } - }); + expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); + expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter); + expect(userBalanceAfter).to.be.eq(userBalanceBefore); + expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true; + } + })); // TODO: Temprorary off. Need refactor // itWeb3('Sponsoring collection from substrate address via access list', async ({api, web3, privateKeyWrapper}) => { @@ -221,40 +243,294 @@ describe('evm collection sponsoring', () => { // } // }); - itEth('Check that transaction via EVM spend money from sponsor address', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); + [ + 'setCollectionSponsorCross', + 'setCollectionSponsor', // Soft-deprecated + ].map(testCase => + itEth(`[${testCase}] Check that transaction via EVM spend money from sponsor address`, async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); - const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner,'Sponsor collection', '1', '1', ''); - const collection = helper.nft.getCollectionObject(collectionId); - const sponsor = await helper.eth.createAccountWithBalance(donor); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner,'Sponsor collection', '1', '1', ''); - await collectionEvm.methods.setCollectionSponsor(sponsor).send(); - let collectionData = (await collection.getData())!; - expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); - await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor'); + const collectionSub = helper.nft.getCollectionObject(collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, testCase === 'setCollectionSponsor'); + // Set collection sponsor: + await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send(); + let collectionData = (await collectionSub.getData())!; + expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); + await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail'); - const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor); - await sponsorCollection.methods.confirmCollectionSponsorship().send(); - collectionData = (await collection.getData())!; - expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); + await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor}); + collectionData = (await collectionSub.getData())!; + expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); - const user = helper.eth.createAccount(); - await collectionEvm.methods.addCollectionAdmin(user).send(); + const user = helper.eth.createAccount(); + const userCross = helper.ethCrossAccount.fromAddress(user); + await collectionEvm.methods.addCollectionAdminCross(userCross).send(); - const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); - const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); - const userCollectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', user); + const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user}); + const tokenId = mintingResult.events.Transfer.returnValues.tokenId; - const result = await userCollectionEvm.methods.mintWithTokenURI(user, 'Test URI').send(); - const tokenId = result.events.Transfer.returnValues.tokenId; + const event = helper.eth.normalizeEvents(mintingResult.events) + .find(event => event.event === 'Transfer'); + const address = helper.ethAddress.fromCollectionId(collectionId); - const events = helper.eth.normalizeEvents(result.events); - const address = helper.ethAddress.fromCollectionId(collectionId); + expect(event).to.be.deep.equal({ + address, + event: 'Transfer', + args: { + from: '0x0000000000000000000000000000000000000000', + to: user, + tokenId: '1', + }, + }); + expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI'); - expect(events).to.be.deep.equal([ + const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore); + const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; + })); + + itEth('Can reassign collection sponsor', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsorEth = await helper.eth.createAccountWithBalance(donor); + const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth); + const [sponsorSub] = await helper.arrange.createAccounts([100n], donor); + const sponsorCrossSub = helper.ethCrossAccount.fromKeyringPair(sponsorSub); + + const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner,'Sponsor collection', '1', '1', ''); + const collectionSub = helper.nft.getCollectionObject(collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + + // Set and confirm sponsor: + await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossEth).send({from: owner}); + await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth}); + + // Can reassign sponsor: + await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossSub).send({from: owner}); + const collectionSponsor = (await collectionSub.getData())?.raw.sponsorship; + expect(collectionSponsor).to.deep.eq({Unconfirmed: sponsorSub.address}); + }); +}); + +describe('evm RFT collection sponsoring', () => { + let donor: IKeyringPair; + let alice: IKeyringPair; + let nominal: bigint; + + before(async function() { + await usingPlaygrounds(async (helper, privateKey) => { + requirePalletsOrSkip(this, helper, [Pallets.ReFungible]); + donor = await privateKey({filename: __filename}); + [alice] = await helper.arrange.createAccounts([100n], donor); + nominal = helper.balance.getOneTokenNominal(); + }); + }); + + [ + 'mintCross', + 'mintWithTokenURI', + ].map(testCase => + itEth(`[${testCase}] sponsors mint transactions`, async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'spnr', permissions: {mintMode: true}, tokenPropertyPermissions: [ + {key: 'URI', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}, + ]}); + + const owner = await helper.eth.createAccountWithBalance(donor); + await collection.setSponsor(alice, alice.address); + await collection.confirmSponsorship(alice); + + const minter = helper.eth.createAccount(); + const minterCross = helper.ethCrossAccount.fromAddress(minter); + expect(await helper.balance.getEthereum(minter)).to.equal(0n); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', minter, true); + + await collection.addToAllowList(alice, {Ethereum: minter}); + await collection.addAdmin(alice, {Ethereum: owner}); + const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner); + await collectionHelpers.methods.makeCollectionERC721MetadataCompatible(collectionAddress, 'base/') + .send(); + + let mintingResult; + let tokenId; + switch (testCase) { + case 'mintCross': + mintingResult = await contract.methods.mintCross(minterCross, []).send(); + break; + case 'mintWithTokenURI': + mintingResult = await contract.methods.mintWithTokenURI(minter, 'Test URI').send(); + tokenId = mintingResult.events.Transfer.returnValues.tokenId; + expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); + break; + } + + const events = helper.eth.normalizeEvents(mintingResult.events); + expect(events).to.deep.include({ + address: collectionAddress, + event: 'Transfer', + args: { + from: '0x0000000000000000000000000000000000000000', + to: minter, + tokenId: '1', + }, + }); + })); + + [ + 'setCollectionSponsorCross', + 'setCollectionSponsor', // Soft-deprecated + ].map(testCase => + itEth(`[${testCase}] can remove collection sponsor`, async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner); + + let result = await collectionHelpers.methods.createRFTCollection('Sponsor collection', '1', '1').send({value: Number(2n * nominal)}); + const collectionIdAddress = helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); + const collectionEvm = await helper.ethNativeContract.collection(collectionIdAddress, 'rft', owner, testCase === 'setCollectionSponsor'); + + expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false; + result = await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send({from: owner}); + expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.true; + + await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor}); + expect(await collectionEvm.methods.hasCollectionPendingSponsor().call({from: owner})).to.be.false; + + await collectionEvm.methods.removeCollectionSponsor().send({from: owner}); + + const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner}); + expect(sponsorStruct.eth).to.be.eq('0x0000000000000000000000000000000000000000'); + })); + + [ + 'setCollectionSponsorCross', + 'setCollectionSponsor', // Soft-deprecated + ].map(testCase => + itEth(`[${testCase}] Can sponsor from evm address via access list`, async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsorEth = await helper.eth.createAccountWithBalance(donor); + const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth); + + const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Sponsor collection', '1', '1', ''); + + const collectionSub = helper.rft.getCollectionObject(collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, testCase === 'setCollectionSponsor'); + + // Set collection sponsor: + await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsorEth : sponsorCrossEth).send({from: owner}); + let sponsorship = (await collectionSub.getData())!.raw.sponsorship; + expect(sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true)); + // Account cannot confirm sponsorship if it is not set as a sponsor + await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail'); + + // Sponsor can confirm sponsorship: + await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth}); + sponsorship = (await collectionSub.getData())!.raw.sponsorship; + expect(sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true)); + + // Create user with no balance: + const user = helper.eth.createAccount(); + const userCross = helper.ethCrossAccount.fromAddress(user); + const nextTokenId = await collectionEvm.methods.nextTokenId().call(); + expect(nextTokenId).to.be.equal('1'); + + // Set collection permissions: + const oldPermissions = (await collectionSub.getData())!.raw.permissions; + expect(oldPermissions.mintMode).to.be.false; + expect(oldPermissions.access).to.be.equal('Normal'); + + await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner}); + await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner}); + await collectionEvm.methods.setCollectionMintMode(true).send({from: owner}); + + const newPermissions = (await collectionSub.getData())!.raw.permissions; + expect(newPermissions.mintMode).to.be.true; + expect(newPermissions.access).to.be.equal('AllowList'); + + const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth)); + const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user)); + + // User can mint token without balance: { + const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user}); + const events = helper.eth.normalizeEvents(result.events); + + expect(events).to.deep.include({ + address: collectionAddress, + event: 'Transfer', + args: { + from: '0x0000000000000000000000000000000000000000', + to: user, + tokenId: '1', + }, + }); + + const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsorEth)); + const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user)); + + expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); + expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter); + expect(userBalanceAfter).to.be.eq(userBalanceBefore); + expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true; + } + })); + + [ + 'setCollectionSponsorCross', + 'setCollectionSponsor', // Soft-deprecated + ].map(testCase => + itEth(`[${testCase}] Check that collection admin EVM transaction spend money from sponsor eth address`, async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); + + const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', ''); + + const collectionSub = helper.rft.getCollectionObject(collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, testCase === 'setCollectionSponsor'); + // Set collection sponsor: + expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false; + await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send(); + expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true; + let collectionData = (await collectionSub.getData())!; + expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); + await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail'); + expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true; + + await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor}); + collectionData = (await collectionSub.getData())!; + expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true)); + expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false; + const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner}); + const sponsorSubAddress = helper.address.normalizeSubstrateToChainFormat(helper.address.ethToSubstrate(sponsor)); + const actualSubAddress = helper.address.normalizeSubstrateToChainFormat(helper.address.restoreCrossAccountFromBigInt(BigInt(sponsorStruct.sub))); + expect(actualSubAddress).to.be.equal(sponsorSubAddress); + + const user = helper.eth.createAccount(); + const userCross = helper.ethCrossAccount.fromAddress(user); + await collectionEvm.methods.addCollectionAdminCross(userCross).send(); + + const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + + const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user}); + const tokenId = mintingResult.events.Transfer.returnValues.tokenId; + + const events = helper.eth.normalizeEvents(mintingResult.events); + const address = helper.ethAddress.fromCollectionId(collectionId); + + expect(events).to.deep.include({ address, event: 'Transfer', args: { @@ -262,13 +538,311 @@ describe('evm collection sponsoring', () => { to: user, tokenId: '1', }, + }); + expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI'); + + const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore); + const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; + })); + + itEth('Check that collection admin EVM transaction spend money from sponsor sub address', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = alice; + const sponsorCross = helper.ethCrossAccount.fromKeyringPair(sponsor); + + const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', ''); + + const collectionSub = helper.rft.getCollectionObject(collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false); + // Set collection sponsor: + expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false; + await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send(); + expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.true; + let collectionData = (await collectionSub.getData())!; + expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(sponsor.address); + await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail'); + + await collectionSub.confirmSponsorship(sponsor); + collectionData = (await collectionSub.getData())!; + expect(collectionData.raw.sponsorship.Confirmed).to.be.eq(sponsor.address); + expect(await collectionEvm.methods.hasCollectionPendingSponsor().call()).to.be.false; + const sponsorStruct = await collectionEvm.methods.collectionSponsor().call({from: owner}); + expect(BigInt(sponsorStruct.sub)).to.be.equal(BigInt('0x' + Buffer.from(sponsor.addressRaw).toString('hex'))); + + const user = helper.eth.createAccount(); + const userCross = helper.ethCrossAccount.fromAddress(user); + await collectionEvm.methods.addCollectionAdminCross(userCross).send(); + + const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceBefore = await helper.balance.getSubstrate(sponsor.address); + + const mintingResult = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user}); + const tokenId = mintingResult.events.Transfer.returnValues.tokenId; + + const events = helper.eth.normalizeEvents(mintingResult.events); + + expect(events).to.deep.include({ + address: collectionAddress, + event: 'Transfer', + args: { + from: '0x0000000000000000000000000000000000000000', + to: user, + tokenId: '1', }, - ]); - expect(await userCollectionEvm.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); + }); + expect(await collectionEvm.methods.tokenURI(tokenId).call({from: user})).to.be.equal('Test URI'); const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore); - const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + const sponsorBalanceAfter = await helper.balance.getSubstrate(sponsor.address); expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; }); + + itEth('Sponsoring collection from substrate address via access list', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const user = helper.eth.createAccount(); + const userCross = helper.ethCrossAccount.fromAddress(user); + const sponsor = alice; + const sponsorCross = helper.ethCrossAccount.fromKeyringPair(sponsor); + + const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', ''); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, false); + + await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send({from: owner}); + + const collectionSub = helper.rft.getCollectionObject(collectionId); + await collectionSub.confirmSponsorship(sponsor); + + const nextTokenId = await collectionEvm.methods.nextTokenId().call(); + expect(nextTokenId).to.be.equal('1'); + + await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner}); + + await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner}); + await collectionEvm.methods.setCollectionMintMode(true).send({from: owner}); + + const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceBefore = await helper.balance.getSubstrate(sponsor.address); + const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user)); + + { + const nextTokenId = await collectionEvm.methods.nextTokenId().call(); + expect(nextTokenId).to.be.equal('1'); + const mintingResult = await collectionEvm.methods.mintWithTokenURI( + user, + 'Test URI', + ).send({from: user}); + + const events = helper.eth.normalizeEvents(mintingResult.events); + + + expect(events).to.deep.include({ + address: collectionAddress, + event: 'Transfer', + args: { + from: '0x0000000000000000000000000000000000000000', + to: user, + tokenId: nextTokenId, + }, + }); + + const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceAfter = await helper.balance.getSubstrate(sponsor.address); + const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user)); + + expect(await collectionEvm.methods.tokenURI(nextTokenId).call()).to.be.equal('Test URI'); + expect(ownerBalanceBefore).to.be.eq(ownerBalanceAfter); + expect(userBalanceAfter).to.be.eq(userBalanceBefore); + expect(sponsorBalanceBefore > sponsorBalanceAfter).to.be.true; + } + }); + + itEth('Can reassign collection sponsor', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsorEth = await helper.eth.createAccountWithBalance(donor); + const sponsorCrossEth = helper.ethCrossAccount.fromAddress(sponsorEth); + const [sponsorSub] = await helper.arrange.createAccounts([100n], donor); + const sponsorCrossSub = helper.ethCrossAccount.fromKeyringPair(sponsorSub); + + const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', ''); + const collectionSub = helper.rft.getCollectionObject(collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner); + + // Set and confirm sponsor: + await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossEth).send({from: owner}); + await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth}); + + // Can reassign sponsor: + await collectionEvm.methods.setCollectionSponsorCross(sponsorCrossSub).send({from: owner}); + const collectionSponsor = (await collectionSub.getData())?.raw.sponsorship; + expect(collectionSponsor).to.deep.eq({Unconfirmed: sponsorSub.address}); + }); + + [ + 'transfer', + 'transferCross', + 'transferFrom', + 'transferFromCross', + ].map(testCase => + itEth(`[${testCase}] Check that transfer via EVM spend money from sponsor address`, async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', ''); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); + const receiver = await helper.eth.createAccountWithBalance(donor); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner); + + await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send(); + await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor}); + + const user = await helper.eth.createAccountWithBalance(donor); + const userCross = helper.ethCrossAccount.fromAddress(user); + await collectionEvm.methods.addCollectionAdminCross(userCross).send(); + + const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user}); + const tokenId = result.events.Transfer.returnValues.tokenId; + + const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user)); + + switch (testCase) { + case 'transfer': + await collectionEvm.methods.transfer(receiver, tokenId).send({from: user}); + break; + case 'transferCross': + await collectionEvm.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user}); + break; + case 'transferFrom': + await collectionEvm.methods.transferFrom(user, receiver, tokenId).send({from: user}); + break; + case 'transferFromCross': + await collectionEvm.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), tokenId).send({from: user}); + break; + } + + const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore); + const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; + const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user)); + expect(userBalanceAfter).to.be.eq(userBalanceBefore); + })); }); + +describe('evm RFT token sponsoring', () => { + let donor: IKeyringPair; + + before(async function() { + await usingPlaygrounds(async (helper, privateKey) => { + requirePalletsOrSkip(this, helper, [Pallets.ReFungible]); + donor = await privateKey({filename: __filename}); + }); + }); + + [ + 'transfer', + 'transferCross', + 'transferFrom', + 'transferFromCross', + ].map(testCase => + itEth(`[${testCase}] Check that token piece transfer via EVM spend money from sponsor address`, async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', ''); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); + const receiver = await helper.eth.createAccountWithBalance(donor); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner); + + await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send(); + await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor}); + + const user = await helper.eth.createAccountWithBalance(donor); + const userCross = helper.ethCrossAccount.fromAddress(user); + await collectionEvm.methods.addCollectionAdminCross(userCross).send(); + + const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user}); + const tokenId = result.events.Transfer.returnValues.tokenId; + + const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, user); + await tokenContract.methods.repartition(2).send(); + + const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user)); + + switch (testCase) { + case 'transfer': + await tokenContract.methods.transfer(receiver, 1).send(); + break; + case 'transferCross': + await tokenContract.methods.transferCross(helper.ethCrossAccount.fromAddress(receiver), 1).send(); + break; + case 'transferFrom': + await tokenContract.methods.transferFrom(user, receiver, 1).send(); + break; + case 'transferFromCross': + await tokenContract.methods.transferFromCross(helper.ethCrossAccount.fromAddress(user), helper.ethCrossAccount.fromAddress(receiver), 1).send(); + break; + } + + const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore); + const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; + const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user)); + expect(userBalanceAfter).to.be.eq(userBalanceBefore); + })); + + [ + 'approve', + 'approveCross', + ].map(testCase => + itEth(`[${testCase}] Check that approve via EVM spend money from sponsor address`, async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner,'Sponsor collection', '1', '1', ''); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); + const receiver = await helper.eth.createAccountWithBalance(donor); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner); + + await collectionEvm.methods.setCollectionSponsorCross(sponsorCross).send(); + await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor}); + + const user = await helper.eth.createAccountWithBalance(donor); + const userCross = helper.ethCrossAccount.fromAddress(user); + await collectionEvm.methods.addCollectionAdminCross(userCross).send(); + + const result = await collectionEvm.methods.mintWithTokenURI(user, 'Test URI').send({from: user}); + const tokenId = result.events.Transfer.returnValues.tokenId; + + const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, user); + await tokenContract.methods.repartition(2).send(); + + const ownerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + const userBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user)); + + switch (testCase) { + case 'approve': + await tokenContract.methods.approve(receiver, 1).send(); + break; + case 'approveCross': + await tokenContract.methods.approveCross(helper.ethCrossAccount.fromAddress(receiver), 1).send(); + break; + } + + const ownerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(owner)); + expect(ownerBalanceAfter).to.be.eq(ownerBalanceBefore); + const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; + const userBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(user)); + expect(userBalanceAfter).to.be.eq(userBalanceBefore); + })); +}); + diff --git a/tests/src/eth/contractSponsoring.test.ts b/tests/src/eth/contractSponsoring.test.ts index 597bf27e13..69ac2df10c 100644 --- a/tests/src/eth/contractSponsoring.test.ts +++ b/tests/src/eth/contractSponsoring.test.ts @@ -22,29 +22,33 @@ import {CompiledContract} from './util/playgrounds/types'; describe('Sponsoring EVM contracts', () => { let donor: IKeyringPair; + let nominal: bigint; before(async () => { - await usingPlaygrounds(async (_helper, privateKey) => { + await usingPlaygrounds(async (helper, privateKey) => { donor = await privateKey({filename: __filename}); + nominal = helper.balance.getOneTokenNominal(); }); }); - itEth('Self sponsored can be set by the address that deployed the contract', async ({helper}) => { + itEth('Self sponsoring can be set by the address that deployed the contract', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const flipper = await helper.eth.deployFlipper(owner); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); + // 1. owner can set selfSponsoring: expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; - await expect(helpers.methods.selfSponsoredEnable(flipper.options.address).send()).to.be.not.rejected; + const result = await helpers.methods.selfSponsoredEnable(flipper.options.address).send({from: owner}); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true; - }); - itEth('Set self sponsored events', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - const flipper = await helper.eth.deployFlipper(owner); - const helpers = helper.ethNativeContract.contractHelpers(owner); - - const result = await helpers.methods.selfSponsoredEnable(flipper.options.address).send(); + // 1.1 Can get sponsor using methods.sponsor: + const actualSponsorOpt = await helpers.methods.sponsor(flipper.options.address).call(); + expect(actualSponsorOpt.status).to.be.true; + const actualSponsor = actualSponsorOpt.value; + expect(actualSponsor.eth).to.eq(flipper.options.address); + expect(actualSponsor.sub).to.eq('0'); + + // 2. Events should be: const ethEvents = helper.eth.helper.eth.normalizeEvents(result.events); expect(ethEvents).to.be.deep.equal([ { @@ -66,10 +70,10 @@ describe('Sponsoring EVM contracts', () => { ]); }); - itEth('Self sponsored can not be set by the address that did not deployed the contract', async ({helper}) => { + itEth('Self sponsoring cannot be set by the address that did not deployed the contract', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const notOwner = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; @@ -79,43 +83,37 @@ describe('Sponsoring EVM contracts', () => { itEth('Sponsoring can be set by the address that has deployed the contract', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false; - await expect(helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner})).to.be.not.rejected; + await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner}); expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.true; }); itEth('Sponsoring cannot be set by the address that did not deployed the contract', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const notOwner = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false; await expect(helpers.methods.setSponsoringMode(notOwner, SponsoringMode.Allowlisted).call({from: notOwner})).to.be.rejectedWith('NoPermission'); expect(await helpers.methods.sponsoringEnabled(flipper.options.address).call()).to.be.false; }); - + itEth('Sponsor can be set by the address that deployed the contract', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); + // 1. owner can set a sponsor: expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false; - await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected; - expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true; - }); - - itEth('Set sponsor event', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - const sponsor = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); - const flipper = await helper.eth.deployFlipper(owner); - const result = await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); + expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.true; + + // 2. Events should be: const events = helper.eth.normalizeEvents(result.events); expect(events).to.be.deep.equal([ { @@ -128,12 +126,12 @@ describe('Sponsoring EVM contracts', () => { }, ]); }); - - itEth('Sponsor can not be set by the address that did not deployed the contract', async ({helper}) => { + + itEth('Sponsor cannot be set by the address that did not deployed the contract', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); const notOwner = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); expect(await helpers.methods.hasPendingSponsor(flipper.options.address).call()).to.be.false; @@ -144,23 +142,24 @@ describe('Sponsoring EVM contracts', () => { itEth('Sponsorship can be confirmed by the address that pending as sponsor', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; - await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected; - await expect(helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor})).to.be.not.rejected; + await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); + + // 1. sponsor can confirm sponsorship: + const result = await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true; - }); - itEth('Confirm sponsorship event', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - const sponsor = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); - const flipper = await helper.eth.deployFlipper(owner); + // 1.1 Can get sponsor using methods.sponsor: + const actualSponsorOpt = await helpers.methods.sponsor(flipper.options.address).call(); + expect(actualSponsorOpt.status).to.be.true; + const actualSponsor = actualSponsorOpt.value; + expect(actualSponsor.eth).to.eq(sponsor); + expect(actualSponsor.sub).to.eq('0'); - await expect(helpers.methods.setSponsor(flipper.options.address, sponsor).send()).to.be.not.rejected; - const result = await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); + // 2. Events should be: const events = helper.eth.normalizeEvents(result.events); expect(events).to.be.deep.equal([ { @@ -178,7 +177,7 @@ describe('Sponsoring EVM contracts', () => { const owner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); const notSponsor = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; @@ -190,7 +189,7 @@ describe('Sponsoring EVM contracts', () => { itEth('Sponsorship can not be confirmed by the address that not set as sponsor', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const notSponsor = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; @@ -198,59 +197,21 @@ describe('Sponsoring EVM contracts', () => { expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; }); - itEth('Get self sponsored sponsor', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); - const flipper = await helper.eth.deployFlipper(owner); - - await helpers.methods.selfSponsoredEnable(flipper.options.address).send(); - - const result = await helpers.methods.sponsor(flipper.options.address).call(); - - expect(result[0]).to.be.eq(flipper.options.address); - expect(result[1]).to.be.eq('0'); - }); - - itEth('Get confirmed sponsor', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - const sponsor = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); - const flipper = await helper.eth.deployFlipper(owner); - - await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); - await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); - - const result = await helpers.methods.sponsor(flipper.options.address).call(); - - expect(result[0]).to.be.eq(sponsor); - expect(result[1]).to.be.eq('0'); - }); - itEth('Sponsor can be removed by the address that deployed the contract', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true; - - await helpers.methods.removeSponsor(flipper.options.address).send(); + // 1. Can remove sponsor: + const result = await helpers.methods.removeSponsor(flipper.options.address).send(); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; - }); - itEth('Remove sponsor event', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - const sponsor = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); - const flipper = await helper.eth.deployFlipper(owner); - - await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); - await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); - - const result = await helpers.methods.removeSponsor(flipper.options.address).send(); + // 2. Events should be: const events = helper.eth.normalizeEvents(result.events); expect(events).to.be.deep.equal([ { @@ -261,21 +222,27 @@ describe('Sponsoring EVM contracts', () => { }, }, ]); + + // TODO: why call method reverts? + // const actualSponsor = await helpers.methods.sponsor(flipper.options.address).call(); + // expect(actualSponsor.eth).to.eq(sponsor); + // expect(actualSponsor.sub).to.eq('0'); }); itEth('Sponsor can not be removed by the address that did not deployed the contract', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const notOwner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.false; await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true; - + await expect(helpers.methods.removeSponsor(flipper.options.address).call({from: notOwner})).to.be.rejectedWith('NoPermission'); + await expect(helpers.methods.removeSponsor(flipper.options.address).send({from: notOwner})).to.be.rejected; expect(await helpers.methods.hasSponsor(flipper.options.address).call()).to.be.true; }); @@ -283,7 +250,7 @@ describe('Sponsoring EVM contracts', () => { const owner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); const caller = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); @@ -292,15 +259,15 @@ describe('Sponsoring EVM contracts', () => { await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Generous).send({from: owner}); await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner}); - const sponsorBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); - const callerBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller)); + const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + const callerBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller)); await flipper.methods.flip().send({from: caller}); expect(await flipper.methods.getValue().call()).to.be.true; // Balance should be taken from sponsor instead of caller - const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); - const callerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller)); + const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + const callerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller)); expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; expect(callerBalanceAfter).to.be.eq(callerBalanceBefore); }); @@ -308,7 +275,7 @@ describe('Sponsoring EVM contracts', () => { itEth('In generous mode, non-allowlisted user transaction will be self sponsored', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const caller = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); await helpers.methods.selfSponsoredEnable(flipper.options.address).send(); @@ -331,91 +298,76 @@ describe('Sponsoring EVM contracts', () => { expect(callerBalanceAfter).to.be.eq(callerBalanceBefore); }); - itEth('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should decrease (allowlisted)', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - const sponsor = await helper.eth.createAccountWithBalance(donor); - const caller = helper.eth.createAccount(); - const helpers = helper.ethNativeContract.contractHelpers(owner); - const flipper = await helper.eth.deployFlipper(owner); - - await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner}); - await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner}); - - await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner}); - await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner}); - - await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); - await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); - - const sponsorBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); - expect(sponsorBalanceBefore).to.be.not.equal('0'); - - await flipper.methods.flip().send({from: caller}); - expect(await flipper.methods.getValue().call()).to.be.true; - - // Balance should be taken from flipper instead of caller - const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); - expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; + [ + {balance: 0n, label: '0'}, + {balance: 10n, label: '10'}, + ].map(testCase => { + itEth(`Allow-listed address that has ${testCase.label} UNQ can call a contract. Sponsor balance should decrease`, async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const caller = helper.eth.createAccount(); + await helper.eth.transferBalanceFromSubstrate(donor, caller, testCase.balance); + const helpers = await helper.ethNativeContract.contractHelpers(owner); + const flipper = await helper.eth.deployFlipper(owner); + + await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner}); + await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner}); + + await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner}); + await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner}); + + await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); + await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); + + const sponsorBalanceBefore = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + expect(sponsorBalanceBefore > 0n).to.be.true; + + await flipper.methods.flip().send({from: caller}); + expect(await flipper.methods.getValue().call()).to.be.true; + + // Balance should be taken from flipper instead of caller + const sponsorBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(sponsor)); + expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; + // Caller's balance does not change: + const callerBalanceAfter = await helper.balance.getSubstrate(helper.address.ethToSubstrate(caller)); + expect(callerBalanceAfter).to.eq(testCase.balance * nominal); + }); }); - itEth('Sponsoring is set, an address that has no UNQ can send a transaction and it works. Sponsor balance should not decrease (non-allowlisted)', async ({helper}) => { + itEth('Non-allow-listed address can call a contract. Sponsor balance should not decrease', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const caller = await helper.eth.createAccount(); - const helpers = helper.ethNativeContract.contractHelpers(owner); - const flipper = await helper.eth.deployFlipper(owner); - - await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner}); - await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner}); + const caller = helper.eth.createAccount(); + const contractHelpers = await helper.ethNativeContract.contractHelpers(owner); + // Deploy flipper and send some tokens: + const flipper = await helper.eth.deployFlipper(owner); await helper.eth.transferBalanceFromSubstrate(donor, flipper.options.address); - + expect(await flipper.methods.getValue().call()).to.be.false; + // flipper address has some tokens: const originalFlipperBalance = await helper.balance.getEthereum(flipper.options.address); - expect(originalFlipperBalance).to.be.not.equal('0'); + expect(originalFlipperBalance > 0n).to.be.true; + + // Set Allowlisted sponsoring mode. caller is not in allow list: + await contractHelpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner}); + await contractHelpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner}); + await contractHelpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner}); - await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/InvalidTransaction::Payment/); + // 1. Caller has no UNQ and is not in allow list. So he cannot flip: + await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/Returned error: insufficient funds for gas \* price \+ value/); expect(await flipper.methods.getValue().call()).to.be.false; - // Balance should be taken from flipper instead of caller - // FIXME the comment is wrong! What check should be here? + // Flipper's balance does not change: const balanceAfter = await helper.balance.getEthereum(flipper.options.address); expect(balanceAfter).to.be.equal(originalFlipperBalance); }); - itEth('Sponsoring is set, an address that has UNQ can send a transaction and it works. User balance should not change', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - const sponsor = await helper.eth.createAccountWithBalance(donor); - const caller = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); - const flipper = await helper.eth.deployFlipper(owner); - - await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner}); - await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner}); - - await helpers.methods.setSponsoringMode(flipper.options.address, SponsoringMode.Allowlisted).send({from: owner}); - await helpers.methods.setSponsoringRateLimit(flipper.options.address, 0).send({from: owner}); - - await helpers.methods.setSponsor(flipper.options.address, sponsor).send(); - await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); - - const sponsorBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); - const callerBalanceBefore = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller)); - - await flipper.methods.flip().send({from: caller}); - expect(await flipper.methods.getValue().call()).to.be.true; - - const sponsorBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(sponsor)); - const callerBalanceAfter = await helper.balance.getSubstrate(await helper.address.ethToSubstrate(caller)); - expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; - expect(callerBalanceAfter).to.be.equal(callerBalanceBefore); - }); - itEth('Sponsoring is limited, with setContractRateLimit. The limitation is working if transactions are sent more often, the sender pays the commission.', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); const caller = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); - + const originalCallerBalance = await helper.balance.getEthereum(caller); await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner}); await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner}); @@ -427,7 +379,7 @@ describe('Sponsoring EVM contracts', () => { await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); const originalFlipperBalance = await helper.balance.getEthereum(sponsor); - expect(originalFlipperBalance).to.be.not.equal('0'); + expect(originalFlipperBalance > 0n).to.be.true; await flipper.methods.flip().send({from: caller}); expect(await flipper.methods.getValue().call()).to.be.true; @@ -445,7 +397,7 @@ describe('Sponsoring EVM contracts', () => { // TODO: Find a way to calculate default rate limit itEth('Default rate limit equal 7200', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); expect(await helpers.methods.sponsoringRateLimit(flipper.options.address).call()).to.be.equal('7200'); @@ -464,7 +416,7 @@ describe('Sponsoring Fee Limit', () => { ` // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; - + contract TestContract { event Result(bool); @@ -484,7 +436,7 @@ describe('Sponsoring Fee Limit', () => { } return testContract; } - + async function deployTestContract(helper: EthUniqueHelper, owner: string) { const compiled = await compileTestContract(helper); return await helper.ethContract.deployByAbi(owner, compiled.abi, compiled.object); @@ -499,7 +451,7 @@ describe('Sponsoring Fee Limit', () => { itEth('Default fee limit', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); expect(await helpers.methods.sponsoringFeeLimit(flipper.options.address).call()).to.be.equal('115792089237316195423570985008687907853269984665640564039457584007913129639935'); @@ -507,7 +459,7 @@ describe('Sponsoring Fee Limit', () => { itEth('Set fee limit', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); await helpers.methods.setSponsoringFeeLimit(flipper.options.address, 100).send(); @@ -517,7 +469,7 @@ describe('Sponsoring Fee Limit', () => { itEth('Negative test - set fee limit by non-owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const stranger = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const flipper = await helper.eth.deployFlipper(owner); await expect(helpers.methods.setSponsoringFeeLimit(flipper.options.address, 100).send({from: stranger})).to.be.rejected; @@ -527,13 +479,13 @@ describe('Sponsoring Fee Limit', () => { const owner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); const user = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const testContract = await deployTestContract(helper, owner); - + await helpers.methods.setSponsoringMode(testContract.options.address, SponsoringMode.Generous).send({from: owner}); await helpers.methods.setSponsoringRateLimit(testContract.options.address, 0).send({from: owner}); - + await helpers.methods.setSponsor(testContract.options.address, sponsor).send(); await helpers.methods.confirmSponsorship(testContract.options.address).send({from: sponsor}); @@ -552,13 +504,13 @@ describe('Sponsoring Fee Limit', () => { itEth('Negative test - check that evm.call transactions exceeding fee limit are not executed', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); const testContract = await deployTestContract(helper, owner); - + await helpers.methods.setSponsoringMode(testContract.options.address, SponsoringMode.Generous).send({from: owner}); await helpers.methods.setSponsoringRateLimit(testContract.options.address, 0).send({from: owner}); - + await helpers.methods.setSponsor(testContract.options.address, sponsor).send(); await helpers.methods.confirmSponsorship(testContract.options.address).send({from: sponsor}); @@ -577,7 +529,7 @@ describe('Sponsoring Fee Limit', () => { ); // expect((await api.query.system.account(alice.address)).data.free.toBigInt()).to.be.equal(originalAliceBalance); expect(await helper.balance.getSubstrate(alice.address)).to.be.equal(originalAliceBalance); - + await helper.eth.sendEVM( alice, testContract.options.address, diff --git a/tests/src/eth/createFTCollection.seqtest.ts b/tests/src/eth/createFTCollection.seqtest.ts new file mode 100644 index 0000000000..e4ba213873 --- /dev/null +++ b/tests/src/eth/createFTCollection.seqtest.ts @@ -0,0 +1,76 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {IKeyringPair} from '@polkadot/types/types'; +import {Pallets, requirePalletsOrSkip} from '../util'; +import {expect, itEth, usingEthPlaygrounds} from './util'; + +const DECIMALS = 18; + +describe('Create FT collection from EVM', () => { + let donor: IKeyringPair; + + before(async function() { + await usingEthPlaygrounds(async (helper, privateKey) => { + requirePalletsOrSkip(this, helper, [Pallets.Fungible]); + donor = await privateKey({filename: __filename}); + }); + }); + + itEth('Create collection', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const name = 'CollectionEVM'; + const description = 'Some description'; + const prefix = 'token prefix'; + + // todo:playgrounds this might fail when in async environment. + const collectionCountBefore = +(await helper.callRpc('api.rpc.unique.collectionStats')).created; + + const {collectionId} = await helper.eth.createFungibleCollection(owner, name, DECIMALS, description, prefix); + + const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created; + const data = (await helper.ft.getData(collectionId))!; + + expect(collectionCountAfter - collectionCountBefore).to.be.eq(1); + expect(collectionId).to.be.eq(collectionCountAfter); + expect(data.name).to.be.eq(name); + expect(data.description).to.be.eq(description); + expect(data.raw.tokenPrefix).to.be.eq(prefix); + expect(data.raw.mode).to.be.deep.eq({Fungible: DECIMALS.toString()}); + }); + + // todo:playgrounds this test will fail when in async environment. + itEth('Check collection address exist', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1; + const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId); + const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner); + + expect(await collectionHelpers.methods + .isCollectionExist(expectedCollectionAddress) + .call()).to.be.false; + + + await helper.eth.createFungibleCollection(owner, 'A', DECIMALS, 'A', 'A'); + + + expect(await collectionHelpers.methods + .isCollectionExist(expectedCollectionAddress) + .call()).to.be.true; + }); +}); diff --git a/tests/src/eth/createFTCollection.test.ts b/tests/src/eth/createFTCollection.test.ts new file mode 100644 index 0000000000..1c2d1bc299 --- /dev/null +++ b/tests/src/eth/createFTCollection.test.ts @@ -0,0 +1,237 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {IKeyringPair} from '@polkadot/types/types'; +import {evmToAddress} from '@polkadot/util-crypto'; +import {Pallets, requirePalletsOrSkip} from '../util'; +import {expect, itEth, usingEthPlaygrounds} from './util'; +import {CollectionLimitField} from './util/playgrounds/types'; + +const DECIMALS = 18; + +describe('Create FT collection from EVM', () => { + let donor: IKeyringPair; + + before(async function() { + await usingEthPlaygrounds(async (helper, privateKey) => { + requirePalletsOrSkip(this, helper, [Pallets.Fungible]); + donor = await privateKey({filename: __filename}); + }); + }); + + // TODO move sponsorship tests to another file: + // Soft-deprecated + itEth('[eth] Set sponsorship', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const ss58Format = helper.chain.getChainProperties().ss58Format; + const description = 'absolutely anything'; + + const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, description, 'ENVY'); + + const collection = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true); + await collection.methods.setCollectionSponsor(sponsor).send(); + + let data = (await helper.rft.getData(collectionId))!; + expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); + + await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail'); + + const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true); + await sponsorCollection.methods.confirmCollectionSponsorship().send(); + + data = (await helper.rft.getData(collectionId))!; + expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); + }); + + itEth('[cross] Set sponsorship', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const ss58Format = helper.chain.getChainProperties().ss58Format; + const description = 'absolutely anything'; + const {collectionId, collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', DECIMALS, description, 'ENVY'); + + const collection = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner); + const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); + await collection.methods.setCollectionSponsorCross(sponsorCross).send(); + + let data = (await helper.rft.getData(collectionId))!; + expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); + + await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail'); + + const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor); + await sponsorCollection.methods.confirmCollectionSponsorship().send(); + + data = (await helper.rft.getData(collectionId))!; + expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); + expect(await collection.methods.description().call()).to.deep.equal(description); + }); + + itEth('Collection address exist', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233'; + const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner); + + expect(await collectionHelpers + .methods.isCollectionExist(collectionAddressForNonexistentCollection).call()) + .to.be.false; + + const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT'); + expect(await collectionHelpers + .methods.isCollectionExist(collectionAddress).call()) + .to.be.true; + + // check collectionOwner: + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true); + const collectionOwner = await collectionEvm.methods.collectionOwner().call(); + expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true)); + }); + + itEth('destroyCollection', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionAddress, collectionId} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT'); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + + const result = await collectionHelper.methods + .destroyCollection(collectionAddress) + .send({from: owner}); + + const events = helper.eth.normalizeEvents(result.events); + + expect(events).to.be.deep.equal([ + { + address: collectionHelper.options.address, + event: 'CollectionDestroyed', + args: { + collectionId: collectionAddress, + }, + }, + ]); + + expect(await collectionHelper.methods + .isCollectionExist(collectionAddress) + .call()).to.be.false; + expect(await helper.collection.getData(collectionId)).to.be.null; + }); +}); + +describe('(!negative tests!) Create FT collection from EVM', () => { + let donor: IKeyringPair; + let nominal: bigint; + + before(async function() { + await usingEthPlaygrounds(async (helper, privateKey) => { + requirePalletsOrSkip(this, helper, [Pallets.Fungible]); + donor = await privateKey({filename: __filename}); + nominal = helper.balance.getOneTokenNominal(); + }); + }); + + itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + { + const MAX_NAME_LENGTH = 64; + const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1); + const description = 'A'; + const tokenPrefix = 'A'; + + await expect(collectionHelper.methods + .createFTCollection(collectionName, DECIMALS, description, tokenPrefix) + .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH); + } + { + const MAX_DESCRIPTION_LENGTH = 256; + const collectionName = 'A'; + const description = 'A'.repeat(MAX_DESCRIPTION_LENGTH + 1); + const tokenPrefix = 'A'; + await expect(collectionHelper.methods + .createFTCollection(collectionName, DECIMALS, description, tokenPrefix) + .call({value: Number(2n * nominal)})).to.be.rejectedWith('description is too long. Max length is ' + MAX_DESCRIPTION_LENGTH); + } + { + const MAX_TOKEN_PREFIX_LENGTH = 16; + const collectionName = 'A'; + const description = 'A'; + const tokenPrefix = 'A'.repeat(MAX_TOKEN_PREFIX_LENGTH + 1); + await expect(collectionHelper.methods + .createFTCollection(collectionName, DECIMALS, description, tokenPrefix) + .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH); + } + }); + + itEth('(!negative test!) cannot create collection if value !== 2', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + const expects = [0n, 1n, 30n].map(async value => { + await expect(collectionHelper.methods + .createFTCollection('Peasantry', DECIMALS, 'absolutely anything', 'TWIW') + .call({value: Number(value * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); + }); + await Promise.all(expects); + }); + + // Soft-deprecated + itEth('(!negative test!) [eth] Check owner', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const peasant = helper.eth.createAccount(); + const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Transgressed', DECIMALS, 'absolutely anything', 'YVNE'); + const peasantCollection = await helper.ethNativeContract.collection(collectionAddress, 'ft', peasant, true); + const EXPECTED_ERROR = 'NoPermission'; + { + const sponsor = await helper.eth.createAccountWithBalance(donor); + await expect(peasantCollection.methods + .setCollectionSponsor(sponsor) + .call()).to.be.rejectedWith(EXPECTED_ERROR); + + const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'ft', sponsor, true); + await expect(sponsorCollection.methods + .confirmCollectionSponsorship() + .call()).to.be.rejectedWith('ConfirmSponsorshipFail'); + } + { + await expect(peasantCollection.methods + .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}) + .call()).to.be.rejectedWith(EXPECTED_ERROR); + } + }); + + itEth('(!negative test!) [cross] Check owner', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const peasant = helper.eth.createAccount(); + const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Transgressed', DECIMALS, 'absolutely anything', 'YVNE'); + const peasantCollection = await helper.ethNativeContract.collection(collectionAddress, 'ft', peasant); + const EXPECTED_ERROR = 'NoPermission'; + { + const sponsor = await helper.eth.createAccountWithBalance(donor); + const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); + await expect(peasantCollection.methods + .setCollectionSponsorCross(sponsorCross) + .call()).to.be.rejectedWith(EXPECTED_ERROR); + + const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'ft', sponsor); + await expect(sponsorCollection.methods + .confirmCollectionSponsorship() + .call()).to.be.rejectedWith('ConfirmSponsorshipFail'); + } + { + await expect(peasantCollection.methods + .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}) + .call()).to.be.rejectedWith(EXPECTED_ERROR); + } + }); +}); diff --git a/tests/src/eth/createNFTCollection.seqtest.ts b/tests/src/eth/createNFTCollection.seqtest.ts new file mode 100644 index 0000000000..1cebe8d8ea --- /dev/null +++ b/tests/src/eth/createNFTCollection.seqtest.ts @@ -0,0 +1,89 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {IKeyringPair} from '@polkadot/types/types'; +import {expect, itEth, usingEthPlaygrounds} from './util'; + + +describe('Create NFT collection from EVM', () => { + let donor: IKeyringPair; + + before(async function () { + await usingEthPlaygrounds(async (_helper, privateKey) => { + donor = await privateKey({filename: __filename}); + }); + }); + + itEth('Create collection', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const name = 'CollectionEVM'; + const description = 'Some description'; + const prefix = 'token prefix'; + + // todo:playgrounds this might fail when in async environment. + const collectionCountBefore = +(await helper.callRpc('api.rpc.unique.collectionStats')).created; + const {collectionId, collectionAddress, events} = await helper.eth.createNFTCollection(owner, name, description, prefix); + + expect(events).to.be.deep.equal([ + { + address: '0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F', + event: 'CollectionCreated', + args: { + owner: owner, + collectionId: collectionAddress, + }, + }, + ]); + + const collectionCountAfter = +(await helper.callRpc('api.rpc.unique.collectionStats')).created; + + const collection = helper.nft.getCollectionObject(collectionId); + const data = (await collection.getData())!; + + expect(collectionCountAfter - collectionCountBefore).to.be.eq(1); + expect(collectionId).to.be.eq(collectionCountAfter); + expect(data.name).to.be.eq(name); + expect(data.description).to.be.eq(description); + expect(data.raw.tokenPrefix).to.be.eq(prefix); + expect(data.raw.mode).to.be.eq('NFT'); + + const options = await collection.getOptions(); + + expect(options.tokenPropertyPermissions).to.be.empty; + }); + + // this test will occasionally fail when in async environment. + itEth('Check collection address exist', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1; + const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId); + const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner); + + expect(await collectionHelpers.methods + .isCollectionExist(expectedCollectionAddress) + .call()).to.be.false; + + await collectionHelpers.methods + .createNFTCollection('A', 'A', 'A') + .send({value: Number(2n * helper.balance.getOneTokenNominal())}); + + expect(await collectionHelpers.methods + .isCollectionExist(expectedCollectionAddress) + .call()).to.be.true; + }); +}); diff --git a/tests/src/eth/createNFTCollection.test.ts b/tests/src/eth/createNFTCollection.test.ts index c3df62101f..67be99969e 100644 --- a/tests/src/eth/createNFTCollection.test.ts +++ b/tests/src/eth/createNFTCollection.test.ts @@ -17,39 +17,19 @@ import {evmToAddress} from '@polkadot/util-crypto'; import {IKeyringPair} from '@polkadot/types/types'; import {expect, itEth, usingEthPlaygrounds} from './util'; +import {CollectionLimitField} from './util/playgrounds/types'; describe('Create NFT collection from EVM', () => { let donor: IKeyringPair; - before(async function() { + before(async function () { await usingEthPlaygrounds(async (_helper, privateKey) => { donor = await privateKey({filename: __filename}); }); }); - itEth('Create collection', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - - const name = 'CollectionEVM'; - const description = 'Some description'; - const prefix = 'token prefix'; - - const {collectionId} = await helper.eth.createNFTCollection(owner, name, description, prefix); - const data = (await helper.rft.getData(collectionId))!; - const collection = helper.nft.getCollectionObject(collectionId); - - expect(data.name).to.be.eq(name); - expect(data.description).to.be.eq(description); - expect(data.raw.tokenPrefix).to.be.eq(prefix); - expect(data.raw.mode).to.be.eq('NFT'); - - const options = await collection.getOptions(); - - expect(options.tokenPropertyPermissions).to.be.empty; - }); - - itEth('Create collection with properties', async ({helper}) => { + itEth('Create collection with properties & get desctription', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const name = 'CollectionEVM'; @@ -57,16 +37,30 @@ describe('Create NFT collection from EVM', () => { const prefix = 'token prefix'; const baseUri = 'BaseURI'; - const {collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, name, description, prefix, baseUri); + const {collectionId, collectionAddress, events} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, name, description, prefix, baseUri); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft'); + + expect(events).to.be.deep.equal([ + { + address: '0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F', + event: 'CollectionCreated', + args: { + owner: owner, + collectionId: collectionAddress, + }, + }, + ]); const collection = helper.nft.getCollectionObject(collectionId); const data = (await collection.getData())!; - + expect(data.name).to.be.eq(name); expect(data.description).to.be.eq(description); expect(data.raw.tokenPrefix).to.be.eq(prefix); expect(data.raw.mode).to.be.eq('NFT'); + expect(await contract.methods.description().call()).to.deep.equal(description); + const options = await collection.getOptions(); expect(options.tokenPropertyPermissions).to.be.deep.equal([ { @@ -80,97 +74,71 @@ describe('Create NFT collection from EVM', () => { ]); }); - // this test will occasionally fail when in async environment. - itEth.skip('Check collection address exist', async ({helper}) => { + // Soft-deprecated + itEth('[eth] Set sponsorship', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const ss58Format = helper.chain.getChainProperties().ss58Format; + const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC'); - const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1; - const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId); - const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner); + const collection = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true); + await collection.methods.setCollectionSponsor(sponsor).send(); - expect(await collectionHelpers.methods - .isCollectionExist(expectedCollectionAddress) - .call()).to.be.false; + let data = (await helper.nft.getData(collectionId))!; + expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); + + await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail'); + + const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor, true); + await sponsorCollection.methods.confirmCollectionSponsorship().send(); - await collectionHelpers.methods - .createNFTCollection('A', 'A', 'A') - .send({value: Number(2n * helper.balance.getOneTokenNominal())}); - - expect(await collectionHelpers.methods - .isCollectionExist(expectedCollectionAddress) - .call()).to.be.true; + data = (await helper.nft.getData(collectionId))!; + expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); }); - - itEth('Set sponsorship', async ({helper}) => { + + itEth('[cross] Set sponsorship & get description', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); const ss58Format = helper.chain.getChainProperties().ss58Format; - const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC'); + const description = 'absolutely anything'; + const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', description, 'ROC'); - const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - await collection.methods.setCollectionSponsor(sponsor).send(); + const collection = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); + await collection.methods.setCollectionSponsorCross(sponsorCross).send(); let data = (await helper.nft.getData(collectionId))!; expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); - await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor'); + await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail'); - const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor); + const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor); await sponsorCollection.methods.confirmCollectionSponsorship().send(); data = (await helper.nft.getData(collectionId))!; expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); - }); - itEth('Set limits', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionId, collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'FLO'); - const limits = { - accountTokenOwnershipLimit: 1000, - sponsoredDataSize: 1024, - sponsoredDataRateLimit: 30, - tokenLimit: 1000000, - sponsorTransferTimeout: 6, - sponsorApproveTimeout: 6, - ownerCanTransfer: false, - ownerCanDestroy: false, - transfersEnabled: false, - }; - - const collection = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - await collection.methods['setCollectionLimit(string,uint32)']('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit).send(); - await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataSize', limits.sponsoredDataSize).send(); - await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataRateLimit', limits.sponsoredDataRateLimit).send(); - await collection.methods['setCollectionLimit(string,uint32)']('tokenLimit', limits.tokenLimit).send(); - await collection.methods['setCollectionLimit(string,uint32)']('sponsorTransferTimeout', limits.sponsorTransferTimeout).send(); - await collection.methods['setCollectionLimit(string,uint32)']('sponsorApproveTimeout', limits.sponsorApproveTimeout).send(); - await collection.methods['setCollectionLimit(string,bool)']('ownerCanTransfer', limits.ownerCanTransfer).send(); - await collection.methods['setCollectionLimit(string,bool)']('ownerCanDestroy', limits.ownerCanDestroy).send(); - await collection.methods['setCollectionLimit(string,bool)']('transfersEnabled', limits.transfersEnabled).send(); - - const data = (await helper.nft.getData(collectionId))!; - expect(data.raw.limits.accountTokenOwnershipLimit).to.be.eq(limits.accountTokenOwnershipLimit); - expect(data.raw.limits.sponsoredDataSize).to.be.eq(limits.sponsoredDataSize); - expect(data.raw.limits.sponsoredDataRateLimit.blocks).to.be.eq(limits.sponsoredDataRateLimit); - expect(data.raw.limits.tokenLimit).to.be.eq(limits.tokenLimit); - expect(data.raw.limits.sponsorTransferTimeout).to.be.eq(limits.sponsorTransferTimeout); - expect(data.raw.limits.sponsorApproveTimeout).to.be.eq(limits.sponsorApproveTimeout); - expect(data.raw.limits.ownerCanTransfer).to.be.eq(limits.ownerCanTransfer); - expect(data.raw.limits.ownerCanDestroy).to.be.eq(limits.ownerCanDestroy); - expect(data.raw.limits.transfersEnabled).to.be.eq(limits.transfersEnabled); + expect(await sponsorCollection.methods.description().call()).to.deep.equal(description); }); itEth('Collection address exist', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233'; - expect(await helper.ethNativeContract.collectionHelpers(collectionAddressForNonexistentCollection) + const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner); + + expect(await collectionHelpers .methods.isCollectionExist(collectionAddressForNonexistentCollection).call()) .to.be.false; - + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Exister', 'absolutely anything', 'EVC'); - expect(await helper.ethNativeContract.collectionHelpers(collectionAddress) + expect(await collectionHelpers .methods.isCollectionExist(collectionAddress).call()) .to.be.true; + + // check collectionOwner: + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true); + const collectionOwner = await collectionEvm.methods.collectionOwner().call(); + expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true)); }); }); @@ -178,7 +146,7 @@ describe('(!negative tests!) Create NFT collection from EVM', () => { let donor: IKeyringPair; let nominal: bigint; - before(async function() { + before(async function () { await usingEthPlaygrounds(async (helper, privateKey) => { donor = await privateKey({filename: __filename}); nominal = helper.balance.getOneTokenNominal(); @@ -187,7 +155,7 @@ describe('(!negative tests!) Create NFT collection from EVM', () => { itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const collectionHelper = helper.ethNativeContract.collectionHelpers(owner); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); { const MAX_NAME_LENGTH = 64; const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1); @@ -197,7 +165,7 @@ describe('(!negative tests!) Create NFT collection from EVM', () => { await expect(collectionHelper.methods .createNFTCollection(collectionName, description, tokenPrefix) .call({value: Number(2n * nominal)})).to.be.rejectedWith('name is too long. Max length is ' + MAX_NAME_LENGTH); - + } { const MAX_DESCRIPTION_LENGTH = 256; @@ -218,45 +186,90 @@ describe('(!negative tests!) Create NFT collection from EVM', () => { .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH); } }); - + itEth('(!negative test!) Create collection (no funds)', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const collectionHelper = helper.ethNativeContract.collectionHelpers(owner); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); await expect(collectionHelper.methods .createNFTCollection('Peasantry', 'absolutely anything', 'CVE') .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); }); - itEth('(!negative test!) Check owner', async ({helper}) => { + // Soft-deprecated + itEth('(!negative test!) [eth] Check owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const malfeasant = helper.eth.createAccount(); const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Transgressed', 'absolutely anything', 'COR'); - const malfeasantCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', malfeasant); + const malfeasantCollection = await helper.ethNativeContract.collection(collectionAddress, 'nft', malfeasant, true); const EXPECTED_ERROR = 'NoPermission'; { const sponsor = await helper.eth.createAccountWithBalance(donor); await expect(malfeasantCollection.methods .setCollectionSponsor(sponsor) .call()).to.be.rejectedWith(EXPECTED_ERROR); - - const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor); + + const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor, true); + await expect(sponsorCollection.methods + .confirmCollectionSponsorship() + .call()).to.be.rejectedWith('ConfirmSponsorshipFail'); + } + { + await expect(malfeasantCollection.methods + .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}) + .call()).to.be.rejectedWith(EXPECTED_ERROR); + } + }); + + itEth('(!negative test!) [cross] Check owner', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const malfeasant = helper.eth.createAccount(); + const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Transgressed', 'absolutely anything', 'COR'); + const malfeasantCollection = await helper.ethNativeContract.collection(collectionAddress, 'nft', malfeasant); + const EXPECTED_ERROR = 'NoPermission'; + { + const sponsor = await helper.eth.createAccountWithBalance(donor); + const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); + await expect(malfeasantCollection.methods + .setCollectionSponsorCross(sponsorCross) + .call()).to.be.rejectedWith(EXPECTED_ERROR); + + const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor); await expect(sponsorCollection.methods .confirmCollectionSponsorship() - .call()).to.be.rejectedWith('caller is not set as sponsor'); + .call()).to.be.rejectedWith('ConfirmSponsorshipFail'); } { await expect(malfeasantCollection.methods - .setCollectionLimit('account_token_ownership_limit', '1000') + .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}) .call()).to.be.rejectedWith(EXPECTED_ERROR); } }); - itEth('(!negative test!) Set limits', async ({helper}) => { + itEth('destroyCollection', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - await expect(collectionEvm.methods - .setCollectionLimit('badLimit', 'true') - .call()).to.be.rejectedWith('unknown boolean limit "badLimit"'); + const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF'); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + + + const result = await collectionHelper.methods + .destroyCollection(collectionAddress) + .send({from: owner}); + + const events = helper.eth.normalizeEvents(result.events); + + expect(events).to.be.deep.equal([ + { + address: collectionHelper.options.address, + event: 'CollectionDestroyed', + args: { + collectionId: collectionAddress, + }, + }, + ]); + + expect(await collectionHelper.methods + .isCollectionExist(collectionAddress) + .call()).to.be.false; + expect(await helper.collection.getData(collectionId)).to.be.null; }); }); diff --git a/tests/src/eth/createRFTCollection.test.ts b/tests/src/eth/createRFTCollection.test.ts index a319d31bad..81a244a07e 100644 --- a/tests/src/eth/createRFTCollection.test.ts +++ b/tests/src/eth/createRFTCollection.test.ts @@ -18,6 +18,7 @@ import {evmToAddress} from '@polkadot/util-crypto'; import {IKeyringPair} from '@polkadot/types/types'; import {Pallets, requirePalletsOrSkip} from '../util'; import {expect, itEth, usingEthPlaygrounds} from './util'; +import {CollectionLimitField} from './util/playgrounds/types'; describe('Create RFT collection from EVM', () => { @@ -32,11 +33,11 @@ describe('Create RFT collection from EVM', () => { itEth('Create collection', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - + const name = 'CollectionEVM'; const description = 'Some description'; const prefix = 'token prefix'; - + const {collectionId} = await helper.eth.createRFTCollection(owner, name, description, prefix); const data = (await helper.rft.getData(collectionId))!; const collection = helper.rft.getCollectionObject(collectionId); @@ -51,9 +52,9 @@ describe('Create RFT collection from EVM', () => { expect(options.tokenPropertyPermissions).to.be.empty; }); - - itEth('Create collection with properties', async ({helper}) => { + + itEth('Create collection with properties & get description', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const name = 'CollectionEVM'; @@ -61,16 +62,19 @@ describe('Create RFT collection from EVM', () => { const prefix = 'token prefix'; const baseUri = 'BaseURI'; - const {collectionId} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri); + const {collectionId, collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, name, description, prefix, baseUri); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft'); const collection = helper.rft.getCollectionObject(collectionId); const data = (await collection.getData())!; - + expect(data.name).to.be.eq(name); expect(data.description).to.be.eq(description); expect(data.raw.tokenPrefix).to.be.eq(prefix); expect(data.raw.mode).to.be.eq('ReFungible'); + expect(await contract.methods.description().call()).to.deep.equal(description); + const options = await collection.getOptions(); expect(options.tokenPropertyPermissions).to.be.deep.equal([ { @@ -83,98 +87,69 @@ describe('Create RFT collection from EVM', () => { }, ]); }); - - // this test will occasionally fail when in async environment. - itEth.skip('Check collection address exist', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - - const expectedCollectionId = +(await helper.callRpc('api.rpc.unique.collectionStats')).created + 1; - const expectedCollectionAddress = helper.ethAddress.fromCollectionId(expectedCollectionId); - const collectionHelpers = helper.ethNativeContract.collectionHelpers(owner); - expect(await collectionHelpers.methods - .isCollectionExist(expectedCollectionAddress) - .call()).to.be.false; - - await collectionHelpers.methods - .createRFTCollection('A', 'A', 'A') - .send({value: Number(2n * helper.balance.getOneTokenNominal())}); - - expect(await collectionHelpers.methods - .isCollectionExist(expectedCollectionAddress) - .call()).to.be.true; - }); - - itEth('Set sponsorship', async ({helper}) => { + // Soft-deprecated + itEth('[eth] Set sponsorship', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const sponsor = await helper.eth.createAccountWithBalance(donor); const ss58Format = helper.chain.getChainProperties().ss58Format; const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY'); - const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); + const collection = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner, true); await collection.methods.setCollectionSponsor(sponsor).send(); let data = (await helper.rft.getData(collectionId))!; expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); - await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('caller is not set as sponsor'); + await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail'); - const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor); + const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true); await sponsorCollection.methods.confirmCollectionSponsorship().send(); data = (await helper.rft.getData(collectionId))!; expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); }); - itEth('Set limits', async ({helper}) => { + itEth('[cross] Set sponsorship', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'INSI'); - const limits = { - accountTokenOwnershipLimit: 1000, - sponsoredDataSize: 1024, - sponsoredDataRateLimit: 30, - tokenLimit: 1000000, - sponsorTransferTimeout: 6, - sponsorApproveTimeout: 6, - ownerCanTransfer: false, - ownerCanDestroy: false, - transfersEnabled: false, - }; - - const collection = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); - await collection.methods['setCollectionLimit(string,uint32)']('accountTokenOwnershipLimit', limits.accountTokenOwnershipLimit).send(); - await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataSize', limits.sponsoredDataSize).send(); - await collection.methods['setCollectionLimit(string,uint32)']('sponsoredDataRateLimit', limits.sponsoredDataRateLimit).send(); - await collection.methods['setCollectionLimit(string,uint32)']('tokenLimit', limits.tokenLimit).send(); - await collection.methods['setCollectionLimit(string,uint32)']('sponsorTransferTimeout', limits.sponsorTransferTimeout).send(); - await collection.methods['setCollectionLimit(string,uint32)']('sponsorApproveTimeout', limits.sponsorApproveTimeout).send(); - await collection.methods['setCollectionLimit(string,bool)']('ownerCanTransfer', limits.ownerCanTransfer).send(); - await collection.methods['setCollectionLimit(string,bool)']('ownerCanDestroy', limits.ownerCanDestroy).send(); - await collection.methods['setCollectionLimit(string,bool)']('transfersEnabled', limits.transfersEnabled).send(); - - const data = (await helper.rft.getData(collectionId))!; - expect(data.raw.limits.accountTokenOwnershipLimit).to.be.eq(limits.accountTokenOwnershipLimit); - expect(data.raw.limits.sponsoredDataSize).to.be.eq(limits.sponsoredDataSize); - expect(data.raw.limits.sponsoredDataRateLimit.blocks).to.be.eq(limits.sponsoredDataRateLimit); - expect(data.raw.limits.tokenLimit).to.be.eq(limits.tokenLimit); - expect(data.raw.limits.sponsorTransferTimeout).to.be.eq(limits.sponsorTransferTimeout); - expect(data.raw.limits.sponsorApproveTimeout).to.be.eq(limits.sponsorApproveTimeout); - expect(data.raw.limits.ownerCanTransfer).to.be.eq(limits.ownerCanTransfer); - expect(data.raw.limits.ownerCanDestroy).to.be.eq(limits.ownerCanDestroy); - expect(data.raw.limits.transfersEnabled).to.be.eq(limits.transfersEnabled); + const sponsor = await helper.eth.createAccountWithBalance(donor); + const ss58Format = helper.chain.getChainProperties().ss58Format; + const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ENVY'); + + const collection = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner); + const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); + await collection.methods.setCollectionSponsorCross(sponsorCross).send(); + + let data = (await helper.rft.getData(collectionId))!; + expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); + + await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail'); + + const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor); + await sponsorCollection.methods.confirmCollectionSponsorship().send(); + + data = (await helper.rft.getData(collectionId))!; + expect(data.raw.sponsorship.Confirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format))); }); itEth('Collection address exist', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const collectionAddressForNonexistentCollection = '0x17C4E6453CC49AAAAEACA894E6D9683E00112233'; - expect(await helper.ethNativeContract.collectionHelpers(collectionAddressForNonexistentCollection) + const collectionHelpers = await helper.ethNativeContract.collectionHelpers(owner); + + expect(await collectionHelpers .methods.isCollectionExist(collectionAddressForNonexistentCollection).call()) .to.be.false; - + const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Exister', 'absolutely anything', 'WIWT'); - expect(await helper.ethNativeContract.collectionHelpers(collectionAddress) + expect(await collectionHelpers .methods.isCollectionExist(collectionAddress).call()) .to.be.true; + + // check collectionOwner: + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true); + const collectionOwner = await collectionEvm.methods.collectionOwner().call(); + expect(helper.address.restoreCrossAccountFromBigInt(BigInt(collectionOwner.sub))).to.eq(helper.address.ethToSubstrate(owner, true)); }); }); @@ -192,7 +167,7 @@ describe('(!negative tests!) Create RFT collection from EVM', () => { itEth('(!negative test!) Create collection (bad lengths)', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const collectionHelper = helper.ethNativeContract.collectionHelpers(owner); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); { const MAX_NAME_LENGTH = 64; const collectionName = 'A'.repeat(MAX_NAME_LENGTH + 1); @@ -222,45 +197,77 @@ describe('(!negative tests!) Create RFT collection from EVM', () => { .call({value: Number(2n * nominal)})).to.be.rejectedWith('token_prefix is too long. Max length is ' + MAX_TOKEN_PREFIX_LENGTH); } }); - + itEth('(!negative test!) Create collection (no funds)', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const collectionHelper = helper.ethNativeContract.collectionHelpers(owner); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); await expect(collectionHelper.methods .createRFTCollection('Peasantry', 'absolutely anything', 'TWIW') .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); }); - itEth('(!negative test!) Check owner', async ({helper}) => { + // Soft-deprecated + itEth('(!negative test!) [eth] Check owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const peasant = helper.eth.createAccount(); const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE'); - const peasantCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', peasant); + const peasantCollection = await helper.ethNativeContract.collection(collectionAddress, 'rft', peasant, true); const EXPECTED_ERROR = 'NoPermission'; { const sponsor = await helper.eth.createAccountWithBalance(donor); await expect(peasantCollection.methods .setCollectionSponsor(sponsor) .call()).to.be.rejectedWith(EXPECTED_ERROR); - - const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor); + + const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true); await expect(sponsorCollection.methods .confirmCollectionSponsorship() - .call()).to.be.rejectedWith('caller is not set as sponsor'); + .call()).to.be.rejectedWith('ConfirmSponsorshipFail'); } { await expect(peasantCollection.methods - .setCollectionLimit('account_token_ownership_limit', '1000') + .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}) .call()).to.be.rejectedWith(EXPECTED_ERROR); } }); - itEth('(!negative test!) Set limits', async ({helper}) => { + itEth('(!negative test!) [cross] Check owner', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'ISNI'); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); - await expect(collectionEvm.methods - .setCollectionLimit('badLimit', 'true') - .call()).to.be.rejectedWith('unknown boolean limit "badLimit"'); + const peasant = helper.eth.createAccount(); + const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Transgressed', 'absolutely anything', 'YVNE'); + const peasantCollection = await helper.ethNativeContract.collection(collectionAddress, 'rft', peasant); + const EXPECTED_ERROR = 'NoPermission'; + { + const sponsor = await helper.eth.createAccountWithBalance(donor); + const sponsorCross = helper.ethCrossAccount.fromAddress(sponsor); + await expect(peasantCollection.methods + .setCollectionSponsorCross(sponsorCross) + .call()).to.be.rejectedWith(EXPECTED_ERROR); + + const sponsorCollection = await helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor); + await expect(sponsorCollection.methods + .confirmCollectionSponsorship() + .call()).to.be.rejectedWith('ConfirmSponsorshipFail'); + } + { + await expect(peasantCollection.methods + .setCollectionLimit({field: CollectionLimitField.AccountTokenOwnership, value: {status: true, value: 1000}}) + .call()).to.be.rejectedWith(EXPECTED_ERROR); + } + }); + + itEth('destroyCollection', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionAddress, collectionId} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF'); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + + await expect(collectionHelper.methods + .destroyCollection(collectionAddress) + .send({from: owner})).to.be.fulfilled; + + expect(await collectionHelper.methods + .isCollectionExist(collectionAddress) + .call()).to.be.false; + expect(await helper.collection.getData(collectionId)).to.be.null; }); }); diff --git a/tests/src/eth/crossTransfer.test.ts b/tests/src/eth/crossTransfer.test.ts index e515db5752..8486b524ba 100644 --- a/tests/src/eth/crossTransfer.test.ts +++ b/tests/src/eth/crossTransfer.test.ts @@ -30,8 +30,8 @@ describe('Token transfer between substrate address and EVM address. Fungible', ( [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor); }); }); - - itEth('The private key X create a substrate address. Alice sends a token to the corresponding EVM address, and X can send it to Bob in the substrate', async ({helper}) => { + + itEth('The private key X create a substrate address. Alice sends a token to the corresponding EVM address, and X can send it to Bob in the substrate', async ({helper}) => { const bobCA = CrossAccountId.fromKeyring(bob); const charlieCA = CrossAccountId.fromKeyring(charlie); @@ -52,7 +52,7 @@ describe('Token transfer between substrate address and EVM address. Fungible', ( await collection.setLimits(alice, {ownerCanTransfer: true}); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'ft', aliceProxy); + const contract = await helper.ethNativeContract.collection(address, 'ft', aliceProxy); await collection.mint(alice, 200n, {Ethereum: aliceProxy}); await contract.methods.transfer(bobProxy, 50).send({from: aliceProxy}); @@ -73,10 +73,10 @@ describe('Token transfer between substrate address and EVM address. NFT', () => [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor); }); }); - + itEth('The private key X create a substrate address. Alice sends a token to the corresponding EVM address, and X can send it to Bob in the substrate', async ({helper}) => { const charlieEth = CrossAccountId.fromKeyring(charlie, 'Ethereum'); - + const collection = await helper.nft.mintCollection(alice); await collection.setLimits(alice, {ownerCanTransfer: true}); const token = await collection.mintToken(alice); @@ -93,7 +93,7 @@ describe('Token transfer between substrate address and EVM address. NFT', () => await collection.setLimits(alice, {ownerCanTransfer: true}); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'nft', aliceProxy); + const contract = await helper.ethNativeContract.collection(address, 'nft', aliceProxy); const token = await collection.mintToken(alice); await token.transfer(alice, {Ethereum: aliceProxy}); diff --git a/tests/src/eth/destroyCollection.test.ts b/tests/src/eth/destroyCollection.test.ts new file mode 100644 index 0000000000..d762ddb3e7 --- /dev/null +++ b/tests/src/eth/destroyCollection.test.ts @@ -0,0 +1,62 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {IKeyringPair} from '@polkadot/types/types'; +import {Pallets} from '../util'; +import {expect, itEth, usingEthPlaygrounds} from './util'; + +describe('Destroy Collection from EVM', function() { + let donor: IKeyringPair; + const testCases = [ + {case: 'rft' as const, params: ['Limits', 'absolutely anything', 'OLF'], requiredPallets: [Pallets.ReFungible]}, + {case: 'nft' as const, params: ['Limits', 'absolutely anything', 'OLF'], requiredPallets: [Pallets.NFT]}, + {case: 'ft' as const, params: ['Limits', 'absolutely anything', 'OLF', 18], requiredPallets: [Pallets.Fungible]}, + ]; + + before(async function() { + await usingEthPlaygrounds(async (_, privateKey) => { + donor = await privateKey({filename: __filename}); + }); + }); + + testCases.map((testCase) => + itEth.ifWithPallets(`Cannot burn non-owned or non-existing collection ${testCase.case}`, testCase.requiredPallets, async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const signer = await helper.eth.createAccountWithBalance(donor); + + const unexistedCollection = helper.ethAddress.fromCollectionId(1000000); + + const collectionHelpers = await helper.ethNativeContract.collectionHelpers(signer); + const {collectionAddress} = await helper.eth.createCollection(testCase.case, owner, ...testCase.params as [string, string, string, number?]); + + // cannot burn collec + await expect(collectionHelpers.methods + .destroyCollection(collectionAddress) + .send({from: signer})).to.be.rejected; + + await expect(collectionHelpers.methods + .destroyCollection(unexistedCollection) + .send({from: signer})).to.be.rejected; + + expect(await collectionHelpers.methods + .isCollectionExist(unexistedCollection) + .call()).to.be.false; + + expect(await collectionHelpers.methods + .isCollectionExist(collectionAddress) + .call()).to.be.true; + })); +}); diff --git a/tests/src/eth/ethFeesAreCorrect.test.ts b/tests/src/eth/ethFeesAreCorrect.test.ts new file mode 100644 index 0000000000..8daff36328 --- /dev/null +++ b/tests/src/eth/ethFeesAreCorrect.test.ts @@ -0,0 +1,66 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {IKeyringPair} from '@polkadot/types/types'; +import {itEth, usingEthPlaygrounds, expect} from './util'; + +describe('Eth fees are correct', () => { + let donor: IKeyringPair; + let minter: IKeyringPair; + let alice: IKeyringPair; + + before(async () => { + await usingEthPlaygrounds(async (helper, privateKey) => { + donor = await privateKey({filename: __filename}); + [minter, alice] = await helper.arrange.createAccounts([100n, 200n], donor); + }); + }); + + + itEth('web3 fees are the same as evm.call fees', async ({helper}) => { + const collection = await helper.nft.mintCollection(minter, {}); + + const owner = await helper.eth.createAccountWithBalance(donor); + const receiver = await helper.eth.createAccountWithBalance(donor); + const aliceEth = helper.address.substrateToEth(alice.address); + + const {tokenId: tokenA} = await collection.mintToken(minter, {Ethereum: owner}); + const {tokenId: tokenB} = await collection.mintToken(minter, {Ethereum: aliceEth}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + + const balanceBeforeWeb3Transfer = await helper.balance.getEthereum(owner); + await contract.methods.transfer(receiver, tokenA).send({from: owner}); + const balanceAfterWeb3Transfer = await helper.balance.getEthereum(owner); + const web3Diff = balanceBeforeWeb3Transfer - balanceAfterWeb3Transfer; + + const encodedCall = contract.methods.transfer(receiver, tokenB) + .encodeABI(); + + const balanceBeforeEvmCall = await helper.balance.getSubstrate(alice.address); + await helper.eth.sendEVM( + alice, + collectionAddress, + encodedCall, + '0', + ); + const balanceAfterEvmCall = await helper.balance.getSubstrate(alice.address); + const evmCallDiff = balanceBeforeEvmCall - balanceAfterEvmCall; + + expect(web3Diff).to.be.equal(evmCallDiff); + }); +}); diff --git a/tests/src/eth/events.test.ts b/tests/src/eth/events.test.ts new file mode 100644 index 0000000000..a163f92d7c --- /dev/null +++ b/tests/src/eth/events.test.ts @@ -0,0 +1,553 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {expect} from 'chai'; +import {IKeyringPair} from '@polkadot/types/types'; +import {EthUniqueHelper, itEth, usingEthPlaygrounds} from './util'; +import {IEvent, TCollectionMode} from '../util/playgrounds/types'; +import {Pallets, requirePalletsOrSkip} from '../util'; +import {CollectionLimitField, TokenPermissionField, NormalizedEvent} from './util/playgrounds/types'; + +let donor: IKeyringPair; + +before(async function () { + await usingEthPlaygrounds(async (_helper, privateKey) => { + donor = await privateKey({filename: __filename}); + }); +}); + +function clearEvents(ethEvents: NormalizedEvent[], subEvents: IEvent[]) { + ethEvents.splice(0); + subEvents.splice(0); +} + +async function testCollectionCreatedAndDestroy(helper: EthUniqueHelper, mode: TCollectionMode) { + const owner = await helper.eth.createAccountWithBalance(donor); + const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionCreated', 'CollectionDestroyed']}]); + const {collectionAddress, events: ethEvents} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C'); + await helper.wait.newBlocks(1); + { + expect(ethEvents).to.containSubset([ + { + event: 'CollectionCreated', + args: { + owner: owner, + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'CollectionCreated'}]); + clearEvents(ethEvents, subEvents); + } + { + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + const result = await collectionHelper.methods.destroyCollection(collectionAddress).send({from:owner}); + await helper.wait.newBlocks(1); + expect(result.events).to.containSubset({ + CollectionDestroyed: { + returnValues: { + collectionId: collectionAddress, + }, + }, + }); + expect(subEvents).to.containSubset([{method: 'CollectionDestroyed'}]); + } + unsubscribe(); +} + +async function testCollectionPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) { + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + + const ethEvents: any = []; + collectionHelper.events.allEvents((_: any, event: any) => { + ethEvents.push(event); + }); + const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionPropertySet', 'CollectionPropertyDeleted']}]); + { + await collection.methods.setCollectionProperties([{key: 'A', value: [0,1,2,3]}]).send({from:owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'CollectionPropertySet'}]); + clearEvents(ethEvents, subEvents); + } + { + await collection.methods.deleteCollectionProperties(['A']).send({from:owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'CollectionPropertyDeleted'}]); + } + unsubscribe(); +} + +async function testPropertyPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) { + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + const ethEvents: any = []; + collectionHelper.events.allEvents((_: any, event: any) => { + ethEvents.push(event); + }); + const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['PropertyPermissionSet']}]); + await collection.methods.setTokenPropertyPermissions([ + ['A', [ + [TokenPermissionField.Mutable, true], + [TokenPermissionField.TokenOwner, true], + [TokenPermissionField.CollectionAdmin, true]], + ], + ]).send({from: owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'PropertyPermissionSet'}]); + unsubscribe(); +} + +async function testAllowListAddressAddedAndRemoved(helper: EthUniqueHelper, mode: TCollectionMode) { + const owner = await helper.eth.createAccountWithBalance(donor); + const user = helper.ethCrossAccount.createAccount(); + const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + const ethEvents: any[] = []; + collectionHelper.events.allEvents((_: any, event: any) => { + ethEvents.push(event); + }); + + const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['AllowListAddressAdded', 'AllowListAddressRemoved']}]); + { + await collection.methods.addToCollectionAllowListCross(user).send({from: owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'AllowListAddressAdded'}]); + clearEvents(ethEvents, subEvents); + } + { + await collection.methods.removeFromCollectionAllowListCross(user).send({from: owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'AllowListAddressRemoved'}]); + } + unsubscribe(); +} + +async function testCollectionAdminAddedAndRemoved(helper: EthUniqueHelper, mode: TCollectionMode) { + const owner = await helper.eth.createAccountWithBalance(donor); + const user = helper.ethCrossAccount.createAccount(); + const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + const ethEvents: any = []; + collectionHelper.events.allEvents((_: any, event: any) => { + ethEvents.push(event); + }); + const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionAdminAdded', 'CollectionAdminRemoved']}]); + { + await collection.methods.addCollectionAdminCross(user).send({from: owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'CollectionAdminAdded'}]); + clearEvents(ethEvents, subEvents); + } + { + await collection.methods.removeCollectionAdminCross(user).send({from: owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'CollectionAdminRemoved'}]); + } + unsubscribe(); +} + +async function testCollectionLimitSet(helper: EthUniqueHelper, mode: TCollectionMode) { + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + const ethEvents: any = []; + collectionHelper.events.allEvents((_: any, event: any) => { + ethEvents.push(event); + }); + const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionLimitSet']}]); + { + await collection.methods.setCollectionLimit({field: CollectionLimitField.OwnerCanTransfer, value: {status: true, value: 0}}).send({from: owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'CollectionLimitSet'}]); + } + unsubscribe(); +} + +async function testCollectionOwnerChanged(helper: EthUniqueHelper, mode: TCollectionMode) { + const owner = await helper.eth.createAccountWithBalance(donor); + const newOwner = helper.ethCrossAccount.createAccount(); + const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + const ethEvents: any = []; + collectionHelper.events.allEvents((_: any, event: any) => { + ethEvents.push(event); + }); + const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionOwnerChanged']}]); + { + await collection.methods.changeCollectionOwnerCross(newOwner).send({from: owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'CollectionOwnerChanged'}]); + } + unsubscribe(); +} + +async function testCollectionPermissionSet(helper: EthUniqueHelper, mode: TCollectionMode) { + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + const ethEvents: any = []; + collectionHelper.events.allEvents((_: any, event: any) => { + ethEvents.push(event); + }); + const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionPermissionSet']}]); + { + await collection.methods.setCollectionMintMode(true).send({from: owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'CollectionPermissionSet'}]); + clearEvents(ethEvents, subEvents); + } + { + await collection.methods.setCollectionAccess(1).send({from: owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'CollectionPermissionSet'}]); + } + unsubscribe(); +} + +async function testCollectionSponsorSetAndConfirmedAndThenRemoved(helper: EthUniqueHelper, mode: TCollectionMode) { + const owner = await helper.eth.createAccountWithBalance(donor); + const sponsor = await helper.ethCrossAccount.createAccountWithBalance(donor); + const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + const ethEvents: any = []; + collectionHelper.events.allEvents((_: any, event: any) => { + ethEvents.push(event); + }); + const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{ + section: 'common', names: ['CollectionSponsorSet', 'SponsorshipConfirmed', 'CollectionSponsorRemoved', + ]}]); + { + await collection.methods.setCollectionSponsorCross(sponsor).send({from: owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([{ + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }]); + expect(subEvents).to.containSubset([{method: 'CollectionSponsorSet'}]); + clearEvents(ethEvents, subEvents); + } + { + await collection.methods.confirmCollectionSponsorship().send({from: sponsor.eth}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'SponsorshipConfirmed'}]); + clearEvents(ethEvents, subEvents); + } + { + await collection.methods.removeCollectionSponsor().send({from: owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'CollectionChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'CollectionSponsorRemoved'}]); + } + unsubscribe(); +} + +async function testTokenPropertySetAndDeleted(helper: EthUniqueHelper, mode: TCollectionMode) { + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionAddress} = await helper.eth.createCollection(mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, mode, owner); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(owner); + const result = await collection.methods.mint(owner).send({from: owner}); + const tokenId = result.events.Transfer.returnValues.tokenId; + await collection.methods.setTokenPropertyPermissions([ + ['A', [ + [TokenPermissionField.Mutable, true], + [TokenPermissionField.TokenOwner, true], + [TokenPermissionField.CollectionAdmin, true]], + ], + ]).send({from: owner}); + + + const ethEvents: any = []; + collectionHelper.events.allEvents((_: any, event: any) => { + ethEvents.push(event); + }); + const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['TokenPropertySet', 'TokenPropertyDeleted']}]); + { + await collection.methods.setProperties(tokenId, [{key: 'A', value: [1,2,3]}]).send({from: owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'TokenChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'TokenPropertySet'}]); + clearEvents(ethEvents, subEvents); + } + { + await collection.methods.deleteProperties(tokenId, ['A']).send({from: owner}); + await helper.wait.newBlocks(1); + expect(ethEvents).to.containSubset([ + { + event: 'TokenChanged', + returnValues: { + collectionId: collectionAddress, + }, + }, + ]); + expect(subEvents).to.containSubset([{method: 'TokenPropertyDeleted'}]); + } + unsubscribe(); +} + +describe('[FT] Sync sub & eth events', () => { + const mode: TCollectionMode = 'ft'; + + itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => { + await testCollectionCreatedAndDestroy(helper, mode); + }); + + itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => { + await testCollectionPropertySetAndDeleted(helper, mode); + }); + + itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => { + await testAllowListAddressAddedAndRemoved(helper, mode); + }); + + itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => { + await testCollectionAdminAddedAndRemoved(helper, mode); + }); + + itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => { + await testCollectionLimitSet(helper, mode); + }); + + itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => { + await testCollectionOwnerChanged(helper, mode); + }); + + itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => { + await testCollectionPermissionSet(helper, mode); + }); + + itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => { + await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode); + }); +}); + +describe('[NFT] Sync sub & eth events', () => { + const mode: TCollectionMode = 'nft'; + + itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => { + await testCollectionCreatedAndDestroy(helper, mode); + }); + + itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => { + await testCollectionPropertySetAndDeleted(helper, mode); + }); + + itEth('CollectionChanged event for PropertyPermissionSet', async ({helper}) => { + await testPropertyPermissionSet(helper, mode); + }); + + itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => { + await testAllowListAddressAddedAndRemoved(helper, mode); + }); + + itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => { + await testCollectionAdminAddedAndRemoved(helper, mode); + }); + + itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => { + await testCollectionLimitSet(helper, mode); + }); + + itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => { + await testCollectionOwnerChanged(helper, mode); + }); + + itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => { + await testCollectionPermissionSet(helper, mode); + }); + + itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => { + await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode); + }); + + itEth('CollectionChanged event for TokenPropertySet, TokenPropertyDeleted', async ({helper}) => { + await testTokenPropertySetAndDeleted(helper, mode); + }); +}); + +describe('[RFT] Sync sub & eth events', () => { + const mode: TCollectionMode = 'rft'; + + before(async function() { + await usingEthPlaygrounds(async (helper, privateKey) => { + requirePalletsOrSkip(this, helper, [Pallets.ReFungible]); + const _donor = await privateKey({filename: __filename}); + }); + }); + + itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => { + await testCollectionCreatedAndDestroy(helper, mode); + }); + + itEth('CollectionChanged event for CollectionPropertySet and CollectionPropertyDeleted', async ({helper}) => { + await testCollectionPropertySetAndDeleted(helper, mode); + }); + + itEth('CollectionChanged event for PropertyPermissionSet', async ({helper}) => { + await testPropertyPermissionSet(helper, mode); + }); + + itEth('CollectionChanged event for AllowListAddressAdded, AllowListAddressRemoved', async ({helper}) => { + await testAllowListAddressAddedAndRemoved(helper, mode); + }); + + itEth('CollectionChanged event for CollectionAdminAdded, CollectionAdminRemoved', async ({helper}) => { + await testCollectionAdminAddedAndRemoved(helper, mode); + }); + + itEth('CollectionChanged event for CollectionLimitSet', async ({helper}) => { + await testCollectionLimitSet(helper, mode); + }); + + itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => { + await testCollectionOwnerChanged(helper, mode); + }); + + itEth('CollectionChanged event for CollectionPermissionSet', async ({helper}) => { + await testCollectionPermissionSet(helper, mode); + }); + + itEth('CollectionChanged event for CollectionSponsorSet, SponsorshipConfirmed, CollectionSponsorRemoved', async ({helper}) => { + await testCollectionSponsorSetAndConfirmedAndThenRemoved(helper, mode); + }); + + itEth('CollectionChanged event for TokenPropertySet, TokenPropertyDeleted', async ({helper}) => { + await testTokenPropertySetAndDeleted(helper, mode); + }); +}); diff --git a/tests/src/eth/evmCoder.test.ts b/tests/src/eth/evmCoder.test.ts index 24cdf6baf7..19ed44b80f 100644 --- a/tests/src/eth/evmCoder.test.ts +++ b/tests/src/eth/evmCoder.test.ts @@ -62,7 +62,7 @@ describe('Evm Coder tests', () => { donor = await privateKey({filename: __filename}); }); }); - + itEth('Call non-existing function', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const collection = await helper.eth.createNFTCollection(owner, 'EVMCODER', '', 'TEST'); diff --git a/tests/src/eth/fractionalizer/Fractionalizer.sol b/tests/src/eth/fractionalizer/Fractionalizer.sol index bc40e4219a..d93c903ae2 100644 --- a/tests/src/eth/fractionalizer/Fractionalizer.sol +++ b/tests/src/eth/fractionalizer/Fractionalizer.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.0; import {CollectionHelpers} from "../api/CollectionHelpers.sol"; import {ContractHelpers} from "../api/ContractHelpers.sol"; import {UniqueRefungibleToken} from "../api/UniqueRefungibleToken.sol"; -import {UniqueRefungible} from "../api/UniqueRefungible.sol"; +import {UniqueRefungible, CrossAddress} from "../api/UniqueRefungible.sol"; import {UniqueNFT} from "../api/UniqueNFT.sol"; /// @dev Fractionalization contract. It stores mappings between NFT and RFT tokens, @@ -63,7 +63,7 @@ contract Fractionalizer { "Wrong collection type. Collection is not refungible." ); require( - refungibleContract.isOwnerOrAdmin(address(this)), + refungibleContract.isOwnerOrAdminCross(CrossAddress({eth: address(this), sub: uint256(0)})), "Fractionalizer contract should be an admin of the collection" ); rftCollection = _collection; @@ -84,7 +84,11 @@ contract Fractionalizer { ) external payable onlyOwner { require(rftCollection == address(0), "RFT collection is already set"); address collectionHelpers = 0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F; - rftCollection = CollectionHelpers(collectionHelpers).createRFTCollection{value: msg.value}(_name, _description, _tokenPrefix); + rftCollection = CollectionHelpers(collectionHelpers).createRFTCollection{value: msg.value}( + _name, + _description, + _tokenPrefix + ); emit RFTCollectionSet(rftCollection); } @@ -124,7 +128,7 @@ contract Fractionalizer { address rftTokenAddress; UniqueRefungibleToken rftTokenContract; if (nft2rftMapping[_collection][_token] == 0) { - rftTokenId = rftCollectionContract.mint(address(this)); + rftTokenId = rftCollectionContract.mint(address(this)); rftTokenAddress = rftCollectionContract.tokenContractAddress(rftTokenId); nft2rftMapping[_collection][_token] = rftTokenId; rft2nftMapping[rftTokenAddress] = Token(_collection, _token); diff --git a/tests/src/eth/fractionalizer/fractionalizer.test.ts b/tests/src/eth/fractionalizer/fractionalizer.test.ts index 13186564cf..503aba4300 100644 --- a/tests/src/eth/fractionalizer/fractionalizer.test.ts +++ b/tests/src/eth/fractionalizer/fractionalizer.test.ts @@ -63,7 +63,7 @@ const mintRFTToken = async (helper: EthUniqueHelper, owner: string, fractionaliz nftCollectionAddress: string, nftTokenId: number, rftTokenAddress: string }> => { const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); - const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); + const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const mintResult = await nftContract.methods.mint(owner).send({from: owner}); const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; @@ -93,9 +93,10 @@ describe('Fractionalizer contract usage', () => { const owner = await helper.eth.createAccountWithBalance(donor, 10n); const fractionalizer = await deployContract(helper, owner); const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT'); - const rftContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); + const rftContract = await helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); - await rftContract.methods.addCollectionAdmin(fractionalizer.options.address).send({from: owner}); + const fractionalizerAddressCross = helper.ethCrossAccount.fromAddress(fractionalizer.options.address); + await rftContract.methods.addCollectionAdminCross(fractionalizerAddressCross).send({from: owner}); const result = await fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).send({from: owner}); expect(result.events).to.be.like({ RFTCollectionSet: { @@ -147,7 +148,7 @@ describe('Fractionalizer contract usage', () => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); - const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); + const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const mintResult = await nftContract.methods.mint(owner).send({from: owner}); const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; @@ -167,7 +168,7 @@ describe('Fractionalizer contract usage', () => { }); const rftTokenAddress = result.events.Fractionalized.returnValues._rftToken; - const rftTokenContract = helper.ethNativeContract.rftToken(rftTokenAddress); + const rftTokenContract = await helper.ethNativeContract.rftToken(rftTokenAddress); expect(await rftTokenContract.methods.balanceOf(owner).call()).to.equal('100'); }); @@ -180,7 +181,7 @@ describe('Fractionalizer contract usage', () => { const {collectionId, tokenId} = helper.ethAddress.extractTokenId(rftTokenAddress); const refungibleAddress = helper.ethAddress.fromCollectionId(collectionId); expect(rftCollectionAddress).to.be.equal(refungibleAddress); - const refungibleTokenContract = helper.ethNativeContract.rftToken(rftTokenAddress, owner); + const refungibleTokenContract = await helper.ethNativeContract.rftToken(rftTokenAddress, owner); await refungibleTokenContract.methods.approve(fractionalizer.options.address, 100).send({from: owner}); const result = await fractionalizer.methods.rft2nft(refungibleAddress, tokenId).send({from: owner}); expect(result.events).to.be.like({ @@ -203,7 +204,7 @@ describe('Fractionalizer contract usage', () => { const {collectionId, tokenId} = helper.ethAddress.extractTokenId(rftTokenAddress); const refungibleAddress = helper.ethAddress.fromCollectionId(collectionId); expect(rftCollectionAddress).to.be.equal(refungibleAddress); - const refungibleTokenContract = helper.ethNativeContract.rftToken(rftTokenAddress, owner); + const refungibleTokenContract = await helper.ethNativeContract.rftToken(rftTokenAddress, owner); await refungibleTokenContract.methods.approve(fractionalizer.options.address, 100).send({from: owner}); const rft2nft = await fractionalizer.methods.rft2nftMapping(rftTokenAddress).call(); @@ -232,10 +233,11 @@ describe('Negative Integration Tests for fractionalizer', () => { itEth('call setRFTCollection twice', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT'); - const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); + const refungibleContract = await helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); const fractionalizer = await deployContract(helper, owner); - await refungibleContract.methods.addCollectionAdmin(fractionalizer.options.address).send({from: owner}); + const fractionalizerAddressCross = helper.ethCrossAccount.fromAddress(fractionalizer.options.address); + await refungibleContract.methods.addCollectionAdminCross(fractionalizerAddressCross).send({from: owner}); await fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).send({from: owner}); await expect(fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).call()) @@ -245,10 +247,11 @@ describe('Negative Integration Tests for fractionalizer', () => { itEth('call setRFTCollection with NFT collection', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); - const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); + const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const fractionalizer = await deployContract(helper, owner); - await nftContract.methods.addCollectionAdmin(fractionalizer.options.address).send({from: owner}); + const fractionalizerAddressCross = helper.ethCrossAccount.fromAddress(fractionalizer.options.address); + await nftContract.methods.addCollectionAdminCross(fractionalizerAddressCross).send({from: owner}); await expect(fractionalizer.methods.setRFTCollection(nftCollection.collectionAddress).call()) .to.be.rejectedWith(/Wrong collection type. Collection is not refungible.$/g); @@ -279,7 +282,7 @@ describe('Negative Integration Tests for fractionalizer', () => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); - const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); + const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const mintResult = await nftContract.methods.mint(owner).send({from: owner}); const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; @@ -294,7 +297,7 @@ describe('Negative Integration Tests for fractionalizer', () => { const nftOwner = await helper.eth.createAccountWithBalance(donor, 10n); const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); - const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); + const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const mintResult = await nftContract.methods.mint(owner).send({from: owner}); const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; await nftContract.methods.transfer(nftOwner, 1).send({from: owner}); @@ -311,7 +314,7 @@ describe('Negative Integration Tests for fractionalizer', () => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); - const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); + const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const mintResult = await nftContract.methods.mint(owner).send({from: owner}); const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; @@ -326,7 +329,7 @@ describe('Negative Integration Tests for fractionalizer', () => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); - const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); + const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const mintResult = await nftContract.methods.mint(owner).send({from: owner}); const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; @@ -342,7 +345,7 @@ describe('Negative Integration Tests for fractionalizer', () => { const fractionalizer = await deployContract(helper, owner); const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT'); - const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); + const refungibleContract = await helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); const mintResult = await refungibleContract.methods.mint(owner).send({from: owner}); const rftTokenId = mintResult.events.Transfer.returnValues.tokenId; @@ -355,7 +358,7 @@ describe('Negative Integration Tests for fractionalizer', () => { const {contract: fractionalizer} = await initContract(helper, owner); const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT'); - const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); + const refungibleContract = await helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); const mintResult = await refungibleContract.methods.mint(owner).send({from: owner}); const rftTokenId = mintResult.events.Transfer.returnValues.tokenId; @@ -366,11 +369,12 @@ describe('Negative Integration Tests for fractionalizer', () => { itEth('call rft2nft for RFT token that was not minted by fractionalizer contract', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor, 20n); const rftCollection = await helper.eth.createRFTCollection(owner, 'rft', 'RFT collection', 'RFT'); - const refungibleContract = helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); + const refungibleContract = await helper.ethNativeContract.collection(rftCollection.collectionAddress, 'rft', owner); const fractionalizer = await deployContract(helper, owner); - await refungibleContract.methods.addCollectionAdmin(fractionalizer.options.address).send({from: owner}); + const fractionalizerAddressCross = helper.ethCrossAccount.fromAddress(fractionalizer.options.address); + await refungibleContract.methods.addCollectionAdminCross(fractionalizerAddressCross).send({from: owner}); await fractionalizer.methods.setRFTCollection(rftCollection.collectionAddress).send({from: owner}); const mintResult = await refungibleContract.methods.mint(owner).send({from: owner}); @@ -388,7 +392,7 @@ describe('Negative Integration Tests for fractionalizer', () => { const {rftTokenAddress} = await mintRFTToken(helper, owner, fractionalizer, 100n); const {tokenId} = helper.ethAddress.extractTokenId(rftTokenAddress); - const refungibleTokenContract = helper.ethNativeContract.rftToken(rftTokenAddress, owner); + const refungibleTokenContract = await helper.ethNativeContract.rftToken(rftTokenAddress, owner); await refungibleTokenContract.methods.transfer(receiver, 50).send({from: owner}); await refungibleTokenContract.methods.approve(fractionalizer.options.address, 50).send({from: receiver}); await expect(fractionalizer.methods.rft2nft(rftCollectionAddress, tokenId).call({from: receiver})) @@ -415,7 +419,7 @@ describe('Negative Integration Tests for fractionalizer', () => { const {contract: fractionalizer} = await initContract(helper, owner); await fractionalizer.methods.setNftCollectionIsAllowed(nftCollectionAddress, true).send({from: owner}); - const nftContract = helper.ethNativeContract.collection(nftCollectionAddress, 'nft', owner); + const nftContract = await helper.ethNativeContract.collection(nftCollectionAddress, 'nft', owner); await nftContract.methods.approve(fractionalizer.options.address, nftToken.tokenId).send({from: owner}); await expect(fractionalizer.methods.nft2rft(nftCollectionAddress, nftToken.tokenId, 100).call()) .to.be.rejectedWith(/TransferNotAllowed$/g); @@ -433,7 +437,7 @@ describe('Negative Integration Tests for fractionalizer', () => { await helper.executeExtrinsic(donor, 'api.tx.unique.setTransfersEnabledFlag', [rftCollection.collectionId, false], true); const nftCollection = await helper.eth.createNFTCollection(owner, 'nft', 'NFT collection', 'NFT'); - const nftContract = helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); + const nftContract = await helper.ethNativeContract.collection(nftCollection.collectionAddress, 'nft', owner); const mintResult = await nftContract.methods.mint(owner).send({from: owner}); const nftTokenId = mintResult.events.Transfer.returnValues.tokenId; diff --git a/tests/src/eth/fungible.test.ts b/tests/src/eth/fungible.test.ts index babed8e16b..6c2ecf94ff 100644 --- a/tests/src/eth/fungible.test.ts +++ b/tests/src/eth/fungible.test.ts @@ -33,7 +33,7 @@ describe('Fungible: Information getting', () => { const collection = await helper.ft.mintCollection(alice); await collection.mint(alice, 200n); - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller); + const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller); const totalSupply = await contract.methods.totalSupply().call(); expect(totalSupply).to.equal('200'); }); @@ -43,7 +43,7 @@ describe('Fungible: Information getting', () => { const collection = await helper.ft.mintCollection(alice); await collection.mint(alice, 200n, {Ethereum: caller}); - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller); + const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'ft', caller); const balance = await contract.methods.balanceOf(caller).call(); expect(balance).to.equal('200'); }); @@ -52,11 +52,12 @@ describe('Fungible: Information getting', () => { describe('Fungible: Plain calls', () => { let donor: IKeyringPair; let alice: IKeyringPair; + let owner: IKeyringPair; before(async function() { await usingEthPlaygrounds(async (helper, privateKey) => { donor = await privateKey({filename: __filename}); - [alice] = await helper.arrange.createAccounts([20n], donor); + [alice, owner] = await helper.arrange.createAccounts([30n, 20n], donor); }); }); @@ -67,10 +68,10 @@ describe('Fungible: Plain calls', () => { await collection.addAdmin(alice, {Ethereum: owner}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner); const result = await contract.methods.mint(receiver, 100).send(); - + const event = result.events.Transfer; expect(event.address).to.equal(collectionAddress); expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000'); @@ -78,6 +79,42 @@ describe('Fungible: Plain calls', () => { expect(event.returnValues.value).to.equal('100'); }); + [ + 'substrate' as const, + 'ethereum' as const, + ].map(testCase => { + itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => { + // 1. Create receiver depending on the test case: + const receiverEth = helper.eth.createAccount(); + const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth); + const receiverSub = owner; + const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(owner); + + const ethOwner = await helper.eth.createAccountWithBalance(donor); + const collection = await helper.ft.mintCollection(alice); + await collection.addAdmin(alice, {Ethereum: ethOwner}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', ethOwner); + + // 2. Mint tokens: + const result = await collectionEvm.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, 100).send(); + + const event = result.events.Transfer; + expect(event.address).to.equal(collectionAddress); + expect(event.returnValues.from).to.equal('0x0000000000000000000000000000000000000000'); + expect(event.returnValues.to).to.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(receiverSub.address)); + expect(event.returnValues.value).to.equal('100'); + + // 3. Get balance depending on the test case: + let balance; + if (testCase === 'ethereum') balance = await collection.getBalance({Ethereum: receiverEth}); + else if (testCase === 'substrate') balance = await collection.getBalance({Substrate: receiverSub.address}); + // 3.1 Check balance: + expect(balance).to.eq(100n); + }); + }); + itEth('Can perform mintBulk()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const bulkSize = 3; @@ -86,7 +123,7 @@ describe('Fungible: Plain calls', () => { await collection.addAdmin(alice, {Ethereum: owner}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner); const result = await contract.methods.mintBulk(Array.from({length: bulkSize}, (_, i) => ( [receivers[i], (i + 1) * 10] @@ -101,6 +138,7 @@ describe('Fungible: Plain calls', () => { } }); + // Soft-deprecated itEth('Can perform burn()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const receiver = await helper.eth.createAccountWithBalance(donor); @@ -108,11 +146,11 @@ describe('Fungible: Plain calls', () => { await collection.addAdmin(alice, {Ethereum: owner}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner, true); await contract.methods.mint(receiver, 100).send(); const result = await contract.methods.burnFrom(receiver, 49).send({from: receiver}); - + const event = result.events.Transfer; expect(event.address).to.equal(collectionAddress); expect(event.returnValues.from).to.equal(receiver); @@ -130,7 +168,7 @@ describe('Fungible: Plain calls', () => { await collection.mint(alice, 200n, {Ethereum: owner}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner); { const result = await contract.methods.approve(spender, 100).send({from: owner}); @@ -148,6 +186,110 @@ describe('Fungible: Plain calls', () => { } }); + itEth('Can perform approveCross()', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const spender = helper.eth.createAccount(); + const spenderSub = (await helper.arrange.createAccounts([1n], donor))[0]; + const spenderCrossEth = helper.ethCrossAccount.fromAddress(spender); + const spenderCrossSub = helper.ethCrossAccount.fromKeyringPair(spenderSub); + + + const collection = await helper.ft.mintCollection(alice); + await collection.mint(alice, 200n, {Ethereum: owner}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner); + + { + const result = await contract.methods.approveCross(spenderCrossEth, 100).send({from: owner}); + const event = result.events.Approval; + expect(event.address).to.be.equal(collectionAddress); + expect(event.returnValues.owner).to.be.equal(owner); + expect(event.returnValues.spender).to.be.equal(spender); + expect(event.returnValues.value).to.be.equal('100'); + } + + { + const allowance = await contract.methods.allowance(owner, spender).call(); + expect(+allowance).to.equal(100); + } + + + { + const result = await contract.methods.approveCross(spenderCrossSub, 100).send({from: owner}); + const event = result.events.Approval; + expect(event.address).to.be.equal(collectionAddress); + expect(event.returnValues.owner).to.be.equal(owner); + expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(spenderSub.address)); + expect(event.returnValues.value).to.be.equal('100'); + } + + { + const allowance = await collection.getApprovedTokens({Ethereum: owner}, {Substrate: spenderSub.address}); + expect(allowance).to.equal(100n); + } + + { + //TO-DO expect with future allowanceCross(owner, spenderCrossEth).call() + } + }); + + itEth('Non-owner and non admin cannot approveCross', async ({helper}) => { + const nonOwner = await helper.eth.createAccountWithBalance(donor); + const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner); + const owner = await helper.eth.createAccountWithBalance(donor); + const collection = await helper.ft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}); + await collection.mint(alice, 100n, {Ethereum: owner}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner); + + await expect(collectionEvm.methods.approveCross(nonOwnerCross, 20).call({from: nonOwner})).to.be.rejectedWith('CantApproveMoreThanOwned'); + }); + + + itEth('Can perform burnFromCross()', async ({helper}) => { + const sender = await helper.eth.createAccountWithBalance(donor, 100n); + + const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0); + + await collection.mint(owner, 200n, {Substrate: owner.address}); + await collection.approveTokens(owner, {Ethereum: sender}, 100n); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'ft'); + + const fromBalanceBefore = await collection.getBalance({Substrate: owner.address}); + + const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner); + const result = await contract.methods.burnFromCross(ownerCross, 49).send({from: sender}); + const events = result.events; + + expect(events).to.be.like({ + Transfer: { + address: helper.ethAddress.fromCollectionId(collection.collectionId), + event: 'Transfer', + returnValues: { + from: helper.address.substrateToEth(owner.address), + to: '0x0000000000000000000000000000000000000000', + value: '49', + }, + }, + Approval: { + address: helper.ethAddress.fromCollectionId(collection.collectionId), + returnValues: { + owner: helper.address.substrateToEth(owner.address), + spender: sender, + value: '51', + }, + event: 'Approval', + }, + }); + + const fromBalanceAfter = await collection.getBalance({Substrate: owner.address}); + expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(49n); + }); + itEth('Can perform transferFrom()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const spender = await helper.eth.createAccountWithBalance(donor); @@ -156,13 +298,13 @@ describe('Fungible: Plain calls', () => { await collection.mint(alice, 200n, {Ethereum: owner}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner); await contract.methods.approve(spender, 100).send(); { const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender}); - + let event = result.events.Transfer; expect(event.address).to.be.equal(collectionAddress); expect(event.returnValues.from).to.be.equal(owner); @@ -187,25 +329,72 @@ describe('Fungible: Plain calls', () => { } }); - itEth('Cannot transfer incorrect amount', async ({helper}) => { + itEth('Can perform transferCross()', async ({helper}) => { + const sender = await helper.eth.createAccountWithBalance(donor); + const receiverEth = await helper.eth.createAccountWithBalance(donor); + const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth); + const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(donor); + const collection = await helper.ft.mintCollection(alice); + await collection.mint(alice, 200n, {Ethereum: sender}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', sender); + + { + // Can transferCross to ethereum address: + const result = await collectionEvm.methods.transferCross(receiverCrossEth, 50).send({from: sender}); + // Check events: + const event = result.events.Transfer; + expect(event.address).to.be.equal(collectionAddress); + expect(event.returnValues.from).to.be.equal(sender); + expect(event.returnValues.to).to.be.equal(receiverEth); + expect(event.returnValues.value).to.be.equal('50'); + // Sender's balance decreased: + const ownerBalance = await collectionEvm.methods.balanceOf(sender).call(); + expect(+ownerBalance).to.equal(150); + // Receiver's balance increased: + const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call(); + expect(+receiverBalance).to.equal(50); + } + + { + // Can transferCross to substrate address: + const result = await collectionEvm.methods.transferCross(receiverCrossSub, 50).send({from: sender}); + // Check events: + const event = result.events.Transfer; + expect(event.address).to.be.equal(collectionAddress); + expect(event.returnValues.from).to.be.equal(sender); + expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(donor.address)); + expect(event.returnValues.value).to.be.equal('50'); + // Sender's balance decreased: + const senderBalance = await collection.getBalance({Ethereum: sender}); + expect(senderBalance).to.equal(100n); + // Receiver's balance increased: + const balance = await collection.getBalance({Substrate: donor.address}); + expect(balance).to.equal(50n); + } + }); + + ['transfer', 'transferCross'].map(testCase => itEth(`Cannot ${testCase} incorrect amount`, async ({helper}) => { const sender = await helper.eth.createAccountWithBalance(donor); const receiverEth = await helper.eth.createAccountWithBalance(donor); + const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth); const BALANCE = 200n; const BALANCE_TO_TRANSFER = BALANCE + 100n; const collection = await helper.ft.mintCollection(alice); await collection.mint(alice, BALANCE, {Ethereum: sender}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', sender); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'ft', sender); // 1. Cannot transfer more than have - const receiver = receiverEth; - await expect(collectionEvm.methods.transfer(receiver, BALANCE_TO_TRANSFER).send({from: sender})).to.be.rejected; + const receiver = testCase === 'transfer' ? receiverEth : receiverCrossEth; + await expect(collectionEvm.methods[testCase](receiver, BALANCE_TO_TRANSFER).send({from: sender})).to.be.rejected; // 2. Zero transfer allowed (EIP-20): - await collectionEvm.methods.transfer(receiver, 0n).send({from: sender}); - }); - - + await collectionEvm.methods[testCase](receiver, 0n).send({from: sender}); + })); + + itEth('Can perform transfer()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const receiver = await helper.eth.createAccountWithBalance(donor); @@ -213,11 +402,11 @@ describe('Fungible: Plain calls', () => { await collection.mint(alice, 200n, {Ethereum: owner}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner); { const result = await contract.methods.transfer(receiver, 50).send({from: owner}); - + const event = result.events.Transfer; expect(event.address).to.be.equal(collectionAddress); expect(event.returnValues.from).to.be.equal(owner); @@ -235,6 +424,53 @@ describe('Fungible: Plain calls', () => { expect(+balance).to.equal(50); } }); + + itEth('Can perform transferFromCross()', async ({helper}) => { + const sender = await helper.eth.createAccountWithBalance(donor, 100n); + + const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0); + + const receiver = helper.eth.createAccount(); + + await collection.mint(owner, 200n, {Substrate: owner.address}); + await collection.approveTokens(owner, {Ethereum: sender}, 100n); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'ft'); + + const from = helper.ethCrossAccount.fromKeyringPair(owner); + const to = helper.ethCrossAccount.fromAddress(receiver); + + const fromBalanceBefore = await collection.getBalance({Substrate: owner.address}); + const toBalanceBefore = await collection.getBalance({Ethereum: receiver}); + + const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender}); + + expect(result.events).to.be.like({ + Transfer: { + address, + event: 'Transfer', + returnValues: { + from: helper.address.substrateToEth(owner.address), + to: receiver, + value: '51', + }, + }, + Approval: { + address, + event: 'Approval', + returnValues: { + owner: helper.address.substrateToEth(owner.address), + spender: sender, + value: '49', + }, + }}); + + const fromBalanceAfter = await collection.getBalance({Substrate: owner.address}); + expect(fromBalanceBefore - fromBalanceAfter).to.be.eq(51n); + const toBalanceAfter = await collection.getBalance({Ethereum: receiver}); + expect(toBalanceAfter - toBalanceBefore).to.be.eq(51n); + }); }); describe('Fungible: Fees', () => { @@ -247,7 +483,7 @@ describe('Fungible: Fees', () => { [alice] = await helper.arrange.createAccounts([20n], donor); }); }); - + itEth('approve() call fee is less than 0.2UNQ', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const spender = helper.eth.createAccount(); @@ -255,7 +491,7 @@ describe('Fungible: Fees', () => { await collection.mint(alice, 200n, {Ethereum: owner}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner); const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner})); expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))); @@ -268,7 +504,7 @@ describe('Fungible: Fees', () => { await collection.mint(alice, 200n, {Ethereum: owner}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner); await contract.methods.approve(spender, 100).send({from: owner}); @@ -283,7 +519,7 @@ describe('Fungible: Fees', () => { await collection.mint(alice, 200n, {Ethereum: owner}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft', owner); const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner})); expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))); @@ -293,11 +529,12 @@ describe('Fungible: Fees', () => { describe('Fungible: Substrate calls', () => { let donor: IKeyringPair; let alice: IKeyringPair; + let owner: IKeyringPair; before(async function() { await usingEthPlaygrounds(async (helper, privateKey) => { donor = await privateKey({filename: __filename}); - [alice] = await helper.arrange.createAccounts([20n], donor); + [alice, owner] = await helper.arrange.createAccounts([20n, 20n], donor); }); }); @@ -307,13 +544,13 @@ describe('Fungible: Substrate calls', () => { await collection.mint(alice, 200n); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'ft'); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft'); const events: any = []; contract.events.allEvents((_: any, event: any) => { events.push(event); }); - + await collection.approveTokens(alice, {Ethereum: receiver}, 100n); if (events.length == 0) await helper.wait.newBlocks(1); const event = events[0]; @@ -333,7 +570,7 @@ describe('Fungible: Substrate calls', () => { await collection.approveTokens(alice, {Substrate: bob.address}, 100n); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'ft'); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft'); const events: any = []; contract.events.allEvents((_: any, event: any) => { @@ -364,13 +601,13 @@ describe('Fungible: Substrate calls', () => { await collection.mint(alice, 200n); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'ft'); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'ft'); const events: any = []; contract.events.allEvents((_: any, event: any) => { events.push(event); }); - + await collection.transfer(alice, {Ethereum:receiver}, 51n); if (events.length == 0) await helper.wait.newBlocks(1); const event = events[0]; @@ -381,4 +618,43 @@ describe('Fungible: Substrate calls', () => { expect(event.returnValues.to).to.be.equal(receiver); expect(event.returnValues.value).to.be.equal('51'); }); + + itEth('Events emitted for transferFromCross()', async ({helper}) => { + const sender = await helper.eth.createAccountWithBalance(donor, 100n); + + const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0); + + const receiver = helper.eth.createAccount(); + + await collection.mint(owner, 200n, {Substrate: owner.address}); + await collection.approveTokens(owner, {Ethereum: sender}, 100n); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'ft'); + + const from = helper.ethCrossAccount.fromKeyringPair(owner); + const to = helper.ethCrossAccount.fromAddress(receiver); + + const result = await contract.methods.transferFromCross(from, to, 51).send({from: sender}); + + expect(result.events).to.be.like({ + Transfer: { + address, + event: 'Transfer', + returnValues: { + from: helper.address.substrateToEth(owner.address), + to: receiver, + value: '51', + }, + }, + Approval: { + address, + event: 'Approval', + returnValues: { + owner: helper.address.substrateToEth(owner.address), + spender: sender, + value: '49', + }, + }}); + }); }); diff --git a/tests/src/eth/fungibleAbi.json b/tests/src/eth/fungibleAbi.json deleted file mode 100644 index 100e26fe49..0000000000 --- a/tests/src/eth/fungibleAbi.json +++ /dev/null @@ -1,396 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [ - { "internalType": "address", "name": "newAdmin", "type": "address" } - ], - "name": "addCollectionAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "user", "type": "address" } - ], - "name": "addToCollectionAllowList", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "owner", "type": "address" }, - { "internalType": "address", "name": "spender", "type": "address" } - ], - "name": "allowance", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "user", "type": "address" } - ], - "name": "allowed", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "spender", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" } - ], - "name": "approve", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "owner", "type": "address" } - ], - "name": "balanceOf", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "from", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" } - ], - "name": "burnFrom", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "newOwner", "type": "address" } - ], - "name": "changeCollectionOwner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "collectionOwner", - "outputs": [ - { - "components": [ - { "internalType": "address", "name": "field_0", "type": "address" }, - { "internalType": "uint256", "name": "field_1", "type": "uint256" } - ], - "internalType": "struct Tuple6", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], - "name": "collectionProperty", - "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "collectionSponsor", - "outputs": [ - { - "components": [ - { "internalType": "address", "name": "field_0", "type": "address" }, - { "internalType": "uint256", "name": "field_1", "type": "uint256" } - ], - "internalType": "struct Tuple6", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "confirmCollectionSponsorship", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "contractAddress", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], - "name": "deleteCollectionProperty", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "hasCollectionPendingSponsor", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "user", "type": "address" } - ], - "name": "isOwnerOrAdmin", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" } - ], - "name": "mint", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { "internalType": "address", "name": "field_0", "type": "address" }, - { "internalType": "uint256", "name": "field_1", "type": "uint256" } - ], - "internalType": "struct Tuple6[]", - "name": "amounts", - "type": "tuple[]" - } - ], - "name": "mintBulk", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [{ "internalType": "string", "name": "", "type": "string" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "admin", "type": "address" } - ], - "name": "removeCollectionAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "removeCollectionSponsor", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "user", "type": "address" } - ], - "name": "removeFromCollectionAllowList", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }], - "name": "setCollectionAccess", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "string", "name": "limit", "type": "string" }, - { "internalType": "uint32", "name": "value", "type": "uint32" } - ], - "name": "setCollectionLimit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "string", "name": "limit", "type": "string" }, - { "internalType": "bool", "name": "value", "type": "bool" } - ], - "name": "setCollectionLimit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }], - "name": "setCollectionMintMode", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }], - "name": "setCollectionNesting", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "bool", "name": "enable", "type": "bool" }, - { - "internalType": "address[]", - "name": "collections", - "type": "address[]" - } - ], - "name": "setCollectionNesting", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "string", "name": "key", "type": "string" }, - { "internalType": "bytes", "name": "value", "type": "bytes" } - ], - "name": "setCollectionProperty", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "sponsor", "type": "address" } - ], - "name": "setCollectionSponsor", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" } - ], - "name": "supportsInterface", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [{ "internalType": "string", "name": "", "type": "string" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" } - ], - "name": "transfer", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "from", "type": "address" }, - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "uint256", "name": "amount", "type": "uint256" } - ], - "name": "transferFrom", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "uniqueCollectionType", - "outputs": [{ "internalType": "string", "name": "", "type": "string" }], - "stateMutability": "view", - "type": "function" - } -] diff --git a/tests/src/eth/helpersSmoke.test.ts b/tests/src/eth/helpersSmoke.test.ts index 31140efa06..2c00b13429 100644 --- a/tests/src/eth/helpersSmoke.test.ts +++ b/tests/src/eth/helpersSmoke.test.ts @@ -25,13 +25,13 @@ describe('Helpers sanity check', () => { donor = await privateKey({filename: __filename}); }); }); - + itEth('Contract owner is recorded', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const flipper = await helper.eth.deployFlipper(owner); - expect(await helper.ethNativeContract.contractHelpers(owner).methods.contractOwner(flipper.options.address).call()).to.be.equal(owner); + expect(await (await helper.ethNativeContract.contractHelpers(owner)).methods.contractOwner(flipper.options.address).call()).to.be.equal(owner); }); itEth('Flipper is working', async ({helper}) => { diff --git a/tests/src/eth/marketplace/MarketPlace.abi b/tests/src/eth/marketplace/MarketPlace.abi deleted file mode 100644 index 05995d05d7..0000000000 --- a/tests/src/eth/marketplace/MarketPlace.abi +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"address","name":"_escrow","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_price","type":"uint256"},{"indexed":false,"internalType":"address","name":"_currencyCode","type":"address"},{"indexed":false,"internalType":"address","name":"_idCollection","type":"address"},{"indexed":false,"internalType":"uint256","name":"_idNFT","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"AddedAsk","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_idCollection","type":"address"},{"indexed":false,"internalType":"uint256","name":"_idNFT","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"orderID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"orderPrice","type":"uint256"}],"name":"BoughtNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_idCollection","type":"address"},{"indexed":false,"internalType":"uint256","name":"_idNFT","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"orderID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"orderPrice","type":"uint256"}],"name":"BoughtNFT4KSM","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_idCollection","type":"address"},{"indexed":false,"internalType":"uint256","name":"_idNFT","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"CanceledAsk","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_sender","type":"address"}],"name":"DepositedKSM","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_price","type":"uint256"},{"indexed":false,"internalType":"address","name":"_currencyCode","type":"address"},{"indexed":false,"internalType":"address","name":"_idCollection","type":"address"},{"indexed":false,"internalType":"uint256","name":"_idNFT","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"_active","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"EditedAsk","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_currencyCode","type":"address"},{"indexed":false,"internalType":"address","name":"_sender","type":"address"}],"name":"Withdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"WithdrawnAllKSM","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"},{"internalType":"address","name":"_currencyCode","type":"address"},{"internalType":"address","name":"_idCollection","type":"address"},{"internalType":"uint256","name":"_idNFT","type":"uint256"}],"name":"addAsk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"asks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"asksbySeller","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceKSM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_idCollection","type":"address"},{"internalType":"uint256","name":"_idNFT","type":"uint256"}],"name":"buy","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_idCollection","type":"address"},{"internalType":"uint256","name":"_idNFT","type":"uint256"},{"internalType":"address","name":"_buyer","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"buyKSM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_idCollection","type":"address"},{"internalType":"uint256","name":"_idNFT","type":"uint256"}],"name":"cancelAsk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_sender","type":"address"}],"name":"depositKSM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"},{"internalType":"address","name":"_currencyCode","type":"address"},{"internalType":"address","name":"_idCollection","type":"address"},{"internalType":"uint256","name":"_idNFT","type":"uint256"},{"internalType":"uint8","name":"_active","type":"uint8"}],"name":"editAsk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_idCollection","type":"address"},{"internalType":"uint256","name":"_idNFT","type":"uint256"}],"name":"getOrder","outputs":[{"components":[{"internalType":"uint256","name":"idNFT","type":"uint256"},{"internalType":"address","name":"currencyCode","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"time","type":"uint256"},{"internalType":"address","name":"idCollection","type":"address"},{"internalType":"address","name":"ownerAddr","type":"address"},{"internalType":"uint8","name":"flagActive","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"tokenURI","type":"string"}],"internalType":"struct MarketPlace.Order","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOrdersLen","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"orders","outputs":[{"internalType":"uint256","name":"idNFT","type":"uint256"},{"internalType":"address","name":"currencyCode","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"time","type":"uint256"},{"internalType":"address","name":"idCollection","type":"address"},{"internalType":"address","name":"ownerAddr","type":"address"},{"internalType":"uint8","name":"flagActive","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"tokenURI","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newEscrow","type":"address"}],"name":"setEscrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_coin","type":"address"}],"name":"setNativeCoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newEscrow","type":"address"}],"name":"setowner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_currencyCode","type":"address"},{"internalType":"address payable","name":"_sender","type":"address"}],"name":"withdraw","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"}],"name":"withdrawAllKSM","outputs":[{"internalType":"uint256","name":"lastBalance","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file diff --git a/tests/src/eth/marketplace/MarketPlace.bin b/tests/src/eth/marketplace/MarketPlace.bin deleted file mode 100644 index c29be59c56..0000000000 --- a/tests/src/eth/marketplace/MarketPlace.bin +++ /dev/null @@ -1 +0,0 @@ -60806040523480156200001157600080fd5b50604051620029b8380380620029b8833981016040819052620000349162000327565b600580546001600160a01b038084166001600160a01b03199283161790925560068054821633179055604080516101408101825260008082526020808301828152838501838152606085018481526080860185815260a0870186815260c0880187815289518088018b5288815260e08a019081528a518089018c528981526101008b01528a51808901909b52888b526101208a019a909a528754600181018955978052885160099098027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563810198895595517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56487018054918e16918d1691909117905593517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56586015591517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566850155517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56784018054918b16919099161790975595517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56882018054975160ff16600160a01b026001600160a81b0319909816919098161795909517909555915180519194929362000239937f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5699091019291019062000281565b5061010082015180516200025891600784019160209091019062000281565b5061012082015180516200027791600884019160209091019062000281565b5050505062000396565b8280546200028f9062000359565b90600052602060002090601f016020900481019282620002b35760008555620002fe565b82601f10620002ce57805160ff1916838001178555620002fe565b82800160010185558215620002fe579182015b82811115620002fe578251825591602001919060010190620002e1565b506200030c92915062000310565b5090565b5b808211156200030c576000815560010162000311565b6000602082840312156200033a57600080fd5b81516001600160a01b03811681146200035257600080fd5b9392505050565b600181811c908216806200036e57607f821691505b602082108114156200039057634e487b7160e01b600052602260045260246000fd5b50919050565b61261280620003a66000396000f3fe6080604052600436106101025760003560e01c806399f2d4eb11610095578063c10c354611610064578063c10c354614610221578063cce7ec1314610378578063e22d4f7d1461038b578063edb25841146103c3578063fd8868c7146103f057610184565b806399f2d4eb146102c5578063a85c38ef146102e5578063b460af941461031b578063b4c3e8ea1461034b57610184565b80636b084b25116100d15780636b084b2514610241578063791bd866146102615780638c088f001461028157806393cdd334146102a557610184565b806337c4eb58146101bf5780633ce61756146101e157806340b8074614610201578063592bd7051461022157610184565b366101845760405162461bcd60e51b815260206004820152604160248201527f43616e277420616363657074207061796d656e7420776974686f757420636f6c60448201527f6c656374696f6e20616e64204944732c20757365206441707020746f2073656e6064820152601960fa1b608482015260a4015b60405180910390fd5b60405162461bcd60e51b815260206004820152601060248201526f27379039bab1b410333ab731ba34b7b760811b604482015260640161017b565b3480156101cb57600080fd5b506101df6101da366004612054565b610410565b005b3480156101ed57600080fd5b506101df6101fc36600461209c565b610979565b34801561020d57600080fd5b506101df61021c3660046120c0565b6109c5565b34801561022d57600080fd5b506101df61023c36600461209c565b610c27565b34801561024d57600080fd5b506101df61025c3660046120ec565b610c73565b34801561026d57600080fd5b506101df61027c366004612151565b610ee6565b34801561028d57600080fd5b506000545b6040519081526020015b60405180910390f35b3480156102b157600080fd5b506102926102c036600461209c565b610fb1565b3480156102d157600080fd5b506102926102e03660046120c0565b61105e565b3480156102f157600080fd5b50610305610300366004612181565b61108f565b60405161029c9a999897969594939291906121f6565b34801561032757600080fd5b5061033b610336366004612283565b6112a0565b604051901515815260200161029c565b34801561035757600080fd5b5061029261036636600461209c565b60026020526000908152604090205481565b61033b6103863660046120c0565b6113d2565b34801561039757600080fd5b506102926103a63660046120c0565b600360209081526000928352604080842090915290825290205481565b3480156103cf57600080fd5b506103e36103de3660046120c0565b61181b565b60405161029c91906122c5565b3480156103fc57600080fd5b506101df61040b3660046123a5565b611b0c565b6040516331a9108f60e11b8152600481018290526000906001600160a01b03841690636352211e90602401602060405180830381865afa158015610458573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061047c91906123f8565b90506001600160a01b03811633146104d65760405162461bcd60e51b815260206004820152601d60248201527f4f6e6c7920746f6b656e206f776e65722063616e206d616b652061736b000000604482015260640161017b565b6060806060856001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa92505050801561053a57506040513d6000823e601f3d908101601f19168201604052610537919081019061242b565b60015b61055557604051806020016040528060008152509250610558565b92505b856001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa9250505080156105b757506040513d6000823e601f3d908101601f191682016040526105b4919081019061242b565b60015b6105d2576040518060200160405280600081525091506105d5565b91505b60405163c87b56dd60e01b8152600481018690526001600160a01b0387169063c87b56dd90602401600060405180830381865afa92505050801561063b57506040513d6000823e601f3d908101601f19168201604052610638919081019061242b565b60015b6106545750604080516020810190915260008152610657565b90505b60408051610140810182528681526001600160a01b03808a1660208084019182529383018c815242606085019081528b8416608086019081523360a08701908152600160c0880181815260e089018d81526101008a018d90526101208a018c90526000805493840181558052895160099093027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563810193845597517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56489018054918b166001600160a01b031992831617905596517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56589015594517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56688015592517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e567870180549189169190961617909455517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56885018054925160ff16600160a01b026001600160a81b03199093169190961617179093559151805193949293610828937f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e569909301929190910190611fa3565b506101008201518051610845916007840191602090910190611fa3565b506101208201518051610862916008840191602090910190611fa3565b505060008054909150610877906001906124ee565b6001600160a01b03881660008181526003602090815260408083208b84528252808320859055338084526004808452828520805460018101825590865293909420909201859055516323b872dd60e01b815293945091926323b872dd926108e492909130918c9101612505565b600060405180830381600087803b1580156108fe57600080fd5b505af1158015610912573d6000803e3d6000fd5b5050604080518c81526001600160a01b038c811660208301528b1681830152606081018a90526080810185905290517f83b3a8754d705365b581ab63c329c1e55255a22aa78c67b5fcef378bfb2d9b9993509081900360a0019150a1505050505050505050565b6006546001600160a01b031633146109a35760405162461bcd60e51b815260040161017b90612529565b600780546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0382166000908152600360209081526040808320848452909152812054815490913391839081106109ff576109ff612551565b60009182526020909120600560099092020101546001600160a01b031614610a695760405162461bcd60e51b815260206004820152601d60248201527f4f6e6c7920746f6b656e206f776e65722063616e20656469742061736b000000604482015260640161017b565b60008181548110610a7c57610a7c612551565b6000918252602090912060099091020160050154600160a01b900460ff16610adb5760405162461bcd60e51b8152602060048201526012602482015271151a1a5cc8185cdac81a5cc818db1bdcd95960721b604482015260640161017b565b4260008281548110610aef57610aef612551565b9060005260206000209060090201600301819055506000808281548110610b1857610b18612551565b906000526020600020906009020160050160146101000a81548160ff021916908360ff160217905550826001600160a01b03166323b872dd3060008481548110610b6457610b64612551565b60009182526020909120600560099092020101546040516001600160e01b031960e085901b168152610ba592916001600160a01b0316908790600401612505565b600060405180830381600087803b158015610bbf57600080fd5b505af1158015610bd3573d6000803e3d6000fd5b5050604080516001600160a01b0387168152602081018690529081018490527f6330f58b476cc7f9dd8db8130a0fbb49b291ebc32531eb36e9646f56ee20174b9250606001905060405180910390a1505050565b6006546001600160a01b03163314610c515760405162461bcd60e51b815260040161017b90612529565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038316600090815260036020908152604080832085845290915281205481549091339183908110610cad57610cad612551565b60009182526020909120600560099092020101546001600160a01b031614610d175760405162461bcd60e51b815260206004820152601d60248201527f4f6e6c7920746f6b656e206f776e65722063616e20656469742061736b000000604482015260640161017b565b60008181548110610d2a57610d2a612551565b6000918252602090912060099091020160050154600160a01b900460ff16610d895760405162461bcd60e51b8152602060048201526012602482015271151a1a5cc8185cdac81a5cc818db1bdcd95960721b604482015260640161017b565b8515610db9578560008281548110610da357610da3612551565b9060005260206000209060090201600201819055505b6001600160a01b03851615610e12578460008281548110610ddc57610ddc612551565b906000526020600020906009020160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b4260008281548110610e2657610e26612551565b9060005260206000209060090201600301819055508160008281548110610e4f57610e4f612551565b600091825260209182902060099190910201600501805460ff60a01b1916600160a01b60ff94851602179055604080518981526001600160a01b03898116938201939093529187169082015260608101859052908316608082015260a081018290527f04211d838289b72af597bf28a4ccff5a30d6056f5fce2eddb127ab4ffea0963d9060c00160405180910390a1505050505050565b6005546001600160a01b03163314610f325760405162461bcd60e51b815260206004820152600f60248201526e27b7363c9032b9b1b937bb9031b0b760891b604482015260640161017b565b6001600160a01b038116600090815260026020526040902054610f56908390612567565b6001600160a01b038216600081815260026020908152604091829020939093558051858152928301919091527f291ce0b690061cb1b3f1111bf6500efe526983251fb0f863251ec3670d035fc4910160405180910390a15050565b6005546000906001600160a01b031633146110005760405162461bcd60e51b815260206004820152600f60248201526e27b7363c9032b9b1b937bb9031b0b760891b604482015260640161017b565b506001600160a01b03811660008181526002602090815260408083208054939055805193845290830182905290917f027aeacbc6fbfa7fe735ff8f14a600469ad1a3197ce1c8c8a159641cf68fe592910160405180910390a1919050565b6004602052816000526040600020818154811061107a57600080fd5b90600052602060002001600091509150505481565b6000818154811061109f57600080fd5b600091825260209091206009909102018054600182015460028301546003840154600485015460058601546006870180549698506001600160a01b0395861697949693959283169492821693600160a01b90920460ff1692916111019061257f565b80601f016020809104026020016040519081016040528092919081815260200182805461112d9061257f565b801561117a5780601f1061114f5761010080835404028352916020019161117a565b820191906000526020600020905b81548152906001019060200180831161115d57829003601f168201915b50505050509080600701805461118f9061257f565b80601f01602080910402602001604051908101604052809291908181526020018280546111bb9061257f565b80156112085780601f106111dd57610100808354040283529160200191611208565b820191906000526020600020905b8154815290600101906020018083116111eb57829003601f168201915b50505050509080600801805461121d9061257f565b80601f01602080910402602001604051908101604052809291908181526020018280546112499061257f565b80156112965780601f1061126b57610100808354040283529160200191611296565b820191906000526020600020905b81548152906001019060200180831161127957829003601f168201915b505050505090508a565b6006546000906001600160a01b031633146112cd5760405162461bcd60e51b815260040161017b90612529565b6007546001600160a01b0384811691161461135b5760405163a9059cbb60e01b81526001600160a01b0383811660048301526024820186905284169063a9059cbb906044016020604051808303816000875af1158015611331573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135591906125ba565b50611382565b6040516001600160a01b0383169085156108fc029086906000818181858888f19450505050505b604080518581526001600160a01b03858116602083015284168183015290517fb524bace85e4ce0f8da306e32f39263c5724780ca00b7551c051c8e3dc36adaf9181900360600190a19392505050565b6001600160a01b0382166000908152600360209081526040808320848452909152812054815482918291811061140a5761140a612551565b600091825260209182902060408051610140810182526009939093029091018054835260018101546001600160a01b039081169484019490945260028101549183019190915260038101546060830152600481015483166080830152600581015492831660a0830152600160a01b90920460ff1660c082015260068201805491929160e08401919061149b9061257f565b80601f01602080910402602001604051908101604052809291908181526020018280546114c79061257f565b80156115145780601f106114e957610100808354040283529160200191611514565b820191906000526020600020905b8154815290600101906020018083116114f757829003601f168201915b5050505050815260200160078201805461152d9061257f565b80601f01602080910402602001604051908101604052809291908181526020018280546115599061257f565b80156115a65780601f1061157b576101008083540402835291602001916115a6565b820191906000526020600020905b81548152906001019060200180831161158957829003601f168201915b505050505081526020016008820180546115bf9061257f565b80601f01602080910402602001604051908101604052809291908181526020018280546115eb9061257f565b80156116385780601f1061160d57610100808354040283529160200191611638565b820191906000526020600020905b81548152906001019060200180831161161b57829003601f168201915b5050505050815250509050806040015134146116ac5760405162461bcd60e51b815260206004820152602d60248201527f4e6f7420726967687420616d6f756e742073656e742c206861766520746f206260448201526c6520657175616c20707269636560981b606482015260840161017b565b6001600160a01b0384166000908152600360209081526040808320868452909152812054815482919081106116e3576116e3612551565b906000526020600020906009020160050160146101000a81548160ff021916908360ff160217905550836001600160a01b03166323b872dd3033866040518463ffffffff1660e01b815260040161173c93929190612505565b600060405180830381600087803b15801561175657600080fd5b505af115801561176a573d6000803e3d6000fd5b505050508060a001516001600160a01b03166108fc82604001519081150290604051600060405180830381858888f16001600160a01b03891660008181526003602090815260408083208c8452825291829020548983015183519485529184018c90529183019190915260608201529096507fc220cf2a12d6492e23ed1141c55018997799699d009b00ebd5a4874c60f5c31e9450608001925061180c915050565b60405180910390a15092915050565b61188f6040518061014001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600060ff1681526020016060815260200160608152602001606081525090565b6001600160a01b038316600090815260036020908152604080832085845290915281205481549091908190839081106118ca576118ca612551565b600091825260209182902060408051610140810182526009939093029091018054835260018101546001600160a01b039081169484019490945260028101549183019190915260038101546060830152600481015483166080830152600581015492831660a0830152600160a01b90920460ff1660c082015260068201805491929160e08401919061195b9061257f565b80601f01602080910402602001604051908101604052809291908181526020018280546119879061257f565b80156119d45780601f106119a9576101008083540402835291602001916119d4565b820191906000526020600020905b8154815290600101906020018083116119b757829003601f168201915b505050505081526020016007820180546119ed9061257f565b80601f0160208091040260200160405190810160405280929190818152602001828054611a199061257f565b8015611a665780601f10611a3b57610100808354040283529160200191611a66565b820191906000526020600020905b815481529060010190602001808311611a4957829003601f168201915b50505050508152602001600882018054611a7f9061257f565b80601f0160208091040260200160405190810160405280929190818152602001828054611aab9061257f565b8015611af85780601f10611acd57610100808354040283529160200191611af8565b820191906000526020600020905b815481529060010190602001808311611adb57829003601f168201915b505050919092525091979650505050505050565b6001600160a01b038416600090815260036020908152604080832086845290915281205481548291908110611b4357611b43612551565b600091825260209182902060408051610140810182526009939093029091018054835260018101546001600160a01b039081169484019490945260028101549183019190915260038101546060830152600481015483166080830152600581015492831660a0830152600160a01b90920460ff1660c082015260068201805491929160e084019190611bd49061257f565b80601f0160208091040260200160405190810160405280929190818152602001828054611c009061257f565b8015611c4d5780601f10611c2257610100808354040283529160200191611c4d565b820191906000526020600020905b815481529060010190602001808311611c3057829003601f168201915b50505050508152602001600782018054611c669061257f565b80601f0160208091040260200160405190810160405280929190818152602001828054611c929061257f565b8015611cdf5780601f10611cb457610100808354040283529160200191611cdf565b820191906000526020600020905b815481529060010190602001808311611cc257829003601f168201915b50505050508152602001600882018054611cf89061257f565b80601f0160208091040260200160405190810160405280929190818152602001828054611d249061257f565b8015611d715780601f10611d4657610100808354040283529160200191611d71565b820191906000526020600020905b815481529060010190602001808311611d5457829003601f168201915b505050919092525050600554919250506001600160a01b0316331480611d9f5750336001600160a01b038416145b611df75760405162461bcd60e51b8152602060048201526024808201527f4f6e6c7920657363726f77206f722062757965722063616e2063616c6c206275604482015263794b534d60e01b606482015260840161017b565b6040808201516001600160a01b038516600090815260026020529190912054611e2091906124ee565b6001600160a01b03808516600090815260026020526040808220939093558383015160a085015190921681529190912054611e5b9190612567565b60a08201516001600160a01b039081166000908152600260209081526040808320949094559188168152600382528281208782529091529081205481548291908110611ea957611ea9612551565b906000526020600020906009020160050160146101000a81548160ff021916908360ff160217905550846001600160a01b03166323b872dd3084876040518463ffffffff1660e01b8152600401611f0293929190612505565b600060405180830381600087803b158015611f1c57600080fd5b505af1158015611f30573d6000803e3d6000fd5b505050506001600160a01b038516600081815260036020908152604080832088845282529182902054848301518351948552918401889052838301526060830152517f68bdd3548f3f05742b376651745ca73472eb18f2230f64b893d7a48e575eb0149181900360800190a15050505050565b828054611faf9061257f565b90600052602060002090601f016020900481019282611fd15760008555612017565b82601f10611fea57805160ff1916838001178555612017565b82800160010185558215612017579182015b82811115612017578251825591602001919060010190611ffc565b50612023929150612027565b5090565b5b808211156120235760008155600101612028565b6001600160a01b038116811461205157600080fd5b50565b6000806000806080858703121561206a57600080fd5b84359350602085013561207c8161203c565b9250604085013561208c8161203c565b9396929550929360600135925050565b6000602082840312156120ae57600080fd5b81356120b98161203c565b9392505050565b600080604083850312156120d357600080fd5b82356120de8161203c565b946020939093013593505050565b600080600080600060a0868803121561210457600080fd5b8535945060208601356121168161203c565b935060408601356121268161203c565b925060608601359150608086013560ff8116811461214357600080fd5b809150509295509295909350565b6000806040838503121561216457600080fd5b8235915060208301356121768161203c565b809150509250929050565b60006020828403121561219357600080fd5b5035919050565b60005b838110156121b557818101518382015260200161219d565b838111156121c4576000848401525b50505050565b600081518084526121e281602086016020860161219a565b601f01601f19169290920160200192915050565b8a81526001600160a01b038a81166020830152604082018a9052606082018990528781166080830152861660a082015260ff851660c082015261014060e08201819052600090612248838201876121ca565b905082810361010084015261225d81866121ca565b905082810361012084015261227281856121ca565b9d9c50505050505050505050505050565b60008060006060848603121561229857600080fd5b8335925060208401356122aa8161203c565b915060408401356122ba8161203c565b809150509250925092565b6020815281516020820152600060208301516122ec60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015161231b60a08401826001600160a01b03169052565b5060a08301516001600160a01b03811660c08401525060c083015160ff811660e08401525060e0830151610140610100818186015261235e6101608601846121ca565b9250808601519050601f1961012081878603018188015261237f85846121ca565b90880151878203909201848801529350905061239b83826121ca565b9695505050505050565b600080600080608085870312156123bb57600080fd5b84356123c68161203c565b93506020850135925060408501356123dd8161203c565b915060608501356123ed8161203c565b939692955090935050565b60006020828403121561240a57600080fd5b81516120b98161203c565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561243d57600080fd5b815167ffffffffffffffff8082111561245557600080fd5b818401915084601f83011261246957600080fd5b81518181111561247b5761247b612415565b604051601f8201601f19908116603f011681019083821181831017156124a3576124a3612415565b816040528281528760208487010111156124bc57600080fd5b6124cd83602083016020880161219a565b979650505050505050565b634e487b7160e01b600052601160045260246000fd5b600082821015612500576125006124d8565b500390565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6020808252600e908201526d27b7363c9037bbb732b91031b0b760911b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6000821982111561257a5761257a6124d8565b500190565b600181811c9082168061259357607f821691505b602082108114156125b457634e487b7160e01b600052602260045260246000fd5b50919050565b6000602082840312156125cc57600080fd5b815180151581146120b957600080fdfea26469706673582212205a8295bbb792776496ccaaa9cb7384efe95af6490ca8015ceb6eb22e5ab3ae6b64736f6c634300080a0033 \ No newline at end of file diff --git a/tests/src/eth/marketplace/MarketPlace.sol b/tests/src/eth/marketplace/MarketPlace.sol index 6178d80fb7..7833f1376b 100644 --- a/tests/src/eth/marketplace/MarketPlace.sol +++ b/tests/src/eth/marketplace/MarketPlace.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache License pragma solidity >=0.8.0; -import "../api/UniqueNFT.sol"; +import {UniqueNFT, Dummy, ERC165} from "../api/UniqueNFT.sol"; // Inline interface ERC20Events { @@ -52,8 +52,9 @@ interface UniqueFungible is Dummy, ERC165, ERC20 {} contract MarketPlace { struct Order { + uint256 idNFT; - address currencyCode; // UNIQ tokens as address address (1); wKSM + address currencyCode; // UNIQ tokens as address address (1); wKSM uint256 price; uint256 time; address idCollection; @@ -61,330 +62,353 @@ contract MarketPlace { uint8 flagActive; string name; string symbol; - string tokenURI; + string tokenURI; } - Order[] public orders; - uint256 test; - mapping(address => uint256) public balanceKSM; // [ownerAddr][currency] => [KSMs] - mapping(address => mapping(uint256 => uint256)) public asks; // [buyer][idCollection][idNFT] => idorder + Order[] public orders; + uint test; + mapping (address => uint256) public balanceKSM; // [ownerAddr][currency] => [KSMs] + mapping (address => mapping (uint256 => uint256)) public asks ; // [buyer][idCollection][idNFT] => idorder + mapping (address => mapping (uint => uint[])) public ordersbyNFT; // [addressCollection] =>idNFT =>idorder - mapping(address => uint256[]) public asksbySeller; // [addressSeller] =>idorder + mapping (address => uint[]) public asksbySeller; // [addressSeller] =>idorder - address escrow; + mapping (address =>bool) internal isEscrow; + + //address escrow; address owner; address nativecoin; - constructor(address _escrow) { - escrow = _escrow; + // from abstract contract ReentrancyGuard + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint8 private constant _NOT_ENTERED = 1; + uint8 private constant _ENTERED = 2; + + uint8 private _status; + + struct NFT { + address collection; + uint256 id; + } + + //function initialize() public initializer { + constructor () { // call setEscrow directly owner = msg.sender; - orders.push( - Order(0, address(0), 0, 0, address(0), address(0), 0, "", "", "") - ); - } + orders.push(Order( + 0, + address(0), + 0, + 0, + address(0), + address(0), + 0, "","","")); + _status = _NOT_ENTERED; - function setowner(address _newEscrow) public onlyOwner { - escrow = _newEscrow; } - function setEscrow(address _newEscrow) public onlyOwner { - escrow = _newEscrow; - } + modifier nonReentrant() { // from abstract contract ReentrancyGuard + // On the first call to nonReentrant, _notEntered will be true + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); - function setNativeCoin(address _coin) public onlyOwner { - nativecoin = _coin; + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + + _; + + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; } - modifier onlyEscrow() { - require(msg.sender == escrow, "Only escrow can"); + modifier onlyEscrow () { + require(isEscrow [msg.sender] , "Only escrow can"); _; } - modifier onlyOwner() { + modifier onlyOwner () { require(msg.sender == owner, "Only owner can"); _; } /** - * Make bids (orders) to sell NFTs - */ + * Make bids (orders) to sell NFTs + */ - receive() external payable { - revert( - "Can't accept payment without collection and IDs, use dApp to send" - ); + + receive () external payable { + // revert ("Can't accept payment without collection and IDs, use dApp to send"); } + fallback () external payable { + revert ("No such function"); + } - fallback() external payable { - revert("No such function"); - } + event AddedAsk (uint256 _price, + address _currencyCode, + address _idCollection, + uint256 _idNFT, + uint256 orderId + ); + event EditedAsk (uint256 _price, + address _currencyCode, + address _idCollection, + uint256 _idNFT, + uint8 _active, + uint orderId); - event AddedAsk( - uint256 _price, - address _currencyCode, - address _idCollection, - uint256 _idNFT, - uint256 orderId - ); - event EditedAsk( - uint256 _price, - address _currencyCode, - address _idCollection, - uint256 _idNFT, - uint8 _active, - uint256 orderId - ); + event CanceledAsk (address _idCollection, + uint256 _idNFT, + uint orderId + ); - event CanceledAsk(address _idCollection, uint256 _idNFT, uint256 orderId); + event DepositedKSM (uint256 _amount, address _sender); - event DepositedKSM(uint256 _amount, address _sender); + event BoughtNFT4KSM (address _idCollection, uint256 _idNFT, uint orderID, uint orderPrice ); - event BoughtNFT4KSM( - address _idCollection, - uint256 _idNFT, - uint256 orderID, - uint256 orderPrice - ); + event BoughtNFT (address _idCollection, uint256 _idNFT, uint orderID, uint orderPrice ); - event BoughtNFT( - address _idCollection, - uint256 _idNFT, - uint256 orderID, - uint256 orderPrice - ); + event WithdrawnAllKSM (address _sender, uint256 balance); + + event WithdrawnKSM (address _sender, uint256 balance); + + event Withdrawn (uint256 _amount, address _currencyCode, address _sender); + + + function setOwner (address _newOwner) public onlyOwner { + owner = _newOwner; + } - event WithdrawnAllKSM(address _sender, uint256 balance); + function setEscrow (address _escrow, bool _state) public onlyOwner returns (bool) { + if (isEscrow[_escrow] != _state) { + isEscrow[_escrow] = _state; + return true; + } + return false; + } + + function setNativeCoin (address _coin) public onlyOwner { + nativecoin = _coin; + } - event Withdrawn(uint256 _amount, address _currencyCode, address _sender); - function addAsk( - uint256 _price, - address _currencyCode, - address _idCollection, - uint256 _idNFT - ) public { - // + function addAsk (uint256 _price, + address _currencyCode, + address _idCollection, + uint256 _idNFT + ) public { // address ownerNFT = UniqueNFT(_idCollection).ownerOf(_idNFT); - require(ownerNFT == msg.sender, "Only token owner can make ask"); + require (ownerNFT == msg.sender, "Only token owner can make ask"); string memory nameNFT; string memory symbolNFT; string memory uriNFT; try UniqueNFT(_idCollection).name() returns (string memory name_) { nameNFT = name_; - } catch { - nameNFT = ""; } + catch { + nameNFT=""; + } try UniqueNFT(_idCollection).symbol() returns (string memory symbol_) { symbolNFT = symbol_; - } catch { - symbolNFT = ""; } - try UniqueNFT(_idCollection).tokenURI(_idNFT) returns ( - string memory uri_ - ) { + catch { + symbolNFT=""; + } + try UniqueNFT(_idCollection).tokenURI(_idNFT) returns (string memory uri_) { uriNFT = uri_; - } catch { - uriNFT = ""; } - orders.push( - Order( - _idNFT, - _currencyCode, - _price, - block.timestamp, - _idCollection, - msg.sender, - 1, // 1 = is active - nameNFT, - symbolNFT, - uriNFT - ) - ); - - uint256 orderId = orders.length - 1; - asks[_idCollection][_idNFT] = orderId; - asksbySeller[msg.sender].push(orderId); - UniqueNFT(_idCollection).transferFrom( - msg.sender, - address(this), - _idNFT - ); - emit AddedAsk(_price, _currencyCode, _idCollection, _idNFT, orderId); + catch { + uriNFT=""; + } + orders.push(Order( + _idNFT, + _currencyCode, + _price, + block.timestamp, + _idCollection, + msg.sender, + 1, // 1 = is active + nameNFT, + symbolNFT, + uriNFT + )); + + uint orderId = orders.length-1; + asks[_idCollection][_idNFT] = orderId; + asksbySeller[msg.sender].push(orderId); + UniqueNFT(_idCollection).transferFrom(msg.sender, address(this), _idNFT); + emit AddedAsk(_price, _currencyCode, _idCollection, _idNFT, orderId); } - function editAsk( - uint256 _price, - address _currencyCode, - address _idCollection, - uint256 _idNFT, - uint8 _active - ) public { - uint256 orderID = asks[_idCollection][_idNFT]; - - require( - orders[orderID].ownerAddr == msg.sender, - "Only token owner can edit ask" - ); - require(orders[orderID].flagActive != 0, "This ask is closed"); - if (_price > 0) { - orders[orderID].price = _price; - } + function editAsk (uint256 _price, + address _currencyCode, + address _idCollection, + uint256 _idNFT, + uint8 _active) public { + - if (_currencyCode != address(0)) { - orders[orderID].currencyCode = _currencyCode; + uint orderID = asks[_idCollection][_idNFT]; + + require (orders[orderID].ownerAddr == msg.sender, "Only token owner can edit ask"); + require (orders[orderID].flagActive != 0, "This ask is closed"); + if (_price> 0 ) { + orders[orderID].price = _price ; + } + + if (_currencyCode != address(0) ) { + orders[orderID].currencyCode = _currencyCode ; } orders[orderID].time = block.timestamp; orders[orderID].flagActive = _active; + + emit EditedAsk(_price, _currencyCode, _idCollection, _idNFT, _active, orderID); + } + - emit EditedAsk( - _price, - _currencyCode, - _idCollection, - _idNFT, - _active, - orderID - ); - } + function cancelAsk (address _idCollection, + uint256 _idNFT + ) public { - function cancelAsk(address _idCollection, uint256 _idNFT) public { - uint256 orderID = asks[_idCollection][_idNFT]; + uint orderID = asks[_idCollection][_idNFT]; - require( - orders[orderID].ownerAddr == msg.sender, - "Only token owner can edit ask" - ); - require(orders[orderID].flagActive != 0, "This ask is closed"); + require (orders[orderID].ownerAddr == msg.sender, "Only token owner can edit ask"); + require (orders[orderID].flagActive != 0, "This ask is closed"); orders[orderID].time = block.timestamp; orders[orderID].flagActive = 0; - UniqueNFT(_idCollection).transferFrom( - address(this), - orders[orderID].ownerAddr, - _idNFT - ); + UniqueNFT(_idCollection).transferFrom(address(this),orders[orderID].ownerAddr, _idNFT); emit CanceledAsk(_idCollection, _idNFT, orderID); - } + } - function depositKSM(uint256 _amount, address _sender) public onlyEscrow { + + function depositKSM (uint256 _amount, address _sender) public onlyEscrow { balanceKSM[_sender] = balanceKSM[_sender] + _amount; emit DepositedKSM(_amount, _sender); } - function buyKSM( - address _idCollection, - uint256 _idNFT, - address _buyer, - address _receiver - ) public { - Order memory order = orders[asks[_idCollection][_idNFT]]; - require(msg.sender == escrow || msg.sender == _buyer, "Only escrow or buyer can call buyKSM" ); + function buyKSM (address _idCollection, uint256 _idNFT, address _buyer, address _receiver ) public { + + Order memory order = orders[ asks[_idCollection][_idNFT]]; + require(isEscrow[msg.sender] || msg.sender == _buyer, "Only escrow or buyer can call buyKSM" ); //1. reduce balance + balanceKSM[_buyer] = balanceKSM[_buyer] - order.price; balanceKSM[order.ownerAddr] = balanceKSM[order.ownerAddr] + order.price; // 2. close order - orders[asks[_idCollection][_idNFT]].flagActive = 0; + orders[ asks[_idCollection][_idNFT]].flagActive = 0; // 3. transfer NFT to buyer UniqueNFT(_idCollection).transferFrom(address(this), _receiver, _idNFT); - emit BoughtNFT4KSM( - _idCollection, - _idNFT, - asks[_idCollection][_idNFT], - order.price - ); - } + emit BoughtNFT4KSM(_idCollection, _idNFT, asks[_idCollection][_idNFT], order.price); - function buy(address _idCollection, uint256 _idNFT) - public - payable - returns (bool result) - { - //buing for UNQ like as ethers - - Order memory order = orders[asks[_idCollection][_idNFT]]; + } + function buy (address _idCollection, uint256 _idNFT ) public payable returns (bool result) { //buing for UNQ like as ethers + + Order memory order = orders[asks[_idCollection][_idNFT]]; //1. check sent amount and send to seller - require( - msg.value == order.price, - "Not right amount sent, have to be equal price" - ); + require (msg.value == order.price, "Not right amount sent, have to be equal price" ); // 2. close order - orders[asks[_idCollection][_idNFT]].flagActive = 0; - + orders[ asks[_idCollection][_idNFT]].flagActive = 0; + // 3. transfer NFT to buyer - UniqueNFT(_idCollection).transferFrom( - address(this), - msg.sender, - _idNFT - ); + UniqueNFT(_idCollection).transferFrom(address(this), msg.sender, _idNFT); //uint balance = address(this).balance; - result = payable(order.ownerAddr).send(order.price); - emit BoughtNFT( - _idCollection, - _idNFT, - asks[_idCollection][_idNFT], - order.price - ); + result = payable(order.ownerAddr).send (order.price); + emit BoughtNFT(_idCollection, _idNFT, asks[_idCollection][_idNFT], order.price); + } - /* - function buyOther (address _idCollection, uint256 _idNFT, address _currencyCode, uint _amount ) public { //buy for sny token if seller wants +/* + function buyOther (address _idCollection, uint256 _idNFT, address _currencyCode, uint _amount ) public { //buy for sny token if seller wants + + Order memory order = orders[ asks[_idCollection][_idNFT]]; + //1. check sent amount and transfer from buyer to seller + require (order.price == _amount && order.currencyCode == _currencyCode, "Not right amount or currency sent, have to be equal currency and price" ); + // !!! transfer have to be approved to marketplace! + UniqueFungible(order.currencyCode).transferFrom(msg.sender, address(this), order.price); //to not disclojure buyer's address + UniqueFungible(order.currencyCode).transfer(order.ownerAddr, order.price); + // 2. close order + orders[ asks[_idCollection][_idNFT]].flagActive = 0; + // 3. transfer NFT to buyer + UniqueNFT(_idCollection).transferFrom(address(this), msg.sender, _idNFT); - Order memory order = orders[ asks[_idCollection][_idNFT]]; - //1. check sent amount and transfer from buyer to seller - require (order.price == _amount && order.currencyCode == _currencyCode, "Not right amount or currency sent, have to be equal currency and price" ); - // !!! transfer have to be approved to marketplace! - IERC20(order.currencyCode).transferFrom(msg.sender, address(this), order.price); //to not disclojure buyer's address - IERC20(order.currencyCode).transfer(order.ownerAddr, order.price); - // 2. close order - orders[ asks[_idCollection][_idNFT]].flagActive = 0; - // 3. transfer NFT to buyer - IERC721ext(_idCollection).transferFrom(address(this), msg.sender, _idNFT); + } + */ - } - */ + function withdrawAllKSM (address _sender) public nonReentrant returns (uint lastBalance ){ + require(isEscrow[msg.sender] || msg.sender == _sender, "Only escrow or balance owner can withdraw all KSM" ); - function withdrawAllKSM(address _sender) - public - onlyEscrow - returns (uint256 lastBalance) - { lastBalance = balanceKSM[_sender]; - balanceKSM[_sender] = 0; + balanceKSM[_sender] =0; emit WithdrawnAllKSM(_sender, lastBalance); } - function withdraw( - uint256 _amount, - address _currencyCode, - address payable _sender - ) public onlyOwner returns (bool result) { - if (_currencyCode != nativecoin) { - //erc20 compat. tokens on UNIQUE chain - // uint balance = IERC20(_currencyCode).balanceOf(address(this)); + function withdrawKSM (uint _amount, address _sender) onlyEscrow public { + balanceKSM[_sender] = balanceKSM[_sender] - _amount; + emit WithdrawnKSM(_sender, balanceKSM[_sender]); + + } + + function withdraw (uint256 _amount, address _currencyCode) public nonReentrant returns (bool result ){ //onlyOwner + address payable _sender = payable( msg.sender); + if (_currencyCode != nativecoin ) { //erc20 compat. tokens on UNIQUE chain + // uint balance = UniqueFungible(_currencyCode).balanceOf(address(this)); UniqueFungible(_currencyCode).transfer(_sender, _amount); } else { // uint balance = address(this).balance; - result = (_sender).send(_amount); // for UNQ like as ethers + result = (_sender).send(_amount); // for UNQ like as ethers } emit Withdrawn(_amount, _currencyCode, _sender); return result; + } - // event GettedOrder(uint , Order); - function getOrder(address _idCollection, uint256 _idNFT) - public - view - returns (Order memory) - { - uint256 orderId = asks[_idCollection][_idNFT]; + + // event GettedOrder(uint , Order); + function getOrder (address _idCollection, uint256 _idNFT) public view returns (Order memory) { + uint orderId = asks[_idCollection][_idNFT]; Order memory order = orders[orderId]; - // emit GettedOrder (orderId, order); + // emit GettedOrder (orderId, order); return order; } - function getOrdersLen() public view returns (uint256) { + function getOrdersLen () public view returns (uint) { return orders.length; } + + function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) public pure returns(bytes4) { + return bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")); + } + + //TODO make destructing function to return all + function terminate(address[] calldata tokens, NFT[] calldata nfts) public onlyOwner { + // Transfer tokens to owner (TODO: error handling) + for (uint i = 0; i < tokens.length; i++) { + address addr = tokens[i]; + UniqueFungible token = UniqueFungible(addr); + uint256 balance = token.balanceOf(address(this)); + token.transfer(owner, balance); + } + for (uint i = 0; i < nfts.length; i++) { + address addr = nfts[i].collection; + UniqueNFT token = UniqueNFT(addr); + token.transferFrom(address(this), owner, nfts[i].id); + } + // Transfer Eth to owner and terminate contract + address payable owner1 = payable (owner); + uint balance = address(this).balance; + owner1.transfer(balance); + + } + } diff --git a/tests/src/eth/marketplace/marketplace.test.ts b/tests/src/eth/marketplace/marketplace.test.ts index 90ce502dd3..c7fd30d522 100644 --- a/tests/src/eth/marketplace/marketplace.test.ts +++ b/tests/src/eth/marketplace/marketplace.test.ts @@ -30,7 +30,7 @@ describe('Matcher contract usage', () => { before(async () => { await usingEthPlaygrounds(async (_helper, privateKey) => { donor = await privateKey({filename: __filename}); - }); + }); }); beforeEach(async () => { @@ -46,26 +46,21 @@ describe('Matcher contract usage', () => { }); itEth('With UNQ', async ({helper}) => { - const web3 = helper.getWeb3(); const matcherOwner = await helper.eth.createAccountWithBalance(donor); - const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, { - from: matcherOwner, - gas: helper.eth.DEFAULT_GAS, - }); - const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner}); + const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${__dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${__dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2); const sponsor = await helper.eth.createAccountWithBalance(donor); - const helpers = helper.ethNativeContract.contractHelpers(matcherOwner); + const helpers = await helper.ethNativeContract.contractHelpers(matcherOwner); await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner}); await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner}); - + await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner}); await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor}); const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}, pendingSponsor: alice.address}); await collection.confirmSponsorship(alice); await collection.addToAllowList(alice, {Substrate: aliceDoubleMirror}); - const evmCollection = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft'); + const evmCollection = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft'); await helper.eth.transferBalanceFromSubstrate(donor, aliceMirror); await helpers.methods.toggleAllowed(matcher.options.address, aliceMirror, true).send({from: matcherOwner}); @@ -103,28 +98,23 @@ describe('Matcher contract usage', () => { }); itEth('With escrow', async ({helper}) => { - const web3 = helper.getWeb3(); const matcherOwner = await helper.eth.createAccountWithBalance(donor); - const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, { - from: matcherOwner, - gas: helper.eth.DEFAULT_GAS, - }); - const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner, gas: 10000000}); + const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${__dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${__dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2); const sponsor = await helper.eth.createAccountWithBalance(donor); const escrow = await helper.eth.createAccountWithBalance(donor); - await matcher.methods.setEscrow(escrow).send({from: matcherOwner}); - const helpers = helper.ethNativeContract.contractHelpers(matcherOwner); + await matcher.methods.setEscrow(escrow, true).send({from: matcherOwner}); + const helpers = await helper.ethNativeContract.contractHelpers(matcherOwner); await helpers.methods.setSponsoringMode(matcher.options.address, SponsoringMode.Allowlisted).send({from: matcherOwner}); await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner}); - + await helpers.methods.setSponsor(matcher.options.address, sponsor).send({from: matcherOwner}); await helpers.methods.confirmSponsorship(matcher.options.address).send({from: sponsor}); const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}, pendingSponsor: alice.address}); await collection.confirmSponsorship(alice); await collection.addToAllowList(alice, {Substrate: aliceDoubleMirror}); - const evmCollection = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft'); + const evmCollection = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft'); await helper.eth.transferBalanceFromSubstrate(donor, aliceMirror); @@ -172,21 +162,16 @@ describe('Matcher contract usage', () => { }); itEth('Sell tokens from substrate user via EVM contract', async ({helper}) => { - const web3 = helper.getWeb3(); const matcherOwner = await helper.eth.createAccountWithBalance(donor); - const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, { - from: matcherOwner, - gas: helper.eth.DEFAULT_GAS, - }); - const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner}); + const matcher = await helper.ethContract.deployByCode(matcherOwner, 'MarketPlace', (await readFile(`${__dirname}/MarketPlace.sol`)).toString(), [{solPath: 'api/UniqueNFT.sol', fsPath: `${__dirname}/../api/UniqueNFT.sol`}], helper.eth.DEFAULT_GAS * 2); await helper.eth.transferBalanceFromSubstrate(donor, matcher.options.address); const collection = await helper.nft.mintCollection(alice, {limits: {sponsorApproveTimeout: 1}}); - const evmCollection = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft'); + const evmCollection = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft'); await helper.balance.transferToSubstrate(donor, seller.address, 100_000_000_000_000_000_000n); - + const token = await collection.mintToken(alice, {Ethereum: sellerMirror}); // Token is owned by seller initially diff --git a/tests/src/eth/migration.test.ts b/tests/src/eth/migration.seqtest.ts similarity index 99% rename from tests/src/eth/migration.test.ts rename to tests/src/eth/migration.seqtest.ts index efbc426612..55a5d7b01d 100644 --- a/tests/src/eth/migration.test.ts +++ b/tests/src/eth/migration.seqtest.ts @@ -165,7 +165,7 @@ describe('EVM Migrations', () => { const collection = await helper.nft.mintCollection(superuser); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); const caller = await helper.eth.createAccountWithBalance(superuser); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller); const events: any = []; contract.events.allEvents((_: any, event: any) => { diff --git a/tests/src/eth/nesting/nest.test.ts b/tests/src/eth/nesting/nest.test.ts index 73a0d938f3..3daceab582 100644 --- a/tests/src/eth/nesting/nest.test.ts +++ b/tests/src/eth/nesting/nest.test.ts @@ -9,7 +9,7 @@ const createNestingCollection = async ( ): Promise<{ collectionId: number, collectionAddress: string, contract: Contract }> => { const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); await contract.methods.setCollectionNesting(true).send({from: owner}); return {collectionId, collectionAddress, contract}; @@ -52,6 +52,21 @@ describe('EVM nesting tests group', () => { expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner); }); + itEth('NFT: collectionNestingRestrictedCollectionIds() & collectionNestingPermissions', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionId: unnestedCollsectionId, collectionAddress: unnsetedCollectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C'); + const unnestedContract = await helper.ethNativeContract.collection(unnsetedCollectionAddress, 'nft', owner); + expect(await unnestedContract.methods.collectionNestingRestrictedCollectionIds().call({from: owner})).to.be.like([false, []]); + + const {contract} = await createNestingCollection(helper, owner); + expect(await contract.methods.collectionNestingRestrictedCollectionIds().call({from: owner})).to.be.like([true, []]); + await contract.methods.setCollectionNesting(true, [unnsetedCollectionAddress]).send({from: owner}); + expect(await contract.methods.collectionNestingRestrictedCollectionIds().call({from: owner})).to.be.like([true, [unnestedCollsectionId.toString()]]); + expect(await contract.methods.collectionNestingPermissions().call({from: owner})).to.be.like([['1', false], ['0', true]]); + await contract.methods.setCollectionNesting(false).send({from: owner}); + expect(await contract.methods.collectionNestingPermissions().call({from: owner})).to.be.like([['1', false], ['0', false]]); + }); + itEth('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); diff --git a/tests/src/eth/nonFungible.test.ts b/tests/src/eth/nonFungible.test.ts index 23c420f03e..e124136839 100644 --- a/tests/src/eth/nonFungible.test.ts +++ b/tests/src/eth/nonFungible.test.ts @@ -17,6 +17,7 @@ import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util'; import {IKeyringPair} from '@polkadot/types/types'; import {Contract} from 'web3-eth-contract'; +import {ITokenPropertyPermission} from '../util/playgrounds/types'; describe('NFT: Information getting', () => { @@ -36,7 +37,7 @@ describe('NFT: Information getting', () => { const caller = await helper.eth.createAccountWithBalance(donor); - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); + const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); const totalSupply = await contract.methods.totalSupply().call(); expect(totalSupply).to.equal('1'); @@ -50,7 +51,7 @@ describe('NFT: Information getting', () => { await collection.mintToken(alice, {Ethereum: caller}); await collection.mintToken(alice, {Ethereum: caller}); - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); + const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); const balance = await contract.methods.balanceOf(caller).call(); expect(balance).to.equal('3'); @@ -62,7 +63,7 @@ describe('NFT: Information getting', () => { const token = await collection.mintToken(alice, {Ethereum: caller}); - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); + const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); const owner = await contract.methods.ownerOf(token.tokenId).call(); @@ -73,7 +74,7 @@ describe('NFT: Information getting', () => { const collection = await helper.nft.mintCollection(alice, {name: 'test', tokenPrefix: 'TEST'}); const caller = helper.eth.createAccount(); - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); + const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); expect(await contract.methods.name().call()).to.equal('test'); expect(await contract.methods.symbol().call()).to.equal('TEST'); @@ -94,7 +95,7 @@ describe('Check ERC721 token URI for NFT', () => { const receiver = helper.eth.createAccount(); const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', 'a', 'b', baseUri); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); const result = await contract.methods.mint(receiver).send(); const tokenId = result.events.Transfer.returnValues.tokenId; @@ -102,7 +103,7 @@ describe('Check ERC721 token URI for NFT', () => { if (propertyKey && propertyValue) { // Set URL or suffix - await contract.methods.setProperty(tokenId, propertyKey, Buffer.from(propertyValue)).send(); + await contract.methods.setProperties(tokenId, [{key: propertyKey, value: Buffer.from(propertyValue)}]).send(); } const event = result.events.Transfer; @@ -138,22 +139,23 @@ describe('Check ERC721 token URI for NFT', () => { describe('NFT: Plain calls', () => { let donor: IKeyringPair; - let alice: IKeyringPair; let minter: IKeyringPair; + let bob: IKeyringPair; + let charlie: IKeyringPair; before(async function() { await usingEthPlaygrounds(async (helper, privateKey) => { donor = await privateKey({filename: __filename}); - [alice, minter] = await helper.arrange.createAccounts([10n, 100n], donor); + [minter, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); }); - itEth('Can perform mint()', async ({helper}) => { + itEth('Can perform mint() & get crossOwner()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', '6', '6', ''); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); const result = await contract.methods.mintWithTokenURI(receiver, 'Test URI').send(); const tokenId = result.events.Transfer.returnValues.tokenId; @@ -165,23 +167,100 @@ describe('NFT: Plain calls', () => { expect(event.returnValues.to).to.be.equal(receiver); expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); - + expect(await contract.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']); // TODO: this wont work right now, need release 919000 first // await helper.methods.setOffchainSchema(collectionIdAddress, 'https://offchain-service.local/token-info/{id}').send(); // const tokenUri = await contract.methods.tokenURI(nextTokenId).call(); // expect(tokenUri).to.be.equal(`https://offchain-service.local/token-info/${nextTokenId}`); }); + // TODO combine all minting tests in one place + [ + 'substrate' as const, + 'ethereum' as const, + ].map(testCase => { + itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => { + const collectionAdmin = await helper.eth.createAccountWithBalance(donor); + + const receiverEth = helper.eth.createAccount(); + const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth); + const receiverSub = bob; + const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub); + + // const receiverCross = helper.ethCrossAccount.fromKeyringPair(bob); + const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; }); + const permissions: ITokenPropertyPermission[] = properties + .map(p => { + return { + key: p.key, permission: { + tokenOwner: false, + collectionAdmin: true, + mutable: false, + }, + }; + }); + + const collection = await helper.nft.mintCollection(minter, { + tokenPrefix: 'ethp', + tokenPropertyPermissions: permissions, + }); + await collection.addAdmin(minter, {Ethereum: collectionAdmin}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', collectionAdmin, true); + let expectedTokenId = await contract.methods.nextTokenId().call(); + let result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, []).send(); + let tokenId = result.events.Transfer.returnValues.tokenId; + expect(tokenId).to.be.equal(expectedTokenId); + + let event = result.events.Transfer; + expect(event.address).to.be.equal(collectionAddress); + expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000'); + expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address)); + expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]); + + expectedTokenId = await contract.methods.nextTokenId().call(); + result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, properties).send(); + event = result.events.Transfer; + expect(event.address).to.be.equal(collectionAddress); + expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000'); + expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address)); + expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]); + + tokenId = result.events.Transfer.returnValues.tokenId; + + expect(tokenId).to.be.equal(expectedTokenId); + + expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties + .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); })); + + expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId)) + .to.deep.eq(testCase === 'ethereum' ? {Ethereum: receiverEth.toLowerCase()} : {Substrate: receiverSub.address}); + }); + }); + + itEth('Non-owner and non admin cannot mintCross', async ({helper}) => { + const nonOwner = await helper.eth.createAccountWithBalance(donor); + const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner); + + const collection = await helper.nft.mintCollection(minter); + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft'); + + await expect(collectionEvm.methods.mintCross(nonOwnerCross, []).call({from: nonOwner})) + .to.be.rejectedWith('PublicMintingNotAllowed'); + }); + //TODO: CORE-302 add eth methods itEth.skip('Can perform mintBulk()', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const collection = await helper.nft.mintCollection(alice); - await collection.addAdmin(alice, {Ethereum: caller}); + const collection = await helper.nft.mintCollection(minter); + await collection.addAdmin(minter, {Ethereum: caller}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller); { const bulkSize = 3; const nextTokenId = await contract.methods.nextTokenId().call(); @@ -209,11 +288,11 @@ describe('NFT: Plain calls', () => { itEth('Can perform burn()', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); - const collection = await helper.nft.mintCollection(alice, {}); - const {tokenId} = await collection.mintToken(alice, {Ethereum: caller}); + const collection = await helper.nft.mintCollection(minter, {}); + const {tokenId} = await collection.mintToken(minter, {Ethereum: caller}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller); { const result = await contract.methods.burn(tokenId).send({from: caller}); @@ -230,11 +309,11 @@ describe('NFT: Plain calls', () => { const owner = await helper.eth.createAccountWithBalance(donor); const spender = helper.eth.createAccount(); - const collection = await helper.nft.mintCollection(alice, {}); - const {tokenId} = await collection.mintToken(alice, {Ethereum: owner}); + const collection = await helper.nft.mintCollection(minter, {}); + const {tokenId} = await collection.mintToken(minter, {Ethereum: owner}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); { const result = await contract.methods.approve(spender, tokenId).send({from: owner}); @@ -247,16 +326,260 @@ describe('NFT: Plain calls', () => { } }); + itEth('Can perform setApprovalForAll()', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const operator = helper.eth.createAccount(); + + const collection = await helper.nft.mintCollection(minter, {}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + + const approvedBefore = await contract.methods.isApprovedForAll(owner, operator).call(); + expect(approvedBefore).to.be.equal(false); + + { + const result = await contract.methods.setApprovalForAll(operator, true).send({from: owner}); + + expect(result.events.ApprovalForAll).to.be.like({ + address: collectionAddress, + event: 'ApprovalForAll', + returnValues: { + owner, + operator, + approved: true, + }, + }); + + const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call(); + expect(approvedAfter).to.be.equal(true); + } + + { + const result = await contract.methods.setApprovalForAll(operator, false).send({from: owner}); + + expect(result.events.ApprovalForAll).to.be.like({ + address: collectionAddress, + event: 'ApprovalForAll', + returnValues: { + owner, + operator, + approved: false, + }, + }); + + const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call(); + expect(approvedAfter).to.be.equal(false); + } + }); + + itEth('Can perform burn with ApprovalForAll', async ({helper}) => { + const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + + const owner = await helper.eth.createAccountWithBalance(donor); + const operator = await helper.eth.createAccountWithBalance(donor, 100n); + + const token = await collection.mintToken(minter, {Ethereum: owner}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'nft'); + + { + await contract.methods.setApprovalForAll(operator, true).send({from: owner}); + const ownerCross = helper.ethCrossAccount.fromAddress(owner); + const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: operator}); + const events = result.events.Transfer; + + expect(events).to.be.like({ + address, + event: 'Transfer', + returnValues: { + from: owner, + to: '0x0000000000000000000000000000000000000000', + tokenId: token.tokenId.toString(), + }, + }); + } + + expect(await helper.nft.doesTokenExist(collection.collectionId, token.tokenId)).to.be.false; + }); + + itEth('Can perform transfer with ApprovalForAll', async ({helper}) => { + const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + + const owner = await helper.eth.createAccountWithBalance(donor); + const operator = await helper.eth.createAccountWithBalance(donor); + const receiver = charlie; + + const token = await collection.mintToken(minter, {Ethereum: owner}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'nft'); + + { + await contract.methods.setApprovalForAll(operator, true).send({from: owner}); + const ownerCross = helper.ethCrossAccount.fromAddress(owner); + const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver); + const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: operator}); + const event = result.events.Transfer; + expect(event).to.be.like({ + address: helper.ethAddress.fromCollectionId(collection.collectionId), + event: 'Transfer', + returnValues: { + from: owner, + to: helper.address.substrateToEth(receiver.address), + tokenId: token.tokenId.toString(), + }, + }); + } + + expect(await token.getOwner()).to.be.like({Substrate: receiver.address}); + }); + + itEth('Can perform burnFromCross()', async ({helper}) => { + const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + const ownerSub = bob; + const ownerCrossSub = helper.ethCrossAccount.fromKeyringPair(ownerSub); + const ownerEth = await helper.eth.createAccountWithBalance(donor, 100n); + const ownerCrossEth = helper.ethCrossAccount.fromAddress(ownerEth); + + const burnerEth = await helper.eth.createAccountWithBalance(donor, 100n); + const burnerCrossEth = helper.ethCrossAccount.fromAddress(burnerEth); + + const token1 = await collection.mintToken(minter, {Substrate: ownerSub.address}); + const token2 = await collection.mintToken(minter, {Ethereum: ownerEth}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft'); + + // Approve tokens from substrate and ethereum: + await token1.approve(ownerSub, {Ethereum: burnerEth}); + await collectionEvm.methods.approveCross(burnerCrossEth, token2.tokenId).send({from: ownerEth}); + + // can burnFromCross: + const result1 = await collectionEvm.methods.burnFromCross(ownerCrossSub, token1.tokenId).send({from: burnerEth}); + const result2 = await collectionEvm.methods.burnFromCross(ownerCrossEth, token2.tokenId).send({from: burnerEth}); + const events1 = result1.events.Transfer; + const events2 = result2.events.Transfer; + + // Check events for burnFromCross (substrate and ethereum): + [ + [events1, token1, helper.address.substrateToEth(ownerSub.address)], + [events2, token2, ownerEth], + ].map(burnData => { + expect(burnData[0]).to.be.like({ + address: collectionAddress, + event: 'Transfer', + returnValues: { + from: burnData[2], + to: '0x0000000000000000000000000000000000000000', + tokenId: burnData[1].tokenId.toString(), + }, + }); + }); + + expect(await token1.doesExist()).to.be.false; + expect(await token2.doesExist()).to.be.false; + }); + + // TODO combine all approve tests in one place + itEth('Can perform approveCross()', async ({helper}) => { + // arrange: create accounts + const owner = await helper.eth.createAccountWithBalance(donor, 100n); + const ownerCross = helper.ethCrossAccount.fromAddress(owner); + const receiverSub = charlie; + const recieverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub); + const receiverEth = await helper.eth.createAccountWithBalance(donor, 100n); + const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth); + + // arrange: create collection and tokens: + const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + const token1 = await collection.mintToken(minter, {Ethereum: owner}); + const token2 = await collection.mintToken(minter, {Ethereum: owner}); + + const collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft'); + + // Can approveCross substrate and ethereum address: + const resultSub = await collectionEvm.methods.approveCross(recieverCrossSub, token1.tokenId).send({from: owner}); + const resultEth = await collectionEvm.methods.approveCross(receiverCrossEth, token2.tokenId).send({from: owner}); + const eventSub = resultSub.events.Approval; + const eventEth = resultEth.events.Approval; + expect(eventSub).to.be.like({ + address: helper.ethAddress.fromCollectionId(collection.collectionId), + event: 'Approval', + returnValues: { + owner, + approved: helper.address.substrateToEth(receiverSub.address), + tokenId: token1.tokenId.toString(), + }, + }); + expect(eventEth).to.be.like({ + address: helper.ethAddress.fromCollectionId(collection.collectionId), + event: 'Approval', + returnValues: { + owner, + approved: receiverEth, + tokenId: token2.tokenId.toString(), + }, + }); + + // Substrate address can transferFrom approved tokens: + await helper.nft.transferTokenFrom(receiverSub, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiverSub.address}); + expect(await helper.nft.getTokenOwner(collection.collectionId, token1.tokenId)).to.deep.eq({Substrate: receiverSub.address}); + // Ethereum address can transferFromCross approved tokens: + await collectionEvm.methods.transferFromCross(ownerCross, receiverCrossEth, token2.tokenId).send({from: receiverEth}); + expect(await helper.nft.getTokenOwner(collection.collectionId, token2.tokenId)).to.deep.eq({Ethereum: receiverEth.toLowerCase()}); + }); + + itEth('Non-owner and non admin cannot approveCross', async ({helper}) => { + const nonOwner = await helper.eth.createAccountWithBalance(donor); + const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner); + const owner = await helper.eth.createAccountWithBalance(donor); + const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + const collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft'); + const token = await collection.mintToken(minter, {Ethereum: owner}); + + await expect(collectionEvm.methods.approveCross(nonOwnerCross, token.tokenId).call({from: nonOwner})).to.be.rejectedWith('CantApproveMoreThanOwned'); + }); + + itEth('Can reaffirm approved address', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor, 100n); + const ownerCrossEth = helper.ethCrossAccount.fromAddress(owner); + const [receiver1, receiver2] = await helper.arrange.createAccounts([100n, 100n], donor); + const receiver1Cross = helper.ethCrossAccount.fromKeyringPair(receiver1); + const receiver2Cross = helper.ethCrossAccount.fromKeyringPair(receiver2); + const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + const token1 = await collection.mintToken(minter, {Ethereum: owner}); + const token2 = await collection.mintToken(minter, {Ethereum: owner}); + const collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft'); + + // Can approve and reaffirm approved address: + await collectionEvm.methods.approveCross(receiver1Cross, token1.tokenId).send({from: owner}); + await collectionEvm.methods.approveCross(receiver2Cross, token1.tokenId).send({from: owner}); + + // receiver1 cannot transferFrom: + await expect(helper.nft.transferTokenFrom(receiver1, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiver1.address})).to.be.rejected; + // receiver2 can transferFrom: + await helper.nft.transferTokenFrom(receiver2, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiver2.address}); + + // can set approved address to self address to remove approval: + await collectionEvm.methods.approveCross(receiver1Cross, token2.tokenId).send({from: owner}); + await collectionEvm.methods.approveCross(ownerCrossEth, token2.tokenId).send({from: owner}); + + // receiver1 cannot transfer token anymore: + await expect(helper.nft.transferTokenFrom(receiver1, collection.collectionId, token2.tokenId, {Ethereum: owner}, {Substrate: receiver1.address})).to.be.rejected; + }); + itEth('Can perform transferFrom()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const spender = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const collection = await helper.nft.mintCollection(alice, {}); - const {tokenId} = await collection.mintToken(alice, {Ethereum: owner}); + const collection = await helper.nft.mintCollection(minter, {}); + const {tokenId} = await collection.mintToken(minter, {Ethereum: owner}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); await contract.methods.approve(spender, tokenId).send({from: owner}); @@ -281,15 +604,47 @@ describe('NFT: Plain calls', () => { } }); + itEth('Can perform transferFromCross()', async ({helper}) => { + const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + + const [owner, receiver] = await helper.arrange.createAccounts([100n, 100n], donor); + const spender = await helper.eth.createAccountWithBalance(donor); + + const token = await collection.mintToken(minter, {Substrate: owner.address}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'nft'); + + await token.approve(owner, {Ethereum: spender}); + + { + const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner); + const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver); + const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender}); + const event = result.events.Transfer; + expect(event).to.be.like({ + address: helper.ethAddress.fromCollectionId(collection.collectionId), + event: 'Transfer', + returnValues: { + from: helper.address.substrateToEth(owner.address), + to: helper.address.substrateToEth(receiver.address), + tokenId: token.tokenId.toString(), + }, + }); + } + + expect(await token.getOwner()).to.be.like({Substrate: receiver.address}); + }); + itEth('Can perform transfer()', async ({helper}) => { - const collection = await helper.nft.mintCollection(alice, {}); + const collection = await helper.nft.mintCollection(minter, {}); const owner = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const {tokenId} = await collection.mintToken(alice, {Ethereum: owner}); + const {tokenId} = await collection.mintToken(minter, {Ethereum: owner}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); { const result = await contract.methods.transfer(receiver, tokenId).send({from: owner}); @@ -312,34 +667,87 @@ describe('NFT: Plain calls', () => { } }); - itEth('Cannot transfer non-owned token', async ({helper}) => { + itEth('Can perform transferCross()', async ({helper}) => { + const collection = await helper.nft.mintCollection(minter, {}); + const owner = await helper.eth.createAccountWithBalance(donor); + const receiverEth = await helper.eth.createAccountWithBalance(donor); + const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth); + const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter); + + const {tokenId} = await collection.mintToken(minter, {Ethereum: owner}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + + { + // Can transferCross to ethereum address: + const result = await collectionEvm.methods.transferCross(receiverCrossEth, tokenId).send({from: owner}); + // Check events: + const event = result.events.Transfer; + expect(event.address).to.be.equal(collectionAddress); + expect(event.returnValues.from).to.be.equal(owner); + expect(event.returnValues.to).to.be.equal(receiverEth); + expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`); + + // owner has balance = 0: + const ownerBalance = await collectionEvm.methods.balanceOf(owner).call(); + expect(+ownerBalance).to.equal(0); + // receiver owns token: + const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call(); + expect(+receiverBalance).to.equal(1); + expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId)).to.deep.eq({Ethereum: receiverEth.toLowerCase()}); + } + + { + // Can transferCross to substrate address: + const substrateResult = await collectionEvm.methods.transferCross(receiverCrossSub, tokenId).send({from: receiverEth}); + // Check events: + const event = substrateResult.events.Transfer; + expect(event.address).to.be.equal(collectionAddress); + expect(event.returnValues.from).to.be.equal(receiverEth); + expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(minter.address)); + expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`); + + // owner has balance = 0: + const ownerBalance = await collectionEvm.methods.balanceOf(receiverEth).call(); + expect(+ownerBalance).to.equal(0); + // receiver owns token: + const receiverBalance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address}); + expect(receiverBalance).to.contain(tokenId); + } + }); + + ['transfer', 'transferCross'].map(testCase => itEth(`Cannot ${testCase} non-owned token`, async ({helper}) => { const sender = await helper.eth.createAccountWithBalance(donor); const tokenOwner = await helper.eth.createAccountWithBalance(donor); const receiverSub = minter; + const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter); const collection = await helper.nft.mintCollection(minter, {}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', sender); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', sender); await collection.mintToken(minter, {Ethereum: sender}); const nonSendersToken = await collection.mintToken(minter, {Ethereum: tokenOwner}); // Cannot transferCross someone else's token: - const receiver = helper.address.substrateToEth(receiverSub.address); - await expect(collectionEvm.methods.transfer(receiver, nonSendersToken.tokenId).send({from: sender})).to.be.rejected; + const receiver = testCase === 'transfer' ? helper.address.substrateToEth(receiverSub.address) : receiverCrossSub; + await expect(collectionEvm.methods[testCase](receiver, nonSendersToken.tokenId).send({from: sender})).to.be.rejected; // Cannot transfer token if it does not exist: - await expect(collectionEvm.methods.transfer(receiver, 999999).send({from: sender})).to.be.rejected; - }); + await expect(collectionEvm.methods[testCase](receiver, 999999).send({from: sender})).to.be.rejected; + })); }); describe('NFT: Fees', () => { let donor: IKeyringPair; let alice: IKeyringPair; + let bob: IKeyringPair; + let charlie: IKeyringPair; before(async function() { await usingEthPlaygrounds(async (helper, privateKey) => { donor = await privateKey({filename: __filename}); - [alice] = await helper.arrange.createAccounts([10n], donor); + [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor); }); }); @@ -350,7 +758,7 @@ describe('NFT: Fees', () => { const collection = await helper.nft.mintCollection(alice, {}); const {tokenId} = await collection.mintToken(alice, {Ethereum: owner}); - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner); + const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner); const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, tokenId).send({from: owner})); expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))); @@ -363,7 +771,7 @@ describe('NFT: Fees', () => { const collection = await helper.nft.mintCollection(alice, {}); const {tokenId} = await collection.mintToken(alice, {Ethereum: owner}); - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner); + const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner); await contract.methods.approve(spender, tokenId).send({from: owner}); @@ -371,6 +779,40 @@ describe('NFT: Fees', () => { expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))); }); + itEth('Can perform transferFromCross()', async ({helper}) => { + const collectionMinter = alice; + const owner = bob; + const receiver = charlie; + const collection = await helper.nft.mintCollection(collectionMinter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + + const spender = await helper.eth.createAccountWithBalance(donor, 100n); + + const token = await collection.mintToken(collectionMinter, {Substrate: owner.address}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'nft'); + + await token.approve(owner, {Ethereum: spender}); + + { + const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner); + const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver); + const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender}); + const event = result.events.Transfer; + expect(event).to.be.like({ + address: helper.ethAddress.fromCollectionId(collection.collectionId), + event: 'Transfer', + returnValues: { + from: helper.address.substrateToEth(owner.address), + to: helper.address.substrateToEth(receiver.address), + tokenId: token.tokenId.toString(), + }, + }); + } + + expect(await token.getOwner()).to.be.like({Substrate: receiver.address}); + }); + itEth('transfer() call fee is less than 0.2UNQ', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); @@ -378,7 +820,7 @@ describe('NFT: Fees', () => { const collection = await helper.nft.mintCollection(alice, {}); const {tokenId} = await collection.mintToken(alice, {Ethereum: owner}); - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner); + const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', owner); const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, tokenId).send({from: owner})); expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))); @@ -399,7 +841,7 @@ describe('NFT: Substrate calls', () => { itEth('Events emitted for mint()', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft'); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft'); const events: any = []; contract.events.allEvents((_: any, event: any) => { @@ -422,7 +864,7 @@ describe('NFT: Substrate calls', () => { const token = await collection.mintToken(alice); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft'); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft'); const events: any = []; contract.events.allEvents((_: any, event: any) => { @@ -447,7 +889,7 @@ describe('NFT: Substrate calls', () => { const token = await collection.mintToken(alice); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft'); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft'); const events: any = []; contract.events.allEvents((_: any, event: any) => { @@ -474,7 +916,7 @@ describe('NFT: Substrate calls', () => { await token.approve(alice, {Substrate: bob.address}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft'); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft'); const events: any = []; contract.events.allEvents((_: any, event: any) => { @@ -499,7 +941,7 @@ describe('NFT: Substrate calls', () => { const token = await collection.mintToken(alice); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft'); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft'); const events: any = []; contract.events.allEvents((_: any, event: any) => { @@ -549,7 +991,7 @@ describe('Common metadata', () => { }, ); - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); + const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); const name = await contract.methods.name().call(); expect(name).to.equal('oh River'); }); @@ -574,8 +1016,64 @@ describe('Common metadata', () => { }, ); - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); + const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller); const symbol = await contract.methods.symbol().call(); expect(symbol).to.equal('CHANGE'); }); }); + +describe('Negative tests', () => { + let donor: IKeyringPair; + let minter: IKeyringPair; + let alice: IKeyringPair; + + before(async function() { + await usingEthPlaygrounds(async (helper, privateKey) => { + donor = await privateKey({filename: __filename}); + [minter, alice] = await helper.arrange.createAccounts([100n, 100n], donor); + }); + }); + + itEth('[negative] Cant perform burn without approval', async ({helper}) => { + const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + + const owner = await helper.eth.createAccountWithBalance(donor, 100n); + const spender = await helper.eth.createAccountWithBalance(donor, 100n); + + const token = await collection.mintToken(minter, {Ethereum: owner}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'nft'); + + const ownerCross = helper.ethCrossAccount.fromAddress(owner); + await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected; + + await contract.methods.setApprovalForAll(spender, true).send({from: owner}); + await contract.methods.setApprovalForAll(spender, false).send({from: owner}); + + await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected; + }); + + itEth('[negative] Cant perform transfer without approval', async ({helper}) => { + const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + const receiver = alice; + + const owner = await helper.eth.createAccountWithBalance(donor, 100n); + const spender = await helper.eth.createAccountWithBalance(donor, 100n); + + const token = await collection.mintToken(minter, {Ethereum: owner}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'nft'); + + const ownerCross = helper.ethCrossAccount.fromAddress(owner); + const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver); + + await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected; + + await contract.methods.setApprovalForAll(spender, true).send({from: owner}); + await contract.methods.setApprovalForAll(spender, false).send({from: owner}); + + await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected; + }); +}); diff --git a/tests/src/eth/nonFungibleAbi.json b/tests/src/eth/nonFungibleAbi.json deleted file mode 100644 index bebf71ba9e..0000000000 --- a/tests/src/eth/nonFungibleAbi.json +++ /dev/null @@ -1,562 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "approved", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "ApprovalForAll", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "MintingFinished", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [ - { "internalType": "address", "name": "newAdmin", "type": "address" } - ], - "name": "addCollectionAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "user", "type": "address" } - ], - "name": "addToCollectionAllowList", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "user", "type": "address" } - ], - "name": "allowed", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "approved", "type": "address" }, - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "approve", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "owner", "type": "address" } - ], - "name": "balanceOf", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "burn", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "from", "type": "address" }, - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "burnFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "newOwner", "type": "address" } - ], - "name": "changeCollectionOwner", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "collectionOwner", - "outputs": [ - { - "components": [ - { "internalType": "address", "name": "field_0", "type": "address" }, - { "internalType": "uint256", "name": "field_1", "type": "uint256" } - ], - "internalType": "struct Tuple17", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], - "name": "collectionProperty", - "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "collectionSponsor", - "outputs": [ - { - "components": [ - { "internalType": "address", "name": "field_0", "type": "address" }, - { "internalType": "uint256", "name": "field_1", "type": "uint256" } - ], - "internalType": "struct Tuple17", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "confirmCollectionSponsorship", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "contractAddress", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "string", "name": "key", "type": "string" }], - "name": "deleteCollectionProperty", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, - { "internalType": "string", "name": "key", "type": "string" } - ], - "name": "deleteProperty", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "finishMinting", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "getApproved", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "hasCollectionPendingSponsor", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "owner", "type": "address" }, - { "internalType": "address", "name": "operator", "type": "address" } - ], - "name": "isApprovedForAll", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "user", "type": "address" } - ], - "name": "isOwnerOrAdmin", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "internalType": "address", "name": "to", "type": "address" }], - "name": "mint", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "string", "name": "tokenUri", "type": "string" } - ], - "name": "mintWithTokenURI", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "mintingFinished", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [{ "internalType": "string", "name": "", "type": "string" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "nextTokenId", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "ownerOf", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, - { "internalType": "string", "name": "key", "type": "string" } - ], - "name": "property", - "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "admin", "type": "address" } - ], - "name": "removeCollectionAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "removeCollectionSponsor", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "user", "type": "address" } - ], - "name": "removeFromCollectionAllowList", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "from", "type": "address" }, - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "from", "type": "address" }, - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, - { "internalType": "bytes", "name": "data", "type": "bytes" } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "operator", "type": "address" }, - { "internalType": "bool", "name": "approved", "type": "bool" } - ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }], - "name": "setCollectionAccess", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "string", "name": "limit", "type": "string" }, - { "internalType": "uint32", "name": "value", "type": "uint32" } - ], - "name": "setCollectionLimit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "string", "name": "limit", "type": "string" }, - { "internalType": "bool", "name": "value", "type": "bool" } - ], - "name": "setCollectionLimit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }], - "name": "setCollectionMintMode", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }], - "name": "setCollectionNesting", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "bool", "name": "enable", "type": "bool" }, - { - "internalType": "address[]", - "name": "collections", - "type": "address[]" - } - ], - "name": "setCollectionNesting", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "string", "name": "key", "type": "string" }, - { "internalType": "bytes", "name": "value", "type": "bytes" } - ], - "name": "setCollectionProperty", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "sponsor", "type": "address" } - ], - "name": "setCollectionSponsor", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, - { "internalType": "string", "name": "key", "type": "string" }, - { "internalType": "bytes", "name": "value", "type": "bytes" } - ], - "name": "setProperty", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "string", "name": "key", "type": "string" }, - { "internalType": "bool", "name": "isMutable", "type": "bool" }, - { "internalType": "bool", "name": "collectionAdmin", "type": "bool" }, - { "internalType": "bool", "name": "tokenOwner", "type": "bool" } - ], - "name": "setTokenPropertyPermission", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" } - ], - "name": "supportsInterface", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [{ "internalType": "string", "name": "", "type": "string" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "index", "type": "uint256" } - ], - "name": "tokenByIndex", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "owner", "type": "address" }, - { "internalType": "uint256", "name": "index", "type": "uint256" } - ], - "name": "tokenOfOwnerByIndex", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "tokenURI", - "outputs": [{ "internalType": "string", "name": "", "type": "string" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "transfer", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "from", "type": "address" }, - { "internalType": "address", "name": "to", "type": "address" }, - { "internalType": "uint256", "name": "tokenId", "type": "uint256" } - ], - "name": "transferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "uniqueCollectionType", - "outputs": [{ "internalType": "string", "name": "", "type": "string" }], - "stateMutability": "view", - "type": "function" - } -] diff --git a/tests/src/eth/payable.test.ts b/tests/src/eth/payable.test.ts index 5b0c014515..32a702d716 100644 --- a/tests/src/eth/payable.test.ts +++ b/tests/src/eth/payable.test.ts @@ -175,7 +175,7 @@ describe('EVM transaction fees', () => { const SMALL_FEE = 1n * helper.balance.getOneTokenNominal(); const BIG_FEE = 3n * helper.balance.getOneTokenNominal(); const caller = await helper.eth.createAccountWithBalance(donor); - const collectionHelper = helper.ethNativeContract.collectionHelpers(caller); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(caller); await expect(collectionHelper.methods.createNFTCollection('A', 'B', 'C').call({value: Number(SMALL_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); await expect(collectionHelper.methods.createNFTCollection('A', 'B', 'C').call({value: Number(BIG_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); @@ -185,7 +185,7 @@ describe('EVM transaction fees', () => { const SMALL_FEE = 1n * helper.balance.getOneTokenNominal(); const BIG_FEE = 3n * helper.balance.getOneTokenNominal(); const caller = await helper.eth.createAccountWithBalance(donor); - const collectionHelper = helper.ethNativeContract.collectionHelpers(caller); + const collectionHelper = await helper.ethNativeContract.collectionHelpers(caller); await expect(collectionHelper.methods.createRFTCollection('A', 'B', 'C').call({value: Number(SMALL_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); await expect(collectionHelper.methods.createRFTCollection('A', 'B', 'C').call({value: Number(BIG_FEE)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)'); diff --git a/tests/src/eth/precompile.test.ts b/tests/src/eth/precompile.test.ts new file mode 100644 index 0000000000..686a770f23 --- /dev/null +++ b/tests/src/eth/precompile.test.ts @@ -0,0 +1,112 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {IKeyringPair} from '@polkadot/types/types'; + +import {expect, itEth, usingEthPlaygrounds} from './util'; + +describe('Precompiles', () => { + let donor: IKeyringPair; + + before(async function() { + await usingEthPlaygrounds(async (_, privateKey) => { + donor = await privateKey({filename: __filename}); + }); + }); + + itEth('ecrecover is supported', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const ecrecoverCompiledСontract = await helper.ethContract.compile( + 'ECRECOVER', + ` + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.17; + + contract ECRECOVER{ + address addressTest = 0x12Cb274aAD8251C875c0bf6872b67d9983E53fDd; + bytes32 msgHash1 = 0xc51dac836bc7841a01c4b631fa620904fc8724d7f9f1d3c420f0e02adf229d50; + bytes32 msgHash2 = 0xc51dac836bc7841a01c4b631fa620904fc8724d7f9f1d3c420f0e02adf229d51; + uint8 v = 0x1b; + bytes32 r = 0x44287513919034a471a7dc2b2ed121f95984ae23b20f9637ba8dff471b6719ef; + bytes32 s = 0x7d7dc30309a3baffbfd9342b97d0e804092c0aeb5821319aa732bc09146eafb4; + + + function verifyValid() public view returns(bool) { + // Use ECRECOVER to verify address + return ecrecover(msgHash1, v, r, s) == (addressTest); + } + + function verifyInvalid() public view returns(bool) { + // Use ECRECOVER to verify address + return ecrecover(msgHash2, v, r, s) == (addressTest); + } + } + `, + ); + + const ecrecoverСontract = await helper.ethContract.deployByAbi(owner, ecrecoverCompiledСontract.abi, ecrecoverCompiledСontract.object); + expect(await ecrecoverСontract.methods.verifyValid().call({from: owner})).to.be.true; + expect(await ecrecoverСontract.methods.verifyInvalid().call({from: owner})).to.be.false; + }); + + itEth('sr25519 is supported', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const sr25519CompiledСontract = await helper.ethContract.compile( + 'SR25519Contract', + ` + // SPDX-License-Identifier: MIT + pragma solidity ^0.8.17; + + /** + * @title SR25519 signature interface. + */ + interface SR25519 { + /** + * @dev Verify signed message using SR25519 crypto. + * @return A boolean confirming whether the public key is signer for the message. + */ + function verify( + bytes32 public_key, + bytes calldata signature, + bytes calldata message + ) external view returns (bool); + } + + contract SR25519Contract{ + SR25519 public constant sr25519 = SR25519(0x0000000000000000000000000000000000005002); + + bytes32 public_key = 0x96b2f9237ed0890fbeed891ebb81b91ac0d5d5b6e3afcdbc95df1b68d9f14036; + bytes signature = hex"4a5d733d7c568f2e88abf0467fd497f87c1be3e940ed897efdf9da72eaad394ef9918cb574ee99c54485775b17a0deaf46ff7a1f10346cea39fff0e4ede97689"; + bytes message1 = hex"7372323535313920697320737570706f72746564"; + bytes message2 = hex"7372323535313920697320737570706f7274656401"; + + + function verifyValid() public view returns(bool) { + return sr25519.verify(public_key, signature, message1); + } + + function verifyInvalid() public view returns(bool) { + return sr25519.verify(public_key, signature, message2); + } + } + `, + ); + + const sr25519Сontract = await helper.ethContract.deployByAbi(owner, sr25519CompiledСontract.abi, sr25519CompiledСontract.object); + expect(await sr25519Сontract.methods.verifyValid().call({from: owner})).to.be.true; + expect(await sr25519Сontract.methods.verifyInvalid().call({from: owner})).to.be.false; + }); +}); \ No newline at end of file diff --git a/tests/src/eth/proxy/fungibleProxy.test.ts b/tests/src/eth/proxy/fungibleProxy.test.ts index 47475cacfb..98f827c317 100644 --- a/tests/src/eth/proxy/fungibleProxy.test.ts +++ b/tests/src/eth/proxy/fungibleProxy.test.ts @@ -48,7 +48,7 @@ describe('Fungible (Via EVM proxy): Information getting', () => { await collection.mint(alice, 200n, {Substrate: alice.address}); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const evmCollection = helper.ethNativeContract.collection(address, 'ft', caller); + const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller); const contract = await proxyWrap(helper, evmCollection, donor); const totalSupply = await contract.methods.totalSupply().call(); @@ -62,7 +62,7 @@ describe('Fungible (Via EVM proxy): Information getting', () => { await collection.mint(alice, 200n, {Ethereum: caller}); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const evmCollection = helper.ethNativeContract.collection(address, 'ft', caller); + const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller); const contract = await proxyWrap(helper, evmCollection, donor); const balance = await contract.methods.balanceOf(caller).call(); @@ -87,7 +87,7 @@ describe('Fungible (Via EVM proxy): Plain calls', () => { const spender = helper.eth.createAccount(); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const evmCollection = helper.ethNativeContract.collection(address, 'ft', caller); + const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller); const contract = await proxyWrap(helper, evmCollection, donor); await collection.mint(alice, 200n, {Ethereum: contract.options.address}); @@ -123,7 +123,7 @@ describe('Fungible (Via EVM proxy): Plain calls', () => { const receiver = helper.eth.createAccount(); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const evmCollection = helper.ethNativeContract.collection(address, 'ft', caller); + const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller); const contract = await proxyWrap(helper, evmCollection, donor); await evmCollection.methods.approve(contract.options.address, 100).send({from: owner}); @@ -170,7 +170,7 @@ describe('Fungible (Via EVM proxy): Plain calls', () => { const receiver = await helper.eth.createAccountWithBalance(donor); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const evmCollection = helper.ethNativeContract.collection(address, 'ft', caller); + const evmCollection = await helper.ethNativeContract.collection(address, 'ft', caller); const contract = await proxyWrap(helper, evmCollection, donor); await collection.mint(alice, 200n, {Ethereum: contract.options.address}); diff --git a/tests/src/eth/proxy/nonFungibleProxy.test.ts b/tests/src/eth/proxy/nonFungibleProxy.test.ts index dc05394088..f1659ef113 100644 --- a/tests/src/eth/proxy/nonFungibleProxy.test.ts +++ b/tests/src/eth/proxy/nonFungibleProxy.test.ts @@ -48,7 +48,7 @@ describe('NFT (Via EVM proxy): Information getting', () => { await collection.mintToken(alice, {Substrate: alice.address}); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const evmCollection = helper.ethNativeContract.collection(address, 'nft', caller); + const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller); const contract = await proxyWrap(helper, evmCollection, donor); const totalSupply = await contract.methods.totalSupply().call(); @@ -66,7 +66,7 @@ describe('NFT (Via EVM proxy): Information getting', () => { ]); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const evmCollection = helper.ethNativeContract.collection(address, 'nft', caller); + const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller); const contract = await proxyWrap(helper, evmCollection, donor); const balance = await contract.methods.balanceOf(caller).call(); @@ -80,7 +80,7 @@ describe('NFT (Via EVM proxy): Information getting', () => { const {tokenId} = await collection.mintToken(alice, {Ethereum: caller}); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const evmCollection = helper.ethNativeContract.collection(address, 'nft', caller); + const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller); const contract = await proxyWrap(helper, evmCollection, donor); const owner = await contract.methods.ownerOf(tokenId).call(); @@ -99,14 +99,15 @@ describe('NFT (Via EVM proxy): Plain calls', () => { }); }); - itEth('Can perform mint()', async ({helper}) => { + // Soft-deprecated + itEth('[eth] Can perform mint()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'A', 'A', 'A', ''); const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - const collectionEvmOwned = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', caller); + const collectionEvmOwned = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller, true); const contract = await proxyWrap(helper, collectionEvm, donor); await collectionEvmOwned.methods.addCollectionAdmin(contract.options.address).send(); @@ -116,20 +117,55 @@ describe('NFT (Via EVM proxy): Plain calls', () => { const tokenId = result.events.Transfer.returnValues.tokenId; expect(tokenId).to.be.equal('1'); - const events = helper.eth.normalizeEvents(result.events); - events[0].address = events[0].address.toLocaleLowerCase(); + const event = helper.eth.normalizeEvents(result.events) + .find(event => event.event === 'Transfer')!; + event.address = event.address.toLocaleLowerCase(); + + expect(event).to.be.deep.equal({ + address: collectionAddress.toLocaleLowerCase(), + event: 'Transfer', + args: { + from: '0x0000000000000000000000000000000000000000', + to: receiver, + tokenId, + }, + }); - expect(events).to.be.deep.equal([ - { - address: collectionAddress.toLocaleLowerCase(), - event: 'Transfer', - args: { - from: '0x0000000000000000000000000000000000000000', - to: receiver, - tokenId, - }, + expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); + } + }); + + itEth('[cross] Can perform mint()', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'A', 'A', 'A', ''); + const caller = await helper.eth.createAccountWithBalance(donor); + const receiver = helper.eth.createAccount(); + + const collectionEvmOwned = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'nft', caller); + const contract = await proxyWrap(helper, collectionEvm, donor); + const contractAddressCross = helper.ethCrossAccount.fromAddress(contract.options.address); + await collectionEvmOwned.methods.addCollectionAdminCross(contractAddressCross).send(); + + { + const nextTokenId = await contract.methods.nextTokenId().call(); + const result = await contract.methods.mintWithTokenURI(receiver, nextTokenId, 'Test URI').send({from: caller}); + const tokenId = result.events.Transfer.returnValues.tokenId; + expect(tokenId).to.be.equal('1'); + + const event = helper.eth.normalizeEvents(result.events) + .find(event => event.event === 'Transfer')!; + event.address = event.address.toLocaleLowerCase(); + + expect(event).to.be.deep.equal({ + address: collectionAddress.toLocaleLowerCase(), + event: 'Transfer', + args: { + from: '0x0000000000000000000000000000000000000000', + to: receiver, + tokenId, }, - ]); + }); expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); } @@ -143,7 +179,7 @@ describe('NFT (Via EVM proxy): Plain calls', () => { const receiver = helper.eth.createAccount(); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const evmCollection = helper.ethNativeContract.collection(address, 'nft', caller); + const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller); const contract = await proxyWrap(helper, evmCollection, donor); await collection.addAdmin(donor, {Ethereum: contract.options.address}); @@ -201,7 +237,7 @@ describe('NFT (Via EVM proxy): Plain calls', () => { const caller = await helper.eth.createAccountWithBalance(donor); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const evmCollection = helper.ethNativeContract.collection(address, 'nft', caller); + const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller); const contract = await proxyWrap(helper, evmCollection, donor); const {tokenId} = await collection.mintToken(alice, {Ethereum: contract.options.address}); await collection.addAdmin(alice, {Ethereum: contract.options.address}); @@ -230,7 +266,7 @@ describe('NFT (Via EVM proxy): Plain calls', () => { const spender = helper.eth.createAccount(); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const evmCollection = helper.ethNativeContract.collection(address, 'nft', caller); + const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller); const contract = await proxyWrap(helper, evmCollection, donor); const {tokenId} = await collection.mintToken(alice, {Ethereum: contract.options.address}); @@ -260,7 +296,7 @@ describe('NFT (Via EVM proxy): Plain calls', () => { const receiver = helper.eth.createAccount(); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const evmCollection = helper.ethNativeContract.collection(address, 'nft', caller); + const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller); const contract = await proxyWrap(helper, evmCollection, donor); const {tokenId} = await collection.mintToken(alice, {Ethereum: owner}); @@ -299,7 +335,7 @@ describe('NFT (Via EVM proxy): Plain calls', () => { const receiver = helper.eth.createAccount(); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const evmCollection = helper.ethNativeContract.collection(address, 'nft', caller); + const evmCollection = await helper.ethNativeContract.collection(address, 'nft', caller); const contract = await proxyWrap(helper, evmCollection, donor); const {tokenId} = await collection.mintToken(alice, {Ethereum: contract.options.address}); diff --git a/tests/src/eth/proxyContract.test.ts b/tests/src/eth/proxyContract.test.ts index 06ae24c0e7..6d84bb29b2 100644 --- a/tests/src/eth/proxyContract.test.ts +++ b/tests/src/eth/proxyContract.test.ts @@ -31,11 +31,11 @@ describe('EVM payable contracts', () => { const deployer = await helper.eth.createAccountWithBalance(donor); const caller = await helper.eth.createAccountWithBalance(donor); const proxyContract = await deployProxyContract(helper, deployer); - + const realContractV1 = await deployRealContractV1(helper, deployer); const realContractV1proxy = new helper.web3!.eth.Contract(realContractV1.options.jsonInterface, proxyContract.options.address, {from: caller, gas: helper.eth.DEFAULT_GAS}); await proxyContract.methods.updateVersion(realContractV1.options.address).send(); - + await realContractV1proxy.methods.flip().send(); await realContractV1proxy.methods.flip().send(); await realContractV1proxy.methods.flip().send(); diff --git a/tests/src/eth/reFungible.test.ts b/tests/src/eth/reFungible.test.ts index 3bed4b0d50..c6cd32af16 100644 --- a/tests/src/eth/reFungible.test.ts +++ b/tests/src/eth/reFungible.test.ts @@ -17,6 +17,7 @@ import {Pallets, requirePalletsOrSkip} from '../util'; import {expect, itEth, usingEthPlaygrounds} from './util'; import {IKeyringPair} from '@polkadot/types/types'; +import {ITokenPropertyPermission} from '../util/playgrounds/types'; describe('Refungible: Information getting', () => { let donor: IKeyringPair; @@ -32,7 +33,7 @@ describe('Refungible: Information getting', () => { itEth('totalSupply', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'TotalSupply', '6', '6'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); await contract.methods.mint(caller).send(); @@ -43,7 +44,7 @@ describe('Refungible: Information getting', () => { itEth('balanceOf', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'BalanceOf', '6', '6'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); await contract.methods.mint(caller).send(); await contract.methods.mint(caller).send(); @@ -56,7 +57,7 @@ describe('Refungible: Information getting', () => { itEth('ownerOf', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'OwnerOf', '6', '6'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const result = await contract.methods.mint(caller).send(); const tokenId = result.events.Transfer.returnValues.tokenId; @@ -69,11 +70,11 @@ describe('Refungible: Information getting', () => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'OwnerOf-AfterBurn', '6', '6'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const result = await contract.methods.mint(caller).send(); const tokenId = result.events.Transfer.returnValues.tokenId; - const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller); + const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller); await tokenContract.methods.repartition(2).send(); await tokenContract.methods.transfer(receiver, 1).send(); @@ -88,11 +89,11 @@ describe('Refungible: Information getting', () => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Partial-OwnerOf', '6', '6'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const result = await contract.methods.mint(caller).send(); const tokenId = result.events.Transfer.returnValues.tokenId; - const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller); + const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller); await tokenContract.methods.repartition(2).send(); await tokenContract.methods.transfer(receiver, 1).send(); @@ -105,21 +106,23 @@ describe('Refungible: Information getting', () => { describe('Refungible: Plain calls', () => { let donor: IKeyringPair; let minter: IKeyringPair; + let bob: IKeyringPair; + let charlie: IKeyringPair; before(async function() { await usingEthPlaygrounds(async (helper, privateKey) => { requirePalletsOrSkip(this, helper, [Pallets.ReFungible]); donor = await privateKey({filename: __filename}); - [minter] = await helper.arrange.createAccounts([100n], donor); + [minter, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); }); - itEth('Can perform mint()', async ({helper}) => { + itEth('Can perform mint() & crossOwnerOf()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Minty', '6', '6', ''); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner); const result = await contract.methods.mintWithTokenURI(receiver, 'Test URI').send(); @@ -130,14 +133,74 @@ describe('Refungible: Plain calls', () => { const tokenId = event.returnValues.tokenId; expect(tokenId).to.be.equal('1'); + expect(await contract.methods.crossOwnerOf(tokenId).call()).to.be.like([receiver, '0']); expect(await contract.methods.tokenURI(tokenId).call()).to.be.equal('Test URI'); }); + [ + 'substrate' as const, + 'ethereum' as const, + ].map(testCase => { + itEth(`Can perform mintCross() for ${testCase} address`, async ({helper}) => { + const collectionAdmin = await helper.eth.createAccountWithBalance(donor); + + const receiverEth = helper.eth.createAccount(); + const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth); + const receiverSub = bob; + const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub); + + const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; }); + const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.key, permission: { + tokenOwner: false, + collectionAdmin: true, + mutable: false}}; + }); + + + const collection = await helper.rft.mintCollection(minter, { + tokenPrefix: 'ethp', + tokenPropertyPermissions: permissions, + }); + await collection.addAdmin(minter, {Ethereum: collectionAdmin}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', collectionAdmin, true); + let expectedTokenId = await contract.methods.nextTokenId().call(); + let result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, []).send(); + let tokenId = result.events.Transfer.returnValues.tokenId; + expect(tokenId).to.be.equal(expectedTokenId); + + let event = result.events.Transfer; + expect(event.address).to.be.equal(collectionAddress); + expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000'); + expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address)); + expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]); + + expectedTokenId = await contract.methods.nextTokenId().call(); + result = await contract.methods.mintCross(testCase === 'ethereum' ? receiverCrossEth : receiverCrossSub, properties).send(); + event = result.events.Transfer; + expect(event.address).to.be.equal(collectionAddress); + expect(event.returnValues.from).to.be.equal('0x0000000000000000000000000000000000000000'); + expect(event.returnValues.to).to.be.equal(testCase === 'ethereum' ? receiverEth : helper.address.substrateToEth(bob.address)); + expect(await contract.methods.properties(tokenId, []).call()).to.be.like([]); + + tokenId = result.events.Transfer.returnValues.tokenId; + + expect(tokenId).to.be.equal(expectedTokenId); + + expect(await contract.methods.properties(tokenId, []).call()).to.be.like(properties + .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); })); + + expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId)) + .to.deep.eq(testCase === 'ethereum' ? {Ethereum: receiverEth.toLowerCase()} : {Substrate: receiverSub.address}); + }); + }); + itEth.skip('Can perform mintBulk()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'MintBulky', '6', '6', ''); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner); { const nextTokenId = await contract.methods.nextTokenId().call(); @@ -166,10 +229,140 @@ describe('Refungible: Plain calls', () => { } }); + itEth('Can perform setApprovalForAll()', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const operator = helper.eth.createAccount(); + + const collection = await helper.rft.mintCollection(minter, {}); + + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner); + + const approvedBefore = await contract.methods.isApprovedForAll(owner, operator).call(); + expect(approvedBefore).to.be.equal(false); + + { + const result = await contract.methods.setApprovalForAll(operator, true).send({from: owner}); + + expect(result.events.ApprovalForAll).to.be.like({ + address: collectionAddress, + event: 'ApprovalForAll', + returnValues: { + owner, + operator, + approved: true, + }, + }); + + const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call(); + expect(approvedAfter).to.be.equal(true); + } + + { + const result = await contract.methods.setApprovalForAll(operator, false).send({from: owner}); + + expect(result.events.ApprovalForAll).to.be.like({ + address: collectionAddress, + event: 'ApprovalForAll', + returnValues: { + owner, + operator, + approved: false, + }, + }); + + const approvedAfter = await contract.methods.isApprovedForAll(owner, operator).call(); + expect(approvedAfter).to.be.equal(false); + } + }); + + itEth('Can perform burn with ApprovalForAll', async ({helper}) => { + const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + + const owner = await helper.eth.createAccountWithBalance(donor); + const operator = await helper.eth.createAccountWithBalance(donor, 100n); + + const token = await collection.mintToken(minter, 100n, {Ethereum: owner}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'rft'); + + { + await contract.methods.setApprovalForAll(operator, true).send({from: owner}); + const ownerCross = helper.ethCrossAccount.fromAddress(owner); + const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: operator}); + const events = result.events.Transfer; + + expect(events).to.be.like({ + address, + event: 'Transfer', + returnValues: { + from: owner, + to: '0x0000000000000000000000000000000000000000', + tokenId: token.tokenId.toString(), + }, + }); + } + }); + + itEth('Can perform burn with approve and approvalForAll', async ({helper}) => { + const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + + const owner = await helper.eth.createAccountWithBalance(donor); + const operator = await helper.eth.createAccountWithBalance(donor, 100n); + + const token = await collection.mintToken(minter, 100n, {Ethereum: owner}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'rft'); + + const rftToken = await helper.ethNativeContract.rftTokenById(token.collectionId, token.tokenId, owner); + + { + await rftToken.methods.approve(operator, 15n).send({from: owner}); + await contract.methods.setApprovalForAll(operator, true).send({from: owner}); + await rftToken.methods.burnFrom(owner, 10n).send({from: operator}); + const allowance = await rftToken.methods.allowance(owner, operator).call(); + expect(allowance).to.be.equal('5'); + } + }); + + itEth('Can perform transfer with ApprovalForAll', async ({helper}) => { + const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + + const owner = await helper.eth.createAccountWithBalance(donor); + const operator = await helper.eth.createAccountWithBalance(donor); + const receiver = charlie; + + const token = await collection.mintToken(minter, 100n, {Ethereum: owner}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'rft'); + + { + await contract.methods.setApprovalForAll(operator, true).send({from: owner}); + const ownerCross = helper.ethCrossAccount.fromAddress(owner); + const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver); + const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: operator}); + const event = result.events.Transfer; + expect(event).to.be.like({ + address: helper.ethAddress.fromCollectionId(collection.collectionId), + event: 'Transfer', + returnValues: { + from: owner, + to: helper.address.substrateToEth(receiver.address), + tokenId: token.tokenId.toString(), + }, + }); + } + + expect(await token.getTop10Owners()).to.be.like([{Substrate: receiver.address}]); + }); + itEth('Can perform burn()', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Burny', '6', '6'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const result = await contract.methods.mint(caller).send(); const tokenId = result.events.Transfer.returnValues.tokenId; @@ -187,14 +380,14 @@ describe('Refungible: Plain calls', () => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'TransferFromy', '6', '6'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const result = await contract.methods.mint(caller).send(); const tokenId = result.events.Transfer.returnValues.tokenId; const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId); - const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller); + const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, caller); await tokenContract.methods.repartition(15).send(); { @@ -229,11 +422,111 @@ describe('Refungible: Plain calls', () => { } }); + // Soft-deprecated + itEth('Can perform burnFrom()', async ({helper}) => { + const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + + const owner = await helper.eth.createAccountWithBalance(donor, 100n); + const spender = await helper.eth.createAccountWithBalance(donor, 100n); + + const token = await collection.mintToken(minter, 100n, {Ethereum: owner}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'rft', spender, true); + + const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId); + const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, owner); + await tokenContract.methods.repartition(15).send(); + await tokenContract.methods.approve(spender, 15).send(); + + { + const result = await contract.methods.burnFrom(owner, token.tokenId).send(); + const event = result.events.Transfer; + expect(event).to.be.like({ + address: helper.ethAddress.fromCollectionId(collection.collectionId), + event: 'Transfer', + returnValues: { + from: owner, + to: '0x0000000000000000000000000000000000000000', + tokenId: token.tokenId.toString(), + }, + }); + } + + expect(await collection.getTokenBalance(token.tokenId, {Ethereum: owner})).to.be.eq(0n); + }); + + itEth('Can perform burnFromCross()', async ({helper}) => { + const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + + const owner = bob; + const spender = await helper.eth.createAccountWithBalance(donor, 100n); + + const token = await collection.mintToken(minter, 100n, {Substrate: owner.address}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'rft'); + + await token.repartition(owner, 15n); + await token.approve(owner, {Ethereum: spender}, 15n); + + { + const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner); + const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender}); + const event = result.events.Transfer; + expect(event).to.be.like({ + address: helper.ethAddress.fromCollectionId(collection.collectionId), + event: 'Transfer', + returnValues: { + from: helper.address.substrateToEth(owner.address), + to: '0x0000000000000000000000000000000000000000', + tokenId: token.tokenId.toString(), + }, + }); + } + + expect(await collection.getTokenBalance(token.tokenId, {Substrate: owner.address})).to.be.eq(0n); + }); + + itEth('Can perform transferFromCross()', async ({helper}) => { + const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + + const owner = bob; + const spender = await helper.eth.createAccountWithBalance(donor, 100n); + const receiver = charlie; + + const token = await collection.mintToken(minter, 100n, {Substrate: owner.address}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'rft'); + + await token.repartition(owner, 15n); + await token.approve(owner, {Ethereum: spender}, 15n); + + { + const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner); + const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver); + const result = await contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender}); + const event = result.events.Transfer; + expect(event).to.be.like({ + address: helper.ethAddress.fromCollectionId(collection.collectionId), + event: 'Transfer', + returnValues: { + from: helper.address.substrateToEth(owner.address), + to: helper.address.substrateToEth(receiver.address), + tokenId: token.tokenId.toString(), + }, + }); + } + + expect(await token.getTop10Owners()).to.be.like([{Substrate: receiver.address}]); + }); + itEth('Can perform transfer()', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry', '6', '6'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const result = await contract.methods.mint(caller).send(); const tokenId = result.events.Transfer.returnValues.tokenId; @@ -258,35 +551,88 @@ describe('Refungible: Plain calls', () => { expect(+balance).to.equal(1); } }); - itEth('Cannot transfer non-owned token', async ({helper}) => { + + itEth('Can perform transferCross()', async ({helper}) => { + const sender = await helper.eth.createAccountWithBalance(donor); + const receiverEth = await helper.eth.createAccountWithBalance(donor); + const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth); + const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter); + + const collection = await helper.rft.mintCollection(minter, {}); + const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', sender); + + const token = await collection.mintToken(minter, 50n, {Ethereum: sender}); + + { + // Can transferCross to ethereum address: + const result = await collectionEvm.methods.transferCross(receiverCrossEth, token.tokenId).send({from: sender}); + // Check events: + const event = result.events.Transfer; + expect(event.address).to.equal(collectionAddress); + expect(event.returnValues.from).to.equal(sender); + expect(event.returnValues.to).to.equal(receiverEth); + expect(event.returnValues.tokenId).to.equal(token.tokenId.toString()); + // Sender's balance decreased: + const senderBalance = await collectionEvm.methods.balanceOf(sender).call(); + expect(+senderBalance).to.equal(0); + expect(await token.getBalance({Ethereum: sender})).to.eq(0n); + // Receiver's balance increased: + const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call(); + expect(+receiverBalance).to.equal(1); + expect(await token.getBalance({Ethereum: receiverEth})).to.eq(50n); + } + + { + // Can transferCross to substrate address: + const substrateResult = await collectionEvm.methods.transferCross(receiverCrossSub, token.tokenId).send({from: receiverEth}); + // Check events: + const event = substrateResult.events.Transfer; + expect(event.address).to.be.equal(collectionAddress); + expect(event.returnValues.from).to.be.equal(receiverEth); + expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(minter.address)); + expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`); + // Sender's balance decreased: + const senderBalance = await collectionEvm.methods.balanceOf(receiverEth).call(); + expect(+senderBalance).to.equal(0); + expect(await token.getBalance({Ethereum: receiverEth})).to.eq(0n); + // Receiver's balance increased: + const receiverBalance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address}); + expect(receiverBalance).to.contain(token.tokenId); + expect(await token.getBalance({Substrate: minter.address})).to.eq(50n); + } + }); + + ['transfer', 'transferCross'].map(testCase => itEth(`Cannot ${testCase} non-owned token`, async ({helper}) => { const sender = await helper.eth.createAccountWithBalance(donor); const tokenOwner = await helper.eth.createAccountWithBalance(donor); const receiverSub = minter; + const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter); const collection = await helper.rft.mintCollection(minter, {}); const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId); - const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', sender); + const collectionEvm = await helper.ethNativeContract.collection(collectionAddress, 'rft', sender); await collection.mintToken(minter, 50n, {Ethereum: sender}); const nonSendersToken = await collection.mintToken(minter, 50n, {Ethereum: tokenOwner}); // Cannot transferCross someone else's token: - const receiver = helper.address.substrateToEth(receiverSub.address); - await expect(collectionEvm.methods.transfer(receiver, nonSendersToken.tokenId).send({from: sender})).to.be.rejected; + const receiver = testCase === 'transfer' ? helper.address.substrateToEth(receiverSub.address) : receiverCrossSub; + await expect(collectionEvm.methods[testCase](receiver, nonSendersToken.tokenId).send({from: sender})).to.be.rejected; // Cannot transfer token if it does not exist: - await expect(collectionEvm.methods.transfer(receiver, 999999).send({from: sender})).to.be.rejected; - }); + await expect(collectionEvm.methods[testCase](receiver, 999999).send({from: sender})).to.be.rejected; + })); itEth('transfer event on transfer from partial ownership to full ownership', async ({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Partial-to-Full', '6', '6'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const result = await contract.methods.mint(caller).send(); const tokenId = result.events.Transfer.returnValues.tokenId; - const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller); + const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller); await tokenContract.methods.repartition(2).send(); await tokenContract.methods.transfer(receiver, 1).send(); @@ -310,12 +656,12 @@ describe('Refungible: Plain calls', () => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Transferry-Full-to-Partial', '6', '6'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const result = await contract.methods.mint(caller).send(); const tokenId = result.events.Transfer.returnValues.tokenId; - const tokenContract = helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller); + const tokenContract = await helper.ethNativeContract.rftTokenById(collectionId, tokenId, caller); await tokenContract.methods.repartition(2).send(); @@ -350,7 +696,7 @@ describe('RFT: Fees', () => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer-From', '6', '6'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const result = await contract.methods.mint(caller).send(); const tokenId = result.events.Transfer.returnValues.tokenId; @@ -364,7 +710,7 @@ describe('RFT: Fees', () => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); const {collectionAddress} = await helper.eth.createRFTCollection(caller, 'Feeful-Transfer', '6', '6'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const result = await contract.methods.mint(caller).send(); const tokenId = result.events.Transfer.returnValues.tokenId; @@ -408,7 +754,7 @@ describe('Common metadata', () => { }, ); - const contract = helper.ethNativeContract.collectionById(collection.collectionId, 'rft', caller); + const contract = await helper.ethNativeContract.collectionById(collection.collectionId, 'rft', caller); const name = await contract.methods.name().call(); expect(name).to.equal('Leviathan'); }); @@ -433,8 +779,67 @@ describe('Common metadata', () => { }, ); - const contract = helper.ethNativeContract.collectionById(collectionId, 'rft', caller); + const contract = await helper.ethNativeContract.collectionById(collectionId, 'rft', caller); const symbol = await contract.methods.symbol().call(); expect(symbol).to.equal('12'); }); }); + +describe('Negative tests', () => { + let donor: IKeyringPair; + let minter: IKeyringPair; + let alice: IKeyringPair; + + before(async function() { + await usingEthPlaygrounds(async (helper, privateKey) => { + requirePalletsOrSkip(this, helper, [Pallets.ReFungible]); + + donor = await privateKey({filename: __filename}); + [minter, alice] = await helper.arrange.createAccounts([100n, 100n], donor); + }); + }); + + itEth('[negative] Cant perform burn without approval', async ({helper}) => { + const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + + const owner = await helper.eth.createAccountWithBalance(donor, 100n); + const spender = await helper.eth.createAccountWithBalance(donor, 100n); + + const token = await collection.mintToken(minter, 100n, {Ethereum: owner}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'rft'); + + const ownerCross = helper.ethCrossAccount.fromAddress(owner); + + await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected; + + await contract.methods.setApprovalForAll(spender, true).send({from: owner}); + await contract.methods.setApprovalForAll(spender, false).send({from: owner}); + + await expect(contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender})).to.be.rejected; + }); + + itEth('[negative] Cant perform transfer without approval', async ({helper}) => { + const collection = await helper.rft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'}); + const owner = await helper.eth.createAccountWithBalance(donor, 100n); + const receiver = alice; + + const spender = await helper.eth.createAccountWithBalance(donor, 100n); + + const token = await collection.mintToken(minter, 100n, {Ethereum: owner}); + + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, 'rft'); + + const ownerCross = helper.ethCrossAccount.fromAddress(owner); + const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver); + + await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected; + + await contract.methods.setApprovalForAll(spender, true).send({from: owner}); + await contract.methods.setApprovalForAll(spender, false).send({from: owner}); + + await expect(contract.methods.transferFromCross(ownerCross, recieverCross, token.tokenId).send({from: spender})).to.be.rejected; + }); +}); diff --git a/tests/src/eth/reFungibleToken.test.ts b/tests/src/eth/reFungibleToken.test.ts index 453f7f06c5..03b93662b1 100644 --- a/tests/src/eth/reFungibleToken.test.ts +++ b/tests/src/eth/reFungibleToken.test.ts @@ -38,7 +38,7 @@ describe('Refungible token: Information getting', () => { const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'}); const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller}); - const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller); + const contract = await helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller); const totalSupply = await contract.methods.totalSupply().call(); expect(totalSupply).to.equal('200'); }); @@ -48,7 +48,7 @@ describe('Refungible token: Information getting', () => { const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'}); const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller}); - const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller); + const contract = await helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller); const balance = await contract.methods.balanceOf(caller).call(); expect(balance).to.equal('200'); }); @@ -58,7 +58,7 @@ describe('Refungible token: Information getting', () => { const collection = await helper.rft.mintCollection(alice, {tokenPrefix: 'MUON'}); const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: caller}); - const contract = helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller); + const contract = await helper.ethNativeContract.rftTokenById(collection.collectionId, tokenId, caller); const decimals = await contract.methods.decimals().call(); expect(decimals).to.equal('0'); }); @@ -81,7 +81,7 @@ describe('Check ERC721 token URI for ReFungible', () => { const receiver = helper.eth.createAccount(); const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleRFTCollection(owner, 'Mint collection', 'a', 'b', baseUri); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner); const result = await contract.methods.mint(receiver).send(); @@ -94,7 +94,8 @@ describe('Check ERC721 token URI for ReFungible', () => { if (propertyKey && propertyValue) { // Set URL or suffix - await contract.methods.setProperty(tokenId, propertyKey, Buffer.from(propertyValue)).send(); + + await contract.methods.setProperties(tokenId, [{key: propertyKey, value: Buffer.from(propertyValue)}]).send(); } return {contract, nextTokenId: tokenId}; @@ -142,7 +143,7 @@ describe('Refungible: Plain calls', () => { const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner}); const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); - const contract = helper.ethNativeContract.rftToken(tokenAddress, owner); + const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner); { const result = await contract.methods.approve(spender, 100).send({from: owner}); @@ -159,110 +160,233 @@ describe('Refungible: Plain calls', () => { } }); - itEth('Can perform transferFrom()', async ({helper}) => { + itEth('Can perform approveCross()', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); - const spender = await helper.eth.createAccountWithBalance(donor); - const receiver = helper.eth.createAccount(); + const spender = helper.eth.createAccount(); + const spenderSub = (await helper.arrange.createAccounts([1n], donor))[0]; + const spenderCrossEth = helper.ethCrossAccount.fromAddress(spender); + const spenderCrossSub = helper.ethCrossAccount.fromKeyringPair(spenderSub); + + const collection = await helper.rft.mintCollection(alice); const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner}); const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); - const contract = helper.ethNativeContract.rftToken(tokenAddress, owner); - - await contract.methods.approve(spender, 100).send(); + const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner); { - const result = await contract.methods.transferFrom(owner, receiver, 49).send({from: spender}); - let event = result.events.Transfer; - expect(event.address).to.be.equal(tokenAddress); - expect(event.returnValues.from).to.be.equal(owner); - expect(event.returnValues.to).to.be.equal(receiver); - expect(event.returnValues.value).to.be.equal('49'); - - event = result.events.Approval; + const result = await contract.methods.approveCross(spenderCrossEth, 100).send({from: owner}); + const event = result.events.Approval; expect(event.address).to.be.equal(tokenAddress); expect(event.returnValues.owner).to.be.equal(owner); expect(event.returnValues.spender).to.be.equal(spender); - expect(event.returnValues.value).to.be.equal('51'); - } - - { - const balance = await contract.methods.balanceOf(receiver).call(); - expect(+balance).to.equal(49); + expect(event.returnValues.value).to.be.equal('100'); } { - const balance = await contract.methods.balanceOf(owner).call(); - expect(+balance).to.equal(151); + const allowance = await contract.methods.allowance(owner, spender).call(); + expect(+allowance).to.equal(100); } - }); - - itEth('Can perform transfer()', async ({helper}) => { - const owner = await helper.eth.createAccountWithBalance(donor); - const receiver = helper.eth.createAccount(); - const collection = await helper.rft.mintCollection(alice); - const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner}); - const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); - const contract = helper.ethNativeContract.rftToken(tokenAddress, owner); { - const result = await contract.methods.transfer(receiver, 50).send({from: owner}); - const event = result.events.Transfer; + const result = await contract.methods.approveCross(spenderCrossSub, 100).send({from: owner}); + const event = result.events.Approval; expect(event.address).to.be.equal(tokenAddress); - expect(event.returnValues.from).to.be.equal(owner); - expect(event.returnValues.to).to.be.equal(receiver); - expect(event.returnValues.value).to.be.equal('50'); + expect(event.returnValues.owner).to.be.equal(owner); + expect(event.returnValues.spender).to.be.equal(helper.address.substrateToEth(spenderSub.address)); + expect(event.returnValues.value).to.be.equal('100'); } { - const balance = await contract.methods.balanceOf(owner).call(); - expect(+balance).to.equal(150); + const allowance = await collection.getTokenApprovedPieces(tokenId, {Ethereum: owner}, {Substrate: spenderSub.address}); + expect(allowance).to.equal(100n); } { - const balance = await contract.methods.balanceOf(receiver).call(); - expect(+balance).to.equal(50); + //TO-DO expect with future allowanceCross(owner, spenderCrossEth).call() } }); + itEth('Non-owner and non admin cannot approveCross', async ({helper}) => { + const nonOwner = await helper.eth.createAccountWithBalance(donor); + const nonOwnerCross = helper.ethCrossAccount.fromAddress(nonOwner); + const owner = await helper.eth.createAccountWithBalance(donor); + const collection = await helper.rft.mintCollection(alice, {name: 'A', description: 'B', tokenPrefix: 'C'}); + const token = await collection.mintToken(alice, 100n, {Ethereum: owner}); + + const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId); + const tokenEvm = await helper.ethNativeContract.rftToken(tokenAddress, owner); + + await expect(tokenEvm.methods.approveCross(nonOwnerCross, 20).call({from: nonOwner})).to.be.rejectedWith('CantApproveMoreThanOwned'); + }); + + [ + 'transferFrom', + 'transferFromCross', + ].map(testCase => + itEth(`Can perform ${testCase}`, async ({helper}) => { + const isCross = testCase === 'transferFromCross'; + const owner = await helper.eth.createAccountWithBalance(donor); + const ownerCross = helper.ethCrossAccount.fromAddress(owner); + const spender = await helper.eth.createAccountWithBalance(donor); + const receiverEth = helper.eth.createAccount(); + const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth); + const [receiverSub] = await helper.arrange.createAccounts([1n], donor); + const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub); + + const collection = await helper.rft.mintCollection(alice); + const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner}); + + const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); + const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner); + + await contract.methods.approve(spender, 100).send({from: owner}); + + // 1. Can transfer from + // 1.1 Plain ethereum or cross address: + { + const result = await contract.methods[testCase]( + isCross ? ownerCross : owner, + isCross ? receiverCrossEth : receiverEth, + 49, + ).send({from: spender}); + + // Check events: + const transferEvent = result.events.Transfer; + expect(transferEvent.address).to.be.equal(tokenAddress); + expect(transferEvent.returnValues.from).to.be.equal(owner); + expect(transferEvent.returnValues.to).to.be.equal(receiverEth); + expect(transferEvent.returnValues.value).to.be.equal('49'); + + const approvalEvent = result.events.Approval; + expect(approvalEvent.address).to.be.equal(tokenAddress); + expect(approvalEvent.returnValues.owner).to.be.equal(owner); + expect(approvalEvent.returnValues.spender).to.be.equal(spender); + expect(approvalEvent.returnValues.value).to.be.equal('51'); + + // Check balances: + const receiverBalance = await contract.methods.balanceOf(receiverEth).call(); + const ownerBalance = await contract.methods.balanceOf(owner).call(); + + expect(+receiverBalance).to.equal(49); + expect(+ownerBalance).to.equal(151); + } + + // 1.2 Cross substrate address: + if (testCase === 'transferFromCross') { + const result = await contract.methods.transferFromCross(ownerCross, receiverCrossSub, 51).send({from: spender}); + // Check events: + const transferEvent = result.events.Transfer; + expect(transferEvent.address).to.be.equal(tokenAddress); + expect(transferEvent.returnValues.from).to.be.equal(owner); + expect(transferEvent.returnValues.to).to.be.equal(helper.address.substrateToEth(receiverSub.address)); + expect(transferEvent.returnValues.value).to.be.equal('51'); + + const approvalEvent = result.events.Approval; + expect(approvalEvent.address).to.be.equal(tokenAddress); + expect(approvalEvent.returnValues.owner).to.be.equal(owner); + expect(approvalEvent.returnValues.spender).to.be.equal(spender); + expect(approvalEvent.returnValues.value).to.be.equal('0'); + + // Check balances: + const receiverBalance = await collection.getTokenBalance(tokenId, {Substrate: receiverSub.address}); + const ownerBalance = await contract.methods.balanceOf(owner).call(); + expect(receiverBalance).to.equal(51n); + expect(+ownerBalance).to.equal(100); + } + })); + + [ + 'transfer', + 'transferCross', + ].map(testCase => + itEth(`Can perform ${testCase}()`, async ({helper}) => { + const isCross = testCase === 'transferCross'; + const owner = await helper.eth.createAccountWithBalance(donor); + const receiverEth = helper.eth.createAccount(); + const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth); + const [receiverSub] = await helper.arrange.createAccounts([1n], donor); + const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub); + const collection = await helper.rft.mintCollection(alice); + const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner}); + + const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); + const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner); + + // 1. Can transfer to plain ethereum or cross-ethereum account: + { + const result = await contract.methods[testCase](isCross ? receiverCrossEth : receiverEth, 50).send({from: owner}); + // Check events + const transferEvent = result.events.Transfer; + expect(transferEvent.address).to.be.equal(tokenAddress); + expect(transferEvent.returnValues.from).to.be.equal(owner); + expect(transferEvent.returnValues.to).to.be.equal(receiverEth); + expect(transferEvent.returnValues.value).to.be.equal('50'); + // Check balances: + const ownerBalance = await contract.methods.balanceOf(owner).call(); + const receiverBalance = await contract.methods.balanceOf(receiverEth).call(); + expect(+ownerBalance).to.equal(150); + expect(+receiverBalance).to.equal(50); + } + + // 2. Can transfer to cross-substrate account: + if(isCross) { + const result = await contract.methods.transferCross(receiverCrossSub, 50).send({from: owner}); + // Check events: + const event = result.events.Transfer; + expect(event.address).to.be.equal(tokenAddress); + expect(event.returnValues.from).to.be.equal(owner); + expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(receiverSub.address)); + expect(event.returnValues.value).to.be.equal('50'); + // Check balances: + const ownerBalance = await contract.methods.balanceOf(owner).call(); + const receiverBalance = await collection.getTokenBalance(tokenId, {Substrate: receiverSub.address}); + expect(+ownerBalance).to.equal(100); + expect(receiverBalance).to.equal(50n); + } + })); + [ 'transfer', - // 'transferCross', // TODO - ].map(testCase => + 'transferCross', + ].map(testCase => itEth(`Cannot ${testCase}() non-owned token`, async ({helper}) => { + const isCross = testCase === 'transferCross'; const owner = await helper.eth.createAccountWithBalance(donor); - const receiver = await helper.eth.createAccountWithBalance(donor); + const ownerCross = helper.ethCrossAccount.fromAddress(owner); + const receiverEth = await helper.eth.createAccountWithBalance(donor); + const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth); const collection = await helper.rft.mintCollection(alice); const rftOwner = await collection.mintToken(alice, 10n, {Ethereum: owner}); - const rftReceiver = await collection.mintToken(alice, 10n, {Ethereum: receiver}); + const rftReceiver = await collection.mintToken(alice, 10n, {Ethereum: receiverEth}); const tokenIdNonExist = 9999999; - + const tokenAddress1 = helper.ethAddress.fromTokenId(collection.collectionId, rftOwner.tokenId); const tokenAddress2 = helper.ethAddress.fromTokenId(collection.collectionId, rftReceiver.tokenId); const tokenAddressNonExist = helper.ethAddress.fromTokenId(collection.collectionId, tokenIdNonExist); - const tokenEvmOwner = helper.ethNativeContract.rftToken(tokenAddress1, owner); - const tokenEvmReceiver = helper.ethNativeContract.rftToken(tokenAddress2, owner); - const tokenEvmNonExist = helper.ethNativeContract.rftToken(tokenAddressNonExist, owner); - + const tokenEvmOwner = await helper.ethNativeContract.rftToken(tokenAddress1, owner); + const tokenEvmReceiver = await helper.ethNativeContract.rftToken(tokenAddress2, owner); + const tokenEvmNonExist = await helper.ethNativeContract.rftToken(tokenAddressNonExist, owner); + // 1. Can transfer zero amount (EIP-20): - await tokenEvmOwner.methods[testCase](receiver, 0).send({from: owner}); + await tokenEvmOwner.methods[testCase](isCross ? receiverCrossEth : receiverEth, 0).send({from: owner}); // 2. Cannot transfer non-owned token: - await expect(tokenEvmReceiver.methods[testCase](owner, 0).send({from: owner})).to.be.rejected; - await expect(tokenEvmReceiver.methods[testCase](owner, 5).send({from: owner})).to.be.rejected; + await expect(tokenEvmReceiver.methods[testCase](isCross ? ownerCross : owner, 0).send({from: owner})).to.be.rejected; + await expect(tokenEvmReceiver.methods[testCase](isCross ? ownerCross : owner, 5).send({from: owner})).to.be.rejected; // 3. Cannot transfer non-existing token: - await expect(tokenEvmNonExist.methods[testCase](owner, 0).send({from: owner})).to.be.rejected; - await expect(tokenEvmNonExist.methods[testCase](owner, 5).send({from: owner})).to.be.rejected; + await expect(tokenEvmNonExist.methods[testCase](isCross ? ownerCross : owner, 0).send({from: owner})).to.be.rejected; + await expect(tokenEvmNonExist.methods[testCase](isCross ? ownerCross : owner, 5).send({from: owner})).to.be.rejected; // 4. Storage is not corrupted: expect(await rftOwner.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]); - expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: receiver.toLowerCase()}]); - expect(await helper.rft.getTokenTop10Owners(collection.collectionId, tokenIdNonExist)).to.deep.eq([]); // TODO + expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: receiverEth.toLowerCase()}]); + expect(await helper.rft.getTokenTop10Owners(collection.collectionId, tokenIdNonExist)).to.deep.eq([]); // 4.1 Tokens can be transferred: - await tokenEvmOwner.methods[testCase](receiver, 10).send({from: owner}); - await tokenEvmReceiver.methods[testCase](owner, 10).send({from: receiver}); - expect(await rftOwner.getTop10Owners()).to.deep.eq([{Ethereum: receiver.toLowerCase()}]); + await tokenEvmOwner.methods[testCase](isCross ? receiverCrossEth : receiverEth, 10).send({from: owner}); + await tokenEvmReceiver.methods[testCase](isCross ? ownerCross : owner, 10).send({from: receiverEth}); + expect(await rftOwner.getTop10Owners()).to.deep.eq([{Ethereum: receiverEth.toLowerCase()}]); expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]); })); @@ -273,7 +397,7 @@ describe('Refungible: Plain calls', () => { const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner}); const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); - const contract = helper.ethNativeContract.rftToken(tokenAddress, owner); + const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner); await contract.methods.repartition(200).send({from: owner}); expect(+await contract.methods.balanceOf(owner).call()).to.be.equal(200); @@ -298,7 +422,7 @@ describe('Refungible: Plain calls', () => { const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner}); const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); - const contract = helper.ethNativeContract.rftToken(tokenAddress, owner); + const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner); const result = await contract.methods.repartition(200).send(); @@ -315,7 +439,7 @@ describe('Refungible: Plain calls', () => { const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner}); const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); - const contract = helper.ethNativeContract.rftToken(tokenAddress, owner); + const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner); const result = await contract.methods.repartition(50).send(); const event = result.events.Transfer; @@ -329,12 +453,12 @@ describe('Refungible: Plain calls', () => { const caller = await helper.eth.createAccountWithBalance(donor); const receiver = await helper.eth.createAccountWithBalance(donor); const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(caller, 'Devastation', '6', '6'); - const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'rft', caller); const result = await contract.methods.mint(caller).send(); const tokenId = result.events.Transfer.returnValues.tokenId; const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId); - const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, caller); + const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, caller); await tokenContract.methods.repartition(2).send(); await tokenContract.methods.transfer(receiver, 1).send(); @@ -352,6 +476,41 @@ describe('Refungible: Plain calls', () => { expect(event.returnValues.to).to.be.equal(receiver); expect(event.returnValues.tokenId).to.be.equal(tokenId); }); + + itEth('Can perform burnFromCross()', async ({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const ownerSub = (await helper.arrange.createAccounts([10n], donor))[0]; + const ownerCross = helper.ethCrossAccount.fromAddress(owner); + const spender = await helper.eth.createAccountWithBalance(donor); + + const spenderCrossEth = helper.ethCrossAccount.fromAddress(spender); + const ownerSubCross = helper.ethCrossAccount.fromKeyringPair(ownerSub); + + const collection = await helper.rft.mintCollection(alice); + const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner}); + + + const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); + const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner); + + { + await contract.methods.approveCross(spenderCrossEth, 100).send({from: owner}); + + await expect(contract.methods.burnFromCross(ownerCross, 50).send({from: spender})).to.be.fulfilled; + await expect(contract.methods.burnFromCross(ownerCross, 100).send({from: spender})).to.be.rejected; + expect(await contract.methods.balanceOf(owner).call({from: owner})).to.be.equal('150'); + } + { + const {tokenId} = await collection.mintToken(alice, 200n, {Substrate: ownerSub.address}); + await collection.approveToken(ownerSub, tokenId, {Ethereum: spender}, 100n); + const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); + const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner); + + await expect(contract.methods.burnFromCross(ownerSubCross, 50).send({from: spender})).to.be.fulfilled; + await expect(contract.methods.burnFromCross(ownerSubCross, 100).send({from: spender})).to.be.rejected; + expect(await collection.getTokenBalance(tokenId, {Substrate: ownerSub.address})).to.be.equal(150n); + } + }); }); describe('Refungible: Fees', () => { @@ -374,7 +533,7 @@ describe('Refungible: Fees', () => { const {tokenId} = await collection.mintToken(alice, 100n, {Ethereum: owner}); const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); - const contract = helper.ethNativeContract.rftToken(tokenAddress, owner); + const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner); const cost = await helper.eth.recordCallFee(owner, () => contract.methods.approve(spender, 100).send({from: owner})); expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))); @@ -387,7 +546,7 @@ describe('Refungible: Fees', () => { const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner}); const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); - const contract = helper.ethNativeContract.rftToken(tokenAddress, owner); + const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner); await contract.methods.approve(spender, 100).send({from: owner}); @@ -402,7 +561,7 @@ describe('Refungible: Fees', () => { const {tokenId} = await collection.mintToken(alice, 200n, {Ethereum: owner}); const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, tokenId); - const contract = helper.ethNativeContract.rftToken(tokenAddress, owner); + const contract = await helper.ethNativeContract.rftToken(tokenAddress, owner); const cost = await helper.eth.recordCallFee(owner, () => contract.methods.transfer(receiver, 100).send({from: owner})); expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal()))); @@ -428,7 +587,7 @@ describe('Refungible: Substrate calls', () => { const token = await collection.mintToken(alice, 200n); const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId); - const contract = helper.ethNativeContract.rftToken(tokenAddress); + const contract = await helper.ethNativeContract.rftToken(tokenAddress); const events: any = []; contract.events.allEvents((_: any, event: any) => { @@ -454,7 +613,7 @@ describe('Refungible: Substrate calls', () => { await token.approve(alice, {Substrate: bob.address}, 100n); const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId); - const contract = helper.ethNativeContract.rftToken(tokenAddress); + const contract = await helper.ethNativeContract.rftToken(tokenAddress); const events: any = []; contract.events.allEvents((_: any, event: any) => { @@ -485,7 +644,7 @@ describe('Refungible: Substrate calls', () => { const token = await collection.mintToken(alice, 200n); const tokenAddress = helper.ethAddress.fromTokenId(collection.collectionId, token.tokenId); - const contract = helper.ethNativeContract.rftToken(tokenAddress); + const contract = await helper.ethNativeContract.rftToken(tokenAddress); const events: any = []; contract.events.allEvents((_: any, event: any) => { @@ -519,13 +678,13 @@ describe('ERC 1633 implementation', () => { const owner = await helper.eth.createAccountWithBalance(donor); const {collectionId, collectionAddress} = await helper.eth.createRFTCollection(owner, 'Sands', '', 'GRAIN'); - const collectionContract = helper.ethNativeContract.collection(collectionAddress, 'rft', owner); + const collectionContract = await helper.ethNativeContract.collection(collectionAddress, 'rft', owner); const result = await collectionContract.methods.mint(owner).send(); const tokenId = result.events.Transfer.returnValues.tokenId; const tokenAddress = helper.ethAddress.fromTokenId(collectionId, tokenId); - const tokenContract = helper.ethNativeContract.rftToken(tokenAddress, owner); + const tokenContract = await helper.ethNativeContract.rftToken(tokenAddress, owner); expect(await tokenContract.methods.parentToken().call()).to.be.equal(collectionAddress); expect(await tokenContract.methods.parentTokenId().call()).to.be.equal(tokenId); diff --git a/tests/src/eth/scheduling.test.ts b/tests/src/eth/scheduling.test.ts new file mode 100644 index 0000000000..c12c4f372f --- /dev/null +++ b/tests/src/eth/scheduling.test.ts @@ -0,0 +1,63 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {expect} from 'chai'; +import {EthUniqueHelper, itSchedEth} from './util'; +import {Pallets, usingPlaygrounds} from '../util'; + +describe('Scheduing EVM smart contracts', () => { + + before(async () => { + await usingPlaygrounds(async (helper) => { + await helper.testUtils.enable(); + }); + }); + + itSchedEth.ifWithPallets('Successfully schedules and periodically executes an EVM contract', [Pallets.Scheduler], async (scheduleKind, {helper, privateKey}) => { + const donor = await privateKey({filename: __filename}); + const [alice] = await helper.arrange.createAccounts([1000n], donor); + + const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined; + + const deployer = await helper.eth.createAccountWithBalance(alice); + const flipper = await helper.eth.deployFlipper(deployer); + + const initialValue = await flipper.methods.getValue().call(); + await helper.eth.transferBalanceFromSubstrate(alice, helper.address.substrateToEth(alice.address)); + + const waitForBlocks = 4; + const periodic = { + period: 2, + repetitions: 2, + }; + + await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, periodic}) + .eth.sendEVM( + alice, + flipper.options.address, + flipper.methods.flip().encodeABI(), + '0', + ); + + expect(await flipper.methods.getValue().call()).to.be.equal(initialValue); + + await helper.wait.newBlocks(waitForBlocks + 1); + expect(await flipper.methods.getValue().call()).to.be.not.equal(initialValue); + + await helper.wait.newBlocks(periodic.period); + expect(await flipper.methods.getValue().call()).to.be.equal(initialValue); + }); +}); diff --git a/tests/src/eth/sponsoring.test.ts b/tests/src/eth/sponsoring.test.ts index 52b748b69a..5fa59092a1 100644 --- a/tests/src/eth/sponsoring.test.ts +++ b/tests/src/eth/sponsoring.test.ts @@ -37,11 +37,11 @@ describe('EVM sponsoring', () => { const flipper = await helper.eth.deployFlipper(owner); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); await helpers.methods.toggleAllowlist(flipper.options.address, true).send({from: owner}); await helpers.methods.toggleAllowed(flipper.options.address, caller, true).send({from: owner}); - + await helpers.methods.setSponsor(flipper.options.address, sponsor).send({from: owner}); await helpers.methods.confirmSponsorship(flipper.options.address).send({from: sponsor}); @@ -71,7 +71,7 @@ describe('EVM sponsoring', () => { const collector = await helper.eth.deployCollectorContract(owner); - const helpers = helper.ethNativeContract.contractHelpers(owner); + const helpers = await helper.ethNativeContract.contractHelpers(owner); await helpers.methods.toggleAllowlist(collector.options.address, true).send({from: owner}); await helpers.methods.toggleAllowed(collector.options.address, caller, true).send({from: owner}); diff --git a/tests/src/eth/tokenProperties.test.ts b/tests/src/eth/tokenProperties.test.ts index 57c69c53a8..ca542e5536 100644 --- a/tests/src/eth/tokenProperties.test.ts +++ b/tests/src/eth/tokenProperties.test.ts @@ -14,8 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import {itEth, usingEthPlaygrounds, expect} from './util'; import {IKeyringPair} from '@polkadot/types/types'; +import {Contract} from 'web3-eth-contract'; +import {itEth, usingEthPlaygrounds, expect} from './util'; +import {ITokenPropertyPermission} from '../util/playgrounds/types'; +import {Pallets} from '../util'; +import {UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection} from '../util/playgrounds/unique'; +import {TokenPermissionField} from './util/playgrounds/types'; describe('EVM token properties', () => { let donor: IKeyringPair; @@ -28,72 +33,286 @@ describe('EVM token properties', () => { }); }); - itEth('Can be reconfigured', async({helper}) => { - const caller = await helper.eth.createAccountWithBalance(donor); - for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) { - const collection = await helper.nft.mintCollection(alice); + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`[${testCase.mode}] Can set all possible token property permissions`, testCase.requiredPallets, async({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const caller = await helper.ethCrossAccount.createAccountWithBalance(donor); + for(const [mutable,collectionAdmin, tokenOwner] of cartesian([], [false, true], [false, true], [false, true])) { + const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner); + await collection.methods.addCollectionAdminCross(caller).send({from: owner}); + + await collection.methods.setTokenPropertyPermissions([ + ['testKey', [ + [TokenPermissionField.Mutable, mutable], + [TokenPermissionField.TokenOwner, tokenOwner], + [TokenPermissionField.CollectionAdmin, collectionAdmin]], + ], + ]).send({from: caller.eth}); + + expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([{ + key: 'testKey', + permission: {mutable, collectionAdmin, tokenOwner}, + }]); + + expect(await collection.methods.tokenPropertyPermissions().call({from: caller.eth})).to.be.like([ + ['testKey', [ + [TokenPermissionField.Mutable.toString(), mutable], + [TokenPermissionField.TokenOwner.toString(), tokenOwner], + [TokenPermissionField.CollectionAdmin.toString(), collectionAdmin]], + ], + ]); + } + })); + + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`[${testCase.mode}] Can set multiple token property permissions as owner`, testCase.requiredPallets, async({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner); + + await collection.methods.setTokenPropertyPermissions([ + ['testKey_0', [ + [TokenPermissionField.Mutable, true], + [TokenPermissionField.TokenOwner, true], + [TokenPermissionField.CollectionAdmin, true]], + ], + ['testKey_1', [ + [TokenPermissionField.Mutable, true], + [TokenPermissionField.TokenOwner, false], + [TokenPermissionField.CollectionAdmin, true]], + ], + ['testKey_2', [ + [TokenPermissionField.Mutable, false], + [TokenPermissionField.TokenOwner, true], + [TokenPermissionField.CollectionAdmin, false]], + ], + ]).send({from: owner}); + + expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([ + { + key: 'testKey_0', + permission: {mutable: true, tokenOwner: true, collectionAdmin: true}, + }, + { + key: 'testKey_1', + permission: {mutable: true, tokenOwner: false, collectionAdmin: true}, + }, + { + key: 'testKey_2', + permission: {mutable: false, tokenOwner: true, collectionAdmin: false}, + }, + ]); + + expect(await collection.methods.tokenPropertyPermissions().call({from: owner})).to.be.like([ + ['testKey_0', [ + [TokenPermissionField.Mutable.toString(), true], + [TokenPermissionField.TokenOwner.toString(), true], + [TokenPermissionField.CollectionAdmin.toString(), true]], + ], + ['testKey_1', [ + [TokenPermissionField.Mutable.toString(), true], + [TokenPermissionField.TokenOwner.toString(), false], + [TokenPermissionField.CollectionAdmin.toString(), true]], + ], + ['testKey_2', [ + [TokenPermissionField.Mutable.toString(), false], + [TokenPermissionField.TokenOwner.toString(), true], + [TokenPermissionField.CollectionAdmin.toString(), false]], + ], + ]); + })); + + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`[${testCase.mode}] Can set multiple token property permissions as admin`, testCase.requiredPallets, async({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const caller = await helper.ethCrossAccount.createAccountWithBalance(donor); + + const {collectionId, collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner); + await collection.methods.addCollectionAdminCross(caller).send({from: owner}); + + await collection.methods.setTokenPropertyPermissions([ + ['testKey_0', [ + [TokenPermissionField.Mutable, true], + [TokenPermissionField.TokenOwner, true], + [TokenPermissionField.CollectionAdmin, true]], + ], + ['testKey_1', [ + [TokenPermissionField.Mutable, true], + [TokenPermissionField.TokenOwner, false], + [TokenPermissionField.CollectionAdmin, true]], + ], + ['testKey_2', [ + [TokenPermissionField.Mutable, false], + [TokenPermissionField.TokenOwner, true], + [TokenPermissionField.CollectionAdmin, false]], + ], + ]).send({from: caller.eth}); + + expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([ + { + key: 'testKey_0', + permission: {mutable: true, tokenOwner: true, collectionAdmin: true}, + }, + { + key: 'testKey_1', + permission: {mutable: true, tokenOwner: false, collectionAdmin: true}, + }, + { + key: 'testKey_2', + permission: {mutable: false, tokenOwner: true, collectionAdmin: false}, + }, + ]); + + expect(await collection.methods.tokenPropertyPermissions().call({from: caller.eth})).to.be.like([ + ['testKey_0', [ + [TokenPermissionField.Mutable.toString(), true], + [TokenPermissionField.TokenOwner.toString(), true], + [TokenPermissionField.CollectionAdmin.toString(), true]], + ], + ['testKey_1', [ + [TokenPermissionField.Mutable.toString(), true], + [TokenPermissionField.TokenOwner.toString(), false], + [TokenPermissionField.CollectionAdmin.toString(), true]], + ], + ['testKey_2', [ + [TokenPermissionField.Mutable.toString(), false], + [TokenPermissionField.TokenOwner.toString(), true], + [TokenPermissionField.CollectionAdmin.toString(), false]], + ], + ]); + + })); + + [ + { + method: 'setProperties', + methodParams: [[{key: 'testKey1', value: Buffer.from('testValue1')}, {key: 'testKey2', value: Buffer.from('testValue2')}]], + expectedProps: [{key: 'testKey1', value: 'testValue1'}, {key: 'testKey2', value: 'testValue2'}], + }, + { + method: 'setProperty' /*Soft-deprecated*/, + methodParams: ['testKey1', Buffer.from('testValue1')], + expectedProps: [{key: 'testKey1', value: 'testValue1'}], + }, + ].map(testCase => + itEth(`[${testCase.method}] Can be set`, async({helper}) => { + const caller = await helper.eth.createAccountWithBalance(donor); + const collection = await helper.nft.mintCollection(alice, { + tokenPropertyPermissions: [{ + key: 'testKey1', + permission: { + collectionAdmin: true, + }, + }, { + key: 'testKey2', + permission: { + collectionAdmin: true, + }, + }], + }); + await collection.addAdmin(alice, {Ethereum: caller}); - + const token = await collection.mintToken(alice); + + const collectionEvm = await helper.ethNativeContract.collectionById(collection.collectionId, 'nft', caller, testCase.method === 'setProperty'); + + await collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller}); + + const properties = await token.getProperties(); + expect(properties).to.deep.equal(testCase.expectedProps); + })); + + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`Can be multiple set/read for ${testCase.mode}`, testCase.requiredPallets, async({helper}) => { + const caller = await helper.eth.createAccountWithBalance(donor); + + const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; }); + const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.key, permission: {tokenOwner: true, + collectionAdmin: true, + mutable: true}}; }); + + const collection = await helper[testCase.mode].mintCollection(alice, { + tokenPrefix: 'ethp', + tokenPropertyPermissions: permissions, + }) as UniqueNFTCollection | UniqueRFTCollection; + + const token = await collection.mintToken(alice); + + const valuesBefore = await token.getProperties(properties.map(p => p.key)); + expect(valuesBefore).to.be.deep.equal([]); + + + await collection.addAdmin(alice, {Ethereum: caller}); + const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'nft', caller); - - await contract.methods.setTokenPropertyPermission('testKey', mutable, collectionAdmin, tokenOwner).send({from: caller}); - - expect(await collection.getPropertyPermissions()).to.be.deep.equal([{ - key: 'testKey', - permission: {mutable, collectionAdmin, tokenOwner}, - }]); - } - }); + const contract = await helper.ethNativeContract.collection(address, testCase.mode, caller); - itEth('Can be set', async({helper}) => { - const caller = await helper.eth.createAccountWithBalance(donor); - const collection = await helper.nft.mintCollection(alice, { - tokenPropertyPermissions: [{ - key: 'testKey', - permission: { - collectionAdmin: true, - }, - }], - }); - const token = await collection.mintToken(alice); + expect(await contract.methods.properties(token.tokenId, []).call()).to.be.deep.equal([]); - await collection.addAdmin(alice, {Ethereum: caller}); + await contract.methods.setProperties(token.tokenId, properties).send({from: caller}); - const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'nft', caller); + const values = await token.getProperties(properties.map(p => p.key)); + expect(values).to.be.deep.equal(properties.map(p => { return {key: p.key, value: p.value.toString()}; })); - await contract.methods.setProperty(token.tokenId, 'testKey', Buffer.from('testValue')).send({from: caller}); + expect(await contract.methods.properties(token.tokenId, []).call()).to.be.like(properties + .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); })); - const [{value}] = await token.getProperties(['testKey']); - expect(value).to.equal('testValue'); - }); + expect(await contract.methods.properties(token.tokenId, [properties[0].key]).call()) + .to.be.like([helper.ethProperty.property(properties[0].key, properties[0].value.toString())]); + })); - itEth('Can be deleted', async({helper}) => { - const caller = await helper.eth.createAccountWithBalance(donor); - const collection = await helper.nft.mintCollection(alice, { - tokenPropertyPermissions: [{ - key: 'testKey', - permission: { - mutable: true, - collectionAdmin: true, + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`Can be deleted for ${testCase.mode}`, testCase.requiredPallets, async({helper}) => { + const caller = await helper.eth.createAccountWithBalance(donor); + const collection = await helper[testCase.mode].mintCollection(alice, { + tokenPropertyPermissions: [{ + key: 'testKey', + permission: { + mutable: true, + collectionAdmin: true, + }, }, - }], - }); - - const token = await collection.mintToken(alice); - await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}]); + { + key: 'testKey_1', + permission: { + mutable: true, + collectionAdmin: true, + }, + }], + }); - await collection.addAdmin(alice, {Ethereum: caller}); + const token = await collection.mintToken(alice); + await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}, {key: 'testKey_1', value: 'testValue_1'}]); + expect(await token.getProperties()).to.has.length(2); - const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'nft', caller); + await collection.addAdmin(alice, {Ethereum: caller}); - await contract.methods.deleteProperty(token.tokenId, 'testKey').send({from: caller}); + const address = helper.ethAddress.fromCollectionId(collection.collectionId); + const contract = await helper.ethNativeContract.collection(address, testCase.mode, caller); - const result = await token.getProperties(['testKey']); - expect(result.length).to.equal(0); - }); + await contract.methods.deleteProperties(token.tokenId, ['testKey', 'testKey_1']).send({from: caller}); + + const result = await token.getProperties(['testKey', 'testKey_1']); + expect(result.length).to.equal(0); + })); itEth('Can be read', async({helper}) => { const caller = helper.eth.createAccount(); @@ -105,18 +324,237 @@ describe('EVM token properties', () => { }, }], }); - + const token = await collection.mintToken(alice); await token.setProperties(alice, [{key: 'testKey', value: 'testValue'}]); const address = helper.ethAddress.fromCollectionId(collection.collectionId); - const contract = helper.ethNativeContract.collection(address, 'nft', caller); + const contract = await helper.ethNativeContract.collection(address, 'nft', caller); const value = await contract.methods.property(token.tokenId, 'testKey').call(); expect(value).to.equal(helper.getWeb3().utils.toHex('testValue')); }); }); +describe('EVM token properties negative', () => { + let donor: IKeyringPair; + let alice: IKeyringPair; + let caller: string; + let aliceCollection: UniqueNFTCollection; + let token: UniqueNFToken; + const tokenProps = [{key: 'testKey_1', value: 'testValue_1'}, {key: 'testKey_2', value: 'testValue_2'}]; + let collectionEvm: Contract; + + before(async function() { + await usingEthPlaygrounds(async (helper, privateKey) => { + donor = await privateKey({filename: __filename}); + [alice] = await helper.arrange.createAccounts([100n], donor); + }); + }); + + beforeEach(async () => { + // 1. create collection with props: testKey_1, testKey_2 + // 2. create token and set props testKey_1, testKey_2 + await usingEthPlaygrounds(async (helper) => { + aliceCollection = await helper.nft.mintCollection(alice, { + tokenPropertyPermissions: [{ + key: 'testKey_1', + permission: { + mutable: true, + collectionAdmin: true, + }, + }, + { + key: 'testKey_2', + permission: { + mutable: true, + collectionAdmin: true, + }, + }], + }); + token = await aliceCollection.mintToken(alice); + await token.setProperties(alice, tokenProps); + collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, true); + }); + }); + + [ + {method: 'setProperty', methodParams: [tokenProps[1].key, Buffer.from('newValue')]}, + {method: 'setProperties', methodParams: [[{key: tokenProps[1].key, value: Buffer.from('newValue')}]]}, + ].map(testCase => + itEth(`[${testCase.method}] Cannot set properties of non-owned collection`, async ({helper}) => { + caller = await helper.eth.createAccountWithBalance(donor); + collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, true); + // Caller not an owner and not an admin, so he cannot set properties: + await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).call({from: caller})).to.be.rejectedWith('NoPermission'); + await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller})).to.be.rejected; + + // Props have not changed: + const expectedProps = tokenProps.map(p => helper.ethProperty.property(p.key, p.value.toString())); + const actualProps = await collectionEvm.methods.properties(token.tokenId, []).call(); + expect(actualProps).to.deep.eq(expectedProps); + })); + + [ + {method: 'setProperty', methodParams: ['testKey_3', Buffer.from('testValue3')]}, + {method: 'setProperties', methodParams: [[{key: 'testKey_3', value: Buffer.from('testValue3')}]]}, + ].map(testCase => + itEth(`[${testCase.method}] Cannot set non-existing properties`, async ({helper}) => { + caller = await helper.eth.createAccountWithBalance(donor); + collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, true); + await helper.collection.addAdmin(alice, aliceCollection.collectionId, {Ethereum: caller}); + + await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).call({from: caller})).to.be.rejectedWith('NoPermission'); + await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller})).to.be.rejected; + + // Props have not changed: + const expectedProps = tokenProps.map(p => helper.ethProperty.property(p.key, p.value.toString())); + const actualProps = await collectionEvm.methods.properties(token.tokenId, []).call(); + expect(actualProps).to.deep.eq(expectedProps); + })); + + [ + {method: 'deleteProperty', methodParams: ['testKey_2']}, + {method: 'deleteProperties', methodParams: [['testKey_2']]}, + ].map(testCase => + itEth(`[${testCase.method}] Cannot delete properties of non-owned collection`, async ({helper}) => { + caller = await helper.eth.createAccountWithBalance(donor); + collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, testCase.method == 'deleteProperty'); + // Caller not an owner and not an admin, so he cannot set properties: + await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).call({from: caller})).to.be.rejectedWith('NoPermission'); + await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller})).to.be.rejected; + + // Props have not changed: + const expectedProps = tokenProps.map(p => helper.ethProperty.property(p.key, p.value.toString())); + const actualProps = await collectionEvm.methods.properties(token.tokenId, []).call(); + expect(actualProps).to.deep.eq(expectedProps); + })); + + [ + {method: 'deleteProperty', methodParams: ['testKey_3']}, + {method: 'deleteProperties', methodParams: [['testKey_3']]}, + ].map(testCase => + itEth(`[${testCase.method}] Cannot delete non-existing properties`, async ({helper}) => { + caller = await helper.eth.createAccountWithBalance(donor); + collectionEvm = await helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(aliceCollection.collectionId), 'nft', caller, testCase.method == 'deleteProperty'); + await helper.collection.addAdmin(alice, aliceCollection.collectionId, {Ethereum: caller}); + // Caller cannot delete non-existing properties: + await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).call({from: caller})).to.be.rejectedWith('NoPermission'); + await expect(collectionEvm.methods[testCase.method](token.tokenId, ...testCase.methodParams).send({from: caller})).to.be.rejected; + // Props have not changed: + const expectedProps = tokenProps.map(p => helper.ethProperty.property(p.key, p.value.toString())); + const actualProps = await collectionEvm.methods.properties(token.tokenId, []).call(); + expect(actualProps).to.deep.eq(expectedProps); + })); + + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`[${testCase.mode}] Cannot set token property permissions as non owner or admin`, testCase.requiredPallets, async({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + const caller = await helper.eth.createAccountWithBalance(donor); + + const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner); + + await expect(collection.methods.setTokenPropertyPermissions([ + ['testKey_0', [ + [TokenPermissionField.Mutable, true], + [TokenPermissionField.TokenOwner, true], + [TokenPermissionField.CollectionAdmin, true]], + ], + ]).call({from: caller})).to.be.rejectedWith('NoPermission'); + })); + + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`[${testCase.mode}] Cannot set token property permissions with invalid character`, testCase.requiredPallets, async({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner); + + await expect(collection.methods.setTokenPropertyPermissions([ + // "Space" is invalid character + ['testKey 0', [ + [TokenPermissionField.Mutable, true], + [TokenPermissionField.TokenOwner, true], + [TokenPermissionField.CollectionAdmin, true]], + ], + ]).call({from: owner})).to.be.rejectedWith('InvalidCharacterInPropertyKey'); + })); + + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`[${testCase.mode}] Can reconfigure token property permissions to stricter ones`, testCase.requiredPallets, async({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionAddress, collectionId} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner); + + // 1. Owner sets strict property-permissions: + await collection.methods.setTokenPropertyPermissions([ + ['testKey', [ + [TokenPermissionField.Mutable, true], + [TokenPermissionField.TokenOwner, true], + [TokenPermissionField.CollectionAdmin, true]], + ], + ]).send({from: owner}); + + // 2. Owner can set stricter property-permissions: + for(const values of [[true, true, false], [true, false, false], [false, false, false]]) { + await collection.methods.setTokenPropertyPermissions([ + ['testKey', [ + [TokenPermissionField.Mutable, values[0]], + [TokenPermissionField.TokenOwner, values[1]], + [TokenPermissionField.CollectionAdmin, values[2]]], + ], + ]).send({from: owner}); + } + + expect(await helper[testCase.mode].getPropertyPermissions(collectionId)).to.be.deep.equal([{ + key: 'testKey', + permission: {mutable: false, collectionAdmin: false, tokenOwner: false}, + }]); + })); + + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itEth.ifWithPallets(`[${testCase.mode}] Cannot reconfigure token property permissions to less strict ones`, testCase.requiredPallets, async({helper}) => { + const owner = await helper.eth.createAccountWithBalance(donor); + + const {collectionAddress} = await helper.eth.createCollection(testCase.mode, owner, 'A', 'B', 'C'); + const collection = await helper.ethNativeContract.collection(collectionAddress, testCase.mode, owner); + + // 1. Owner sets strict property-permissions: + await collection.methods.setTokenPropertyPermissions([ + ['testKey', [ + [TokenPermissionField.Mutable, false], + [TokenPermissionField.TokenOwner, false], + [TokenPermissionField.CollectionAdmin, false]], + ], + ]).send({from: owner}); + + // 2. Owner cannot set less strict property-permissions: + for(const values of [[true, false, false], [false, true, false], [false, false, true]]) { + await expect(collection.methods.setTokenPropertyPermissions([ + ['testKey', [ + [TokenPermissionField.Mutable, values[0]], + [TokenPermissionField.TokenOwner, values[1]], + [TokenPermissionField.CollectionAdmin, values[2]]], + ], + ]).call({from: owner})).to.be.rejectedWith('NoPermission'); + } + })); +}); + type ElementOf = A extends readonly (infer T)[] ? T : never; function* cartesian>, R extends Array>(internalRest: [...R], ...args: [...T]): Generator<[...R, ...{[K in keyof T]: ElementOf}]> { diff --git a/tests/src/eth/util/index.ts b/tests/src/eth/util/index.ts index eba5e1d386..19c9186b0c 100644 --- a/tests/src/eth/util/index.ts +++ b/tests/src/eth/util/index.ts @@ -8,6 +8,7 @@ import config from '../../config'; import {EthUniqueHelper} from './playgrounds/unique.dev'; import {SilentLogger, SilentConsole} from '../../util/playgrounds/unique.dev'; +import {SchedKind} from '../../util'; export {EthUniqueHelper} from './playgrounds/unique.dev'; @@ -57,9 +58,9 @@ export const usingEthPlaygrounds = async (code: (helper: EthUniqueHelper, privat silentConsole.disable(); } }; - + export function itEth(name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) { - (opts.only ? it.only : + (opts.only ? it.only : opts.skip ? it.skip : it)(name, async function() { await usingEthPlaygrounds(async (helper, privateKey) => { if (opts.requiredPallets) { @@ -81,3 +82,19 @@ itEth.skip = (name: string, cb: (apis: { helper: EthUniqueHelper, privateKey: (s itEthIfWithPallet.only = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise }) => any) => itEthIfWithPallet(name, required, cb, {only: true}); itEthIfWithPallet.skip = (name: string, required: string[], cb: (apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise }) => any) => itEthIfWithPallet(name, required, cb, {skip: true}); itEth.ifWithPallets = itEthIfWithPallet; + +export function itSchedEth( + name: string, + cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise }) => any, + opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}, +) { + itEth(name + ' (anonymous scheduling)', (apis) => cb('anon', apis), opts); + itEth(name + ' (named scheduling)', (apis) => cb('named', apis), opts); +} +itSchedEth.only = (name: string, cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise }) => any) => itSchedEth(name, cb, {only: true}); +itSchedEth.skip = (name: string, cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise }) => any) => itSchedEth(name, cb, {skip: true}); +itSchedEth.ifWithPallets = itSchedIfWithPallets; + +function itSchedIfWithPallets(name: string, required: string[], cb: (schedKind: SchedKind, apis: { helper: EthUniqueHelper, privateKey: (seed: string | {filename: string}) => Promise }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) { + return itSchedEth(name, cb, {requiredPallets: required, ...opts}); +} diff --git a/tests/src/eth/util/playgrounds/types.ts b/tests/src/eth/util/playgrounds/types.ts index eda8a191ca..44ee10fa27 100644 --- a/tests/src/eth/util/playgrounds/types.ts +++ b/tests/src/eth/util/playgrounds/types.ts @@ -13,3 +13,38 @@ export type NormalizedEvent = { event: string, args: { [key: string]: string } }; + +export interface OptionUint { + status: boolean, + value: bigint, +} + +export interface CrossAddress { + readonly eth: string, + readonly sub: string | Uint8Array, +} + +export type EthProperty = string[]; + +export enum TokenPermissionField { + Mutable, + TokenOwner, + CollectionAdmin +} + +export enum CollectionLimitField { + AccountTokenOwnership, + SponsoredDataSize, + SponsoredDataRateLimit, + TokenLimit, + SponsorTransferTimeout, + SponsorApproveTimeout, + OwnerCanTransfer, + OwnerCanDestroy, + TransferEnabled +} + +export interface CollectionLimit { + field: CollectionLimitField, + value: OptionUint, +} diff --git a/tests/src/eth/util/playgrounds/unique.dev.ts b/tests/src/eth/util/playgrounds/unique.dev.ts index 9e64050fb6..c7b02e3d36 100644 --- a/tests/src/eth/util/playgrounds/unique.dev.ts +++ b/tests/src/eth/util/playgrounds/unique.dev.ts @@ -18,25 +18,59 @@ import {IKeyringPair} from '@polkadot/types/types'; import {DevUniqueHelper} from '../../../util/playgrounds/unique.dev'; -import {ContractImports, CompiledContract, NormalizedEvent} from './types'; +import {ContractImports, CompiledContract, CrossAddress, NormalizedEvent, EthProperty} from './types'; // Native contracts ABI -import collectionHelpersAbi from '../../collectionHelpersAbi.json'; -import fungibleAbi from '../../fungibleAbi.json'; -import nonFungibleAbi from '../../nonFungibleAbi.json'; -import refungibleAbi from '../../reFungibleAbi.json'; -import refungibleTokenAbi from '../../reFungibleTokenAbi.json'; -import contractHelpersAbi from './../contractHelpersAbi.json'; +import collectionHelpersAbi from '../../abi/collectionHelpers.json'; +import fungibleAbi from '../../abi/fungible.json'; +import fungibleDeprecatedAbi from '../../abi/fungibleDeprecated.json'; +import nonFungibleAbi from '../../abi/nonFungible.json'; +import nonFungibleDeprecatedAbi from '../../abi/nonFungibleDeprecated.json'; +import refungibleAbi from '../../abi/reFungible.json'; +import refungibleDeprecatedAbi from '../../abi/reFungibleDeprecated.json'; +import refungibleTokenAbi from '../../abi/reFungibleToken.json'; +import contractHelpersAbi from '../../abi/contractHelpers.json'; import {ICrossAccountId, TEthereumAccount} from '../../../util/playgrounds/types'; +import {TCollectionMode} from '../../../util/playgrounds/types'; class EthGroupBase { helper: EthUniqueHelper; + gasPrice?: string; constructor(helper: EthUniqueHelper) { this.helper = helper; } + async getGasPrice() { + if (this.gasPrice) + return this.gasPrice; + this.gasPrice = await this.helper.getWeb3().eth.getGasPrice(); + return this.gasPrice; + } } +function unlimitedMoneyHack(_contract: C): C { + const contract = _contract as any; + // Hack: fight against gasPrice override + for (const method in contract.methods) { + const _method = contract.methods[method]; + contract.methods[method] = function (...args: any) { + const encodedCall = _method.call(this, ...args); + const _call = encodedCall.call; + encodedCall.call = function (...args: any) { + if (args.length === 0) { + return _call.call(this, {gasPrice: '0'}); + } + // No support for callback/defaultBlock, they may be placed as first argument + if (typeof args[0] !== 'object') + throw new Error('only options are supported'); + args[0].gasPrice = '0'; + return _call.call(this, ...args); + }; + return encodedCall; + }; + } + return contract; +} class ContractGroup extends EthGroupBase { async findImports(imports?: ContractImports[]){ @@ -56,7 +90,7 @@ class ContractGroup extends EthGroupBase { } async compile(name: string, src: string, imports?: ContractImports[]): Promise { - const out = JSON.parse(solc.compile(JSON.stringify({ + const compiled = JSON.parse(solc.compile(JSON.stringify({ language: 'Solidity', sources: { [`${name}.sol`]: { @@ -70,7 +104,18 @@ class ContractGroup extends EthGroupBase { }, }, }, - }), {import: await this.findImports(imports)})).contracts[`${name}.sol`][name]; + }), {import: await this.findImports(imports)})); + + const hasErrors = compiled['errors'] + && compiled['errors'].length > 0 + && compiled.errors.some(function(err: any) { + return err.severity == 'error'; + }); + + if (hasErrors) { + throw compiled.errors; + } + const out = compiled.contracts[`${name}.sol`][name]; return { abi: out.abi, @@ -78,55 +123,80 @@ class ContractGroup extends EthGroupBase { }; } - async deployByCode(signer: string, name: string, src: string, imports?: ContractImports[]): Promise { + async deployByCode(signer: string, name: string, src: string, imports?: ContractImports[], gas?: number): Promise { const compiledContract = await this.compile(name, src, imports); - return this.deployByAbi(signer, compiledContract.abi, compiledContract.object); + return this.deployByAbi(signer, compiledContract.abi, compiledContract.object, gas); } - async deployByAbi(signer: string, abi: any, object: string): Promise { + async deployByAbi(signer: string, abi: any, object: string, gas?: number): Promise { const web3 = this.helper.getWeb3(); const contract = new web3.eth.Contract(abi, undefined, { data: object, from: signer, - gas: this.helper.eth.DEFAULT_GAS, + gas: gas ?? this.helper.eth.DEFAULT_GAS, + gasPrice: await this.getGasPrice(), }); - return await contract.deploy({data: object}).send({from: signer}); + return unlimitedMoneyHack(await contract.deploy({data: object}).send({from: signer})); } } class NativeContractGroup extends EthGroupBase { - contractHelpers(caller: string): Contract { + async contractHelpers(caller: string): Promise { const web3 = this.helper.getWeb3(); - return new web3.eth.Contract(contractHelpersAbi as any, '0x842899ECF380553E8a4de75bF534cdf6fBF64049', {from: caller, gas: this.helper.eth.DEFAULT_GAS}); + return unlimitedMoneyHack(new web3.eth.Contract(contractHelpersAbi as any, this.helper.getApi().consts.evmContractHelpers.contractAddress.toString(), { + from: caller, + gas: this.helper.eth.DEFAULT_GAS, + gasPrice: await this.getGasPrice(), + })); } - collectionHelpers(caller: string) { + async collectionHelpers(caller: string) { const web3 = this.helper.getWeb3(); - return new web3.eth.Contract(collectionHelpersAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, gas: this.helper.eth.DEFAULT_GAS}); + return unlimitedMoneyHack(new web3.eth.Contract(collectionHelpersAbi as any, this.helper.getApi().consts.common.contractAddress.toString(), { + from: caller, + gas: this.helper.eth.DEFAULT_GAS, + gasPrice: await this.getGasPrice(), + })); } - collection(address: string, mode: 'nft' | 'rft' | 'ft', caller?: string): Contract { - const abi = { + async collection(address: string, mode: TCollectionMode, caller?: string, mergeDeprecated = false) { + let abi = { 'nft': nonFungibleAbi, 'rft': refungibleAbi, 'ft': fungibleAbi, }[mode]; + if (mergeDeprecated) { + const deprecated = { + 'nft': nonFungibleDeprecatedAbi, + 'rft': refungibleDeprecatedAbi, + 'ft': fungibleDeprecatedAbi, + }[mode]; + abi = [...abi,...deprecated]; + } const web3 = this.helper.getWeb3(); - return new web3.eth.Contract(abi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})}); + return unlimitedMoneyHack(new web3.eth.Contract(abi as any, address, { + gas: this.helper.eth.DEFAULT_GAS, + gasPrice: await this.getGasPrice(), + ...(caller ? {from: caller} : {}), + })); } - collectionById(collectionId: number, mode: 'nft' | 'rft' | 'ft', caller?: string): Contract { - return this.collection(this.helper.ethAddress.fromCollectionId(collectionId), mode, caller); + collectionById(collectionId: number, mode: 'nft' | 'rft' | 'ft', caller?: string, mergeDeprecated = false) { + return this.collection(this.helper.ethAddress.fromCollectionId(collectionId), mode, caller, mergeDeprecated); } - rftToken(address: string, caller?: string): Contract { + async rftToken(address: string, caller?: string) { const web3 = this.helper.getWeb3(); - return new web3.eth.Contract(refungibleTokenAbi as any, address, {gas: this.helper.eth.DEFAULT_GAS, ...(caller ? {from: caller} : {})}); + return unlimitedMoneyHack(new web3.eth.Contract(refungibleTokenAbi as any, address, { + gas: this.helper.eth.DEFAULT_GAS, + gasPrice: await this.getGasPrice(), + ...(caller ? {from: caller} : {}), + })); } - rftTokenById(collectionId: number, tokenId: number, caller?: string): Contract { + rftTokenById(collectionId: number, tokenId: number, caller?: string) { return this.rftToken(this.helper.ethAddress.fromTokenId(collectionId, tokenId), caller); } } @@ -154,7 +224,7 @@ class EthGroup extends EthGroupBase { } async getCollectionCreationFee(signer: string) { - const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); + const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer); return await collectionHelper.methods.collectionCreationFee().call(); } @@ -174,48 +244,62 @@ class EthGroup extends EthGroupBase { return await this.helper.callRpc('api.rpc.eth.call', [{from: signer, to: contractAddress, data: abi}]); } - async createNFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> { + createCollectionMethodName(mode: TCollectionMode) { + switch (mode) { + case 'ft': + return 'createFTCollection'; + case 'nft': + return 'createNFTCollection'; + case 'rft': + return 'createRFTCollection'; + } + } + + async createCollection(mode: TCollectionMode, signer: string, name: string, description: string, tokenPrefix: string, decimals = 18): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> { const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice(); - const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); + const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer); + const functionName: string = this.createCollectionMethodName(mode); - const result = await collectionHelper.methods.createNFTCollection(name, description, tokenPrefix).send({value: Number(collectionCreationPrice)}); + const functionParams = mode === 'ft' ? [name, decimals, description, tokenPrefix] : [name, description, tokenPrefix]; + const result = await collectionHelper.methods[functionName](...functionParams).send({value: Number(collectionCreationPrice)}); const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress); + const events = this.helper.eth.normalizeEvents(result.events); + + return {collectionId, collectionAddress, events}; + } - return {collectionId, collectionAddress}; + createNFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> { + return this.createCollection('nft', signer, name, description, tokenPrefix); } - async createERC721MetadataCompatibleNFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string}> { - const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); + async createERC721MetadataCompatibleNFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> { + const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer); - const {collectionId, collectionAddress} = await this.createNFTCollection(signer, name, description, tokenPrefix); + const {collectionId, collectionAddress, events} = await this.createCollection('nft', signer, name, description, tokenPrefix); await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send(); - return {collectionId, collectionAddress}; + return {collectionId, collectionAddress, events}; } - async createRFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string}> { - const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice(); - const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); - - const result = await collectionHelper.methods.createRFTCollection(name, description, tokenPrefix).send({value: Number(collectionCreationPrice)}); - - const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId); - const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress); + createRFTCollection(signer: string, name: string, description: string, tokenPrefix: string): Promise<{collectionId: number, collectionAddress: string, events: NormalizedEvent[]}> { + return this.createCollection('rft', signer, name, description, tokenPrefix); + } - return {collectionId, collectionAddress}; + createFungibleCollection(signer: string, name: string, decimals: number, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[]}> { + return this.createCollection('ft', signer, name, description, tokenPrefix, decimals); } - async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string}> { - const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer); + async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> { + const collectionHelper = await this.helper.ethNativeContract.collectionHelpers(signer); - const {collectionId, collectionAddress} = await this.createRFTCollection(signer, name, description, tokenPrefix); + const {collectionId, collectionAddress, events} = await this.createCollection('rft', signer, name, description, tokenPrefix); await collectionHelper.methods.makeCollectionERC721MetadataCompatible(collectionAddress, baseUri).send(); - return {collectionId, collectionAddress}; + return {collectionId, collectionAddress, events}; } async deployCollectorContract(signer: string): Promise { @@ -340,17 +424,50 @@ class EthAddressGroup extends EthGroupBase { return '0x' + address.substring(address.length - 40); } } - +export class EthPropertyGroup extends EthGroupBase { + property(key: string, value: string): EthProperty { + return [ + key, + '0x'+Buffer.from(value).toString('hex'), + ]; + } +} export type EthUniqueHelperConstructor = new (...args: any[]) => EthUniqueHelper; +export class EthCrossAccountGroup extends EthGroupBase { + createAccount(): CrossAddress { + return this.fromAddress(this.helper.eth.createAccount()); + } + + async createAccountWithBalance(donor: IKeyringPair, amount=100n) { + return this.fromAddress(await this.helper.eth.createAccountWithBalance(donor, amount)); + } + + fromAddress(address: TEthereumAccount): CrossAddress { + return { + eth: address, + sub: '0', + }; + } + + fromKeyringPair(keyring: IKeyringPair): CrossAddress { + return { + eth: '0x0000000000000000000000000000000000000000', + sub: keyring.addressRaw, + }; + } +} + export class EthUniqueHelper extends DevUniqueHelper { web3: Web3 | null = null; web3Provider: WebsocketProvider | null = null; eth: EthGroup; ethAddress: EthAddressGroup; + ethCrossAccount: EthCrossAccountGroup; ethNativeContract: NativeContractGroup; ethContract: ContractGroup; + ethProperty: EthPropertyGroup; constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) { options.helperBase = options.helperBase ?? EthUniqueHelper; @@ -358,8 +475,10 @@ export class EthUniqueHelper extends DevUniqueHelper { super(logger, options); this.eth = new EthGroup(this); this.ethAddress = new EthAddressGroup(this); + this.ethCrossAccount = new EthCrossAccountGroup(this); this.ethNativeContract = new NativeContractGroup(this); this.ethContract = new ContractGroup(this); + this.ethProperty = new EthPropertyGroup(this); } getWeb3(): Web3 { diff --git a/tests/src/fungible.test.ts b/tests/src/fungible.test.ts index 9433e475b4..43317dab1b 100644 --- a/tests/src/fungible.test.ts +++ b/tests/src/fungible.test.ts @@ -43,7 +43,7 @@ describe('integration test: Fungible functionality:', () => { expect(itemCountAfter).to.be.equal(defaultTokenId); expect(aliceBalance).to.be.equal(U128_MAX); }); - + itSub('RPC method tokenOnewrs for fungible collection and token', async ({helper}) => { const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'}; const facelessCrowd = (await helper.arrange.createAccounts(Array(7).fill(0n), donor)).map(keyring => {return {Substrate: keyring.address};}); @@ -54,22 +54,22 @@ describe('integration test: Fungible functionality:', () => { await collection.transfer(alice, {Substrate: bob.address}, 1000n); await collection.transfer(alice, ethAcc, 900n); - + for (let i = 0; i < 7; i++) { await collection.transfer(alice, facelessCrowd[i], 1n); - } + } const owners = await collection.getTop10Owners(); // What to expect expect(owners).to.deep.include.members([{Substrate: alice.address}, ethAcc, {Substrate: bob.address}, ...facelessCrowd]); expect(owners.length).to.be.equal(10); - + const [eleven] = await helper.arrange.createAccounts([0n], donor); expect(await collection.transfer(alice, {Substrate: eleven.address}, 10n)).to.be.true; expect((await collection.getTop10Owners()).length).to.be.equal(10); }); - + itSub('Transfer token', async ({helper}) => { const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'}; const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}); @@ -108,7 +108,7 @@ describe('integration test: Fungible functionality:', () => { expect(await collection.doesTokenExist(0)).to.be.true; expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(1n); }); - + itSub('Burn all tokens ', async ({helper}) => { const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}); await collection.mint(alice, 500n); @@ -127,7 +127,7 @@ describe('integration test: Fungible functionality:', () => { await collection.mint(alice, 100n); expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(100n); - + expect(await collection.approveTokens(alice, {Substrate: bob.address}, 60n)).to.be.true; expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(60n); expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(0n); @@ -169,11 +169,11 @@ describe('Fungible negative tests', () => { // 1. Alice cannot transfer more than 0 tokens if balance low: await expect(collection.transfer(alice, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.TokenValueTooLow'); await expect(collection.transfer(alice, {Substrate: charlie.address}, 100n)).to.be.rejectedWith('common.TokenValueTooLow'); - + // 2. Alice cannot transfer non-existing token: await expect(nonExistingCollection.transfer(alice, {Substrate: charlie.address}, 0n)).to.be.rejectedWith('common.CollectionNotFound'); await expect(nonExistingCollection.transfer(alice, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.CollectionNotFound'); - + // 3. Zero transfer allowed (EIP-20): await collection.transfer(bob, {Substrate: charlie.address}, 0n); // 3.1 even if the balance = 0 diff --git a/tests/src/inflation.test.ts b/tests/src/inflation.seqtest.ts similarity index 99% rename from tests/src/inflation.test.ts rename to tests/src/inflation.seqtest.ts index 78e5131f18..661490d00d 100644 --- a/tests/src/inflation.test.ts +++ b/tests/src/inflation.seqtest.ts @@ -26,7 +26,7 @@ describe('integration test: Inflation', () => { superuser = await privateKey('//Alice'); }); }); - + itSub('First year inflation is 10%', async ({helper}) => { // Make sure non-sudo can't start inflation const [bob] = await helper.arrange.createAccounts([10n], superuser); diff --git a/tests/src/interfaces/augment-api-consts.ts b/tests/src/interfaces/augment-api-consts.ts index 7328235a63..584b085b57 100644 --- a/tests/src/interfaces/augment-api-consts.ts +++ b/tests/src/interfaces/augment-api-consts.ts @@ -8,8 +8,8 @@ import '@polkadot/api-base/types/consts'; import type { ApiTypes, AugmentedConst } from '@polkadot/api-base/types'; import type { Option, u128, u16, u32, u64, u8 } from '@polkadot/types-codec'; import type { Codec } from '@polkadot/types-codec/types'; -import type { Perbill, Permill } from '@polkadot/types/interfaces/runtime'; -import type { FrameSupportPalletId, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, XcmV1MultiLocation } from '@polkadot/types/lookup'; +import type { H160, Perbill, Permill } from '@polkadot/types/interfaces/runtime'; +import type { FrameSupportPalletId, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, UpDataStructsCollectionLimits, XcmV1MultiLocation } from '@polkadot/types/lookup'; export type __AugmentedConst = AugmentedConst; @@ -69,6 +69,10 @@ declare module '@polkadot/api-base/types/consts' { * Set price to create a collection. **/ collectionCreationPrice: u128 & AugmentedConst; + /** + * Address under which the CollectionHelper contract would be available. + **/ + contractAddress: H160 & AugmentedConst; /** * Generic const **/ @@ -78,8 +82,18 @@ declare module '@polkadot/api-base/types/consts' { appPromotionDailyRate: Perbill & AugmentedConst; dayRelayBlocks: u32 & AugmentedConst; defaultMinGasPrice: u64 & AugmentedConst; - defaultWeightToFeeCoefficient: u32 & AugmentedConst; - maxOverridedAllowedLocations: u32 & AugmentedConst; + defaultWeightToFeeCoefficient: u64 & AugmentedConst; + maxXcmAllowedLocations: u32 & AugmentedConst; + /** + * Generic const + **/ + [key: string]: Codec; + }; + evmContractHelpers: { + /** + * Address, under which magic contract will be available + **/ + contractAddress: H160 & AugmentedConst; /** * Generic const **/ @@ -220,6 +234,64 @@ declare module '@polkadot/api-base/types/consts' { **/ [key: string]: Codec; }; + unique: { + /** + * Maximum admins per collection. + **/ + collectionAdminsLimit: u32 & AugmentedConst; + /** + * Default FT collection limit. + **/ + ftDefaultCollectionLimits: UpDataStructsCollectionLimits & AugmentedConst; + /** + * Maximal length of a collection description. + **/ + maxCollectionDescriptionLength: u32 & AugmentedConst; + /** + * Maximal length of a collection name. + **/ + maxCollectionNameLength: u32 & AugmentedConst; + /** + * Maximum size for all collection properties. + **/ + maxCollectionPropertiesSize: u32 & AugmentedConst; + /** + * A maximum number of token properties. + **/ + maxPropertiesPerItem: u32 & AugmentedConst; + /** + * Maximal length of a property key. + **/ + maxPropertyKeyLength: u32 & AugmentedConst; + /** + * Maximal length of a property value. + **/ + maxPropertyValueLength: u32 & AugmentedConst; + /** + * Maximal length of a token prefix. + **/ + maxTokenPrefixLength: u32 & AugmentedConst; + /** + * Maximum size of all token properties. + **/ + maxTokenPropertiesSize: u32 & AugmentedConst; + /** + * A maximum number of levels of depth in the token nesting tree. + **/ + nestingBudget: u32 & AugmentedConst; + /** + * Default NFT collection limit. + **/ + nftDefaultCollectionLimits: UpDataStructsCollectionLimits & AugmentedConst; + /** + * Default RFT collection limit. + **/ + rftDefaultCollectionLimits: UpDataStructsCollectionLimits & AugmentedConst; + /** + * Generic const + **/ + [key: string]: Codec; + }; vesting: { /** * The minimum amount transferred to call `vested_transfer`. diff --git a/tests/src/interfaces/augment-api-errors.ts b/tests/src/interfaces/augment-api-errors.ts index f4c8b15f4e..b5f2652638 100644 --- a/tests/src/interfaces/augment-api-errors.ts +++ b/tests/src/interfaces/augment-api-errors.ts @@ -55,7 +55,7 @@ declare module '@polkadot/api-base/types/errors' { **/ ExistingVestingSchedule: AugmentedError; /** - * Balance too low to send value + * Balance too low to send value. **/ InsufficientBalance: AugmentedError; /** @@ -144,6 +144,10 @@ declare module '@polkadot/api-base/types/errors' { * Token prefix can not be longer than 15 char. **/ CollectionTokenPrefixLimitExceeded: AugmentedError; + /** + * This address is not set as sponsor, use setCollectionSponsor first. + **/ + ConfirmSponsorshipFail: AugmentedError; /** * Empty property keys are forbidden **/ @@ -216,6 +220,10 @@ declare module '@polkadot/api-base/types/errors' { * User does not satisfy the nesting rule **/ UserIsNotAllowedToNest: AugmentedError; + /** + * The user is not an administrator. + **/ + UserIsNotCollectionAdmin: AugmentedError; /** * Generic error **/ @@ -271,6 +279,14 @@ declare module '@polkadot/api-base/types/errors' { * Calculating total fee overflowed **/ FeeOverflow: AugmentedError; + /** + * Gas limit is too high. + **/ + GasLimitTooHigh: AugmentedError; + /** + * Gas limit is too low. + **/ + GasLimitTooLow: AugmentedError; /** * Gas price is too low. **/ @@ -283,6 +299,18 @@ declare module '@polkadot/api-base/types/errors' { * Calculating total payment overflowed **/ PaymentOverflow: AugmentedError; + /** + * EVM reentrancy + **/ + Reentrancy: AugmentedError; + /** + * EIP-3607, + **/ + TransactionMustComeFromEOA: AugmentedError; + /** + * Undefined error. + **/ + Undefined: AugmentedError; /** * Withdraw fee failed **/ @@ -380,6 +408,10 @@ declare module '@polkadot/api-base/types/errors' { * Not Fungible item data used to mint in Fungible collection. **/ NotFungibleDataUsedToMintFungibleCollectionToken: AugmentedError; + /** + * Setting allowance for all is not allowed. + **/ + SettingAllowanceForAllNotAllowed: AugmentedError; /** * Setting item properties is not allowed. **/ @@ -539,6 +571,124 @@ declare module '@polkadot/api-base/types/errors' { **/ [key: string]: AugmentedError; }; + rmrkCore: { + /** + * Not the target owner of the sent NFT. + **/ + CannotAcceptNonOwnedNft: AugmentedError; + /** + * Not the target owner of the sent NFT. + **/ + CannotRejectNonOwnedNft: AugmentedError; + /** + * NFT was not sent and is not pending. + **/ + CannotRejectNonPendingNft: AugmentedError; + /** + * If an NFT is sent to a descendant, that would form a nesting loop, an ouroboros. + * Sending to self is redundant. + **/ + CannotSendToDescendentOrSelf: AugmentedError; + /** + * Too many tokens created in the collection, no new ones are allowed. + **/ + CollectionFullOrLocked: AugmentedError; + /** + * Only destroying collections without tokens is allowed. + **/ + CollectionNotEmpty: AugmentedError; + /** + * Collection does not exist, has a wrong type, or does not map to a Unique ID. + **/ + CollectionUnknown: AugmentedError; + /** + * Property of the type of RMRK collection could not be read successfully. + **/ + CorruptedCollectionType: AugmentedError; + /** + * Could not find an ID for a collection. It is likely there were too many collections created on the chain, causing an overflow. + **/ + NoAvailableCollectionId: AugmentedError; + /** + * Token does not exist, or there is no suitable ID for it, likely too many tokens were created in a collection, causing an overflow. + **/ + NoAvailableNftId: AugmentedError; + /** + * Could not find an ID for the resource. It is likely there were too many resources created on an NFT, causing an overflow. + **/ + NoAvailableResourceId: AugmentedError; + /** + * Token is marked as non-transferable, and thus cannot be transferred. + **/ + NonTransferable: AugmentedError; + /** + * No permission to perform action. + **/ + NoPermission: AugmentedError; + /** + * No such resource found. + **/ + ResourceDoesntExist: AugmentedError; + /** + * Resource is not pending for the operation. + **/ + ResourceNotPending: AugmentedError; + /** + * Could not find a property by the supplied key. + **/ + RmrkPropertyIsNotFound: AugmentedError; + /** + * Too many symbols supplied as the property key. The maximum is [256](up_data_structs::MAX_PROPERTY_KEY_LENGTH). + **/ + RmrkPropertyKeyIsTooLong: AugmentedError; + /** + * Too many bytes supplied as the property value. The maximum is [32768](up_data_structs::MAX_PROPERTY_VALUE_LENGTH). + **/ + RmrkPropertyValueIsTooLong: AugmentedError; + /** + * Something went wrong when decoding encoded data from the storage. + * Perhaps, there was a wrong key supplied for the type, or the data was improperly stored. + **/ + UnableToDecodeRmrkData: AugmentedError; + /** + * Generic error + **/ + [key: string]: AugmentedError; + }; + rmrkEquip: { + /** + * Base collection linked to this ID does not exist. + **/ + BaseDoesntExist: AugmentedError; + /** + * No Theme named "default" is associated with the Base. + **/ + NeedsDefaultThemeFirst: AugmentedError; + /** + * Could not find an ID for a Base collection. It is likely there were too many collections created on the chain, causing an overflow. + **/ + NoAvailableBaseId: AugmentedError; + /** + * Could not find a suitable ID for a Part, likely too many Part tokens were created in the Base, causing an overflow + **/ + NoAvailablePartId: AugmentedError; + /** + * Cannot assign equippables to a fixed Part. + **/ + NoEquippableOnFixedPart: AugmentedError; + /** + * Part linked to this ID does not exist. + **/ + PartDoesntExist: AugmentedError; + /** + * No permission to perform action. + **/ + PermissionError: AugmentedError; + /** + * Generic error + **/ + [key: string]: AugmentedError; + }; structure: { /** * While nesting, reached the breadth limit of nesting, exceeding the provided budget. @@ -605,6 +755,14 @@ declare module '@polkadot/api-base/types/errors' { **/ [key: string]: AugmentedError; }; + testUtils: { + TestPalletDisabled: AugmentedError; + TriggerRollback: AugmentedError; + /** + * Generic error + **/ + [key: string]: AugmentedError; + }; tokens: { /** * Cannot convert Amount into Balance type @@ -672,10 +830,6 @@ declare module '@polkadot/api-base/types/errors' { * Decimal_points parameter must be lower than [`up_data_structs::MAX_DECIMAL_POINTS`]. **/ CollectionDecimalPointLimitExceeded: AugmentedError; - /** - * This address is not set as sponsor, use setCollectionSponsor first. - **/ - ConfirmUnsetSponsorFail: AugmentedError; /** * Length of items properties must be greater than 0. **/ diff --git a/tests/src/interfaces/augment-api-events.ts b/tests/src/interfaces/augment-api-events.ts index 71f90d4a79..d075d1a592 100644 --- a/tests/src/interfaces/augment-api-events.ts +++ b/tests/src/interfaces/augment-api-events.ts @@ -6,9 +6,9 @@ import '@polkadot/api-base/types/events'; import type { ApiTypes, AugmentedEvent } from '@polkadot/api-base/types'; -import type { Bytes, Null, Option, Result, U256, U8aFixed, u128, u32, u64, u8 } from '@polkadot/types-codec'; -import type { AccountId32, H160, H256, Weight } from '@polkadot/types/interfaces/runtime'; -import type { EthereumLog, EvmCoreErrorExitReason, FrameSupportDispatchDispatchInfo, FrameSupportTokensMiscBalanceStatus, OrmlVestingVestingSchedule, PalletEvmAccountBasicCrossAccountIdRepr, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, SpRuntimeDispatchError, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetMultiAssets, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation } from '@polkadot/types/lookup'; +import type { Bytes, Null, Option, Result, U8aFixed, bool, u128, u32, u64, u8 } from '@polkadot/types-codec'; +import type { AccountId32, H160, H256 } from '@polkadot/types/interfaces/runtime'; +import type { EthereumLog, EvmCoreErrorExitReason, FrameSupportDispatchDispatchInfo, FrameSupportTokensMiscBalanceStatus, OrmlVestingVestingSchedule, PalletEvmAccountBasicCrossAccountIdRepr, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, RmrkTraitsNftAccountIdOrCollectionNftTuple, SpRuntimeDispatchError, SpWeightsWeightV2Weight, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetMultiAssets, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation } from '@polkadot/types/lookup'; export type __AugmentedEvent = AugmentedEvent; @@ -101,10 +101,30 @@ declare module '@polkadot/api-base/types/events' { [key: string]: AugmentedEvent; }; common: { + /** + * Address was added to the allow list. + **/ + AllowListAddressAdded: AugmentedEvent; + /** + * Address was removed from the allow list. + **/ + AllowListAddressRemoved: AugmentedEvent; /** * Amount pieces of token owned by `sender` was approved for `spender`. **/ Approved: AugmentedEvent; + /** + * A `sender` approves operations on all owned tokens for `spender`. + **/ + ApprovedForAll: AugmentedEvent; + /** + * Collection admin was added. + **/ + CollectionAdminAdded: AugmentedEvent; + /** + * Collection admin was removed. + **/ + CollectionAdminRemoved: AugmentedEvent; /** * New collection was created **/ @@ -113,6 +133,18 @@ declare module '@polkadot/api-base/types/events' { * New collection was destroyed **/ CollectionDestroyed: AugmentedEvent; + /** + * Collection limits were set. + **/ + CollectionLimitSet: AugmentedEvent; + /** + * Collection owned was changed. + **/ + CollectionOwnerChanged: AugmentedEvent; + /** + * Collection permissions were set. + **/ + CollectionPermissionSet: AugmentedEvent; /** * The property has been deleted. **/ @@ -121,6 +153,14 @@ declare module '@polkadot/api-base/types/events' { * The colletion property has been added or edited. **/ CollectionPropertySet: AugmentedEvent; + /** + * Collection sponsor was removed. + **/ + CollectionSponsorRemoved: AugmentedEvent; + /** + * Collection sponsor was set. + **/ + CollectionSponsorSet: AugmentedEvent; /** * New item was created. **/ @@ -133,6 +173,10 @@ declare module '@polkadot/api-base/types/events' { * The token property permission of a collection has been set. **/ PropertyPermissionSet: AugmentedEvent; + /** + * New sponsor was confirm. + **/ + SponsorshipConfirmed: AugmentedEvent; /** * The token property has been deleted. **/ @@ -183,11 +227,11 @@ declare module '@polkadot/api-base/types/events' { /** * Downward message is overweight and was placed in the overweight queue. **/ - OverweightEnqueued: AugmentedEvent; + OverweightEnqueued: AugmentedEvent; /** * Downward message from the overweight queue was executed. **/ - OverweightServiced: AugmentedEvent; + OverweightServiced: AugmentedEvent; /** * Downward message is unsupported version of XCM. **/ @@ -195,7 +239,7 @@ declare module '@polkadot/api-base/types/events' { /** * The weight limit for handling downward messages was reached. **/ - WeightExhausted: AugmentedEvent; + WeightExhausted: AugmentedEvent; /** * Generic event **/ @@ -203,9 +247,9 @@ declare module '@polkadot/api-base/types/events' { }; ethereum: { /** - * An ethereum transaction was successfully executed. [from, to/contract_address, transaction_hash, exit_reason] + * An ethereum transaction was successfully executed. **/ - Executed: AugmentedEvent; + Executed: AugmentedEvent; /** * Generic event **/ @@ -213,33 +257,25 @@ declare module '@polkadot/api-base/types/events' { }; evm: { /** - * A deposit has been made at a given address. \[sender, address, value\] - **/ - BalanceDeposit: AugmentedEvent; - /** - * A withdrawal has been made from a given address. \[sender, address, value\] + * A contract has been created at given address. **/ - BalanceWithdraw: AugmentedEvent; + Created: AugmentedEvent; /** - * A contract has been created at given \[address\]. + * A contract was attempted to be created, but the execution failed. **/ - Created: AugmentedEvent; + CreatedFailed: AugmentedEvent; /** - * A \[contract\] was attempted to be created, but the execution failed. + * A contract has been executed successfully with states applied. **/ - CreatedFailed: AugmentedEvent; + Executed: AugmentedEvent; /** - * A \[contract\] has been executed successfully with states applied. + * A contract has been executed with errors. States are reverted with only gas fees applied. **/ - Executed: AugmentedEvent; - /** - * A \[contract\] has been executed with errors. States are reverted with only gas fees applied. - **/ - ExecutedFailed: AugmentedEvent; + ExecutedFailed: AugmentedEvent; /** * Ethereum events from contracts. **/ - Log: AugmentedEvent; + Log: AugmentedEvent; /** * Generic event **/ @@ -307,7 +343,7 @@ declare module '@polkadot/api-base/types/events' { /** * Downward messages were processed using the given weight. **/ - DownwardMessagesProcessed: AugmentedEvent; + DownwardMessagesProcessed: AugmentedEvent; /** * Some downward messages have been received and will be processed. **/ @@ -334,6 +370,12 @@ declare module '@polkadot/api-base/types/events' { [key: string]: AugmentedEvent; }; polkadotXcm: { + /** + * Some assets have been claimed from an asset trap + * + * \[ hash, origin, assets \] + **/ + AssetsClaimed: AugmentedEvent; /** * Some assets have been placed in an asset trap. * @@ -395,7 +437,7 @@ declare module '@polkadot/api-base/types/events' { * * \[ id, pallet index, call index, actual weight, max budgeted weight \] **/ - NotifyOverweight: AugmentedEvent; + NotifyOverweight: AugmentedEvent; /** * A given location which had a version change subscription was dropped owing to an error * migrating the location to our new XCM format. @@ -455,6 +497,35 @@ declare module '@polkadot/api-base/types/events' { **/ [key: string]: AugmentedEvent; }; + rmrkCore: { + CollectionCreated: AugmentedEvent; + CollectionDestroyed: AugmentedEvent; + CollectionLocked: AugmentedEvent; + IssuerChanged: AugmentedEvent; + NFTAccepted: AugmentedEvent; + NFTBurned: AugmentedEvent; + NftMinted: AugmentedEvent; + NFTRejected: AugmentedEvent; + NFTSent: AugmentedEvent; + PrioritySet: AugmentedEvent; + PropertySet: AugmentedEvent, key: Bytes, value: Bytes], { collectionId: u32, maybeNftId: Option, key: Bytes, value: Bytes }>; + ResourceAccepted: AugmentedEvent; + ResourceAdded: AugmentedEvent; + ResourceRemoval: AugmentedEvent; + ResourceRemovalAccepted: AugmentedEvent; + /** + * Generic event + **/ + [key: string]: AugmentedEvent; + }; + rmrkEquip: { + BaseCreated: AugmentedEvent; + EquippablesUpdated: AugmentedEvent; + /** + * Generic event + **/ + [key: string]: AugmentedEvent; + }; structure: { /** * Executed call on behalf of the token. @@ -513,6 +584,15 @@ declare module '@polkadot/api-base/types/events' { **/ [key: string]: AugmentedEvent; }; + testUtils: { + BatchCompleted: AugmentedEvent; + ShouldRollback: AugmentedEvent; + ValueIsSet: AugmentedEvent; + /** + * Generic event + **/ + [key: string]: AugmentedEvent; + }; tokens: { /** * A balance was set by root. @@ -622,89 +702,6 @@ declare module '@polkadot/api-base/types/events' { **/ [key: string]: AugmentedEvent; }; - unique: { - /** - * Address was added to the allow list - * - * # Arguments - * * collection_id: ID of the affected collection. - * * user: Address of the added account. - **/ - AllowListAddressAdded: AugmentedEvent; - /** - * Address was removed from the allow list - * - * # Arguments - * * collection_id: ID of the affected collection. - * * user: Address of the removed account. - **/ - AllowListAddressRemoved: AugmentedEvent; - /** - * Collection admin was added - * - * # Arguments - * * collection_id: ID of the affected collection. - * * admin: Admin address. - **/ - CollectionAdminAdded: AugmentedEvent; - /** - * Collection admin was removed - * - * # Arguments - * * collection_id: ID of the affected collection. - * * admin: Removed admin address. - **/ - CollectionAdminRemoved: AugmentedEvent; - /** - * Collection limits were set - * - * # Arguments - * * collection_id: ID of the affected collection. - **/ - CollectionLimitSet: AugmentedEvent; - /** - * Collection owned was changed - * - * # Arguments - * * collection_id: ID of the affected collection. - * * owner: New owner address. - **/ - CollectionOwnedChanged: AugmentedEvent; - /** - * Collection permissions were set - * - * # Arguments - * * collection_id: ID of the affected collection. - **/ - CollectionPermissionSet: AugmentedEvent; - /** - * Collection sponsor was removed - * - * # Arguments - * * collection_id: ID of the affected collection. - **/ - CollectionSponsorRemoved: AugmentedEvent; - /** - * Collection sponsor was set - * - * # Arguments - * * collection_id: ID of the affected collection. - * * owner: New sponsor address. - **/ - CollectionSponsorSet: AugmentedEvent; - /** - * New sponsor was confirm - * - * # Arguments - * * collection_id: ID of the affected collection. - * * sponsor: New sponsor address. - **/ - SponsorshipConfirmed: AugmentedEvent; - /** - * Generic event - **/ - [key: string]: AugmentedEvent; - }; vesting: { /** * Claimed vesting. @@ -735,19 +732,19 @@ declare module '@polkadot/api-base/types/events' { /** * Some XCM failed. **/ - Fail: AugmentedEvent, error: XcmV2TraitsError, weight: Weight], { messageHash: Option, error: XcmV2TraitsError, weight: Weight }>; + Fail: AugmentedEvent, error: XcmV2TraitsError, weight: SpWeightsWeightV2Weight], { messageHash: Option, error: XcmV2TraitsError, weight: SpWeightsWeightV2Weight }>; /** * An XCM exceeded the individual message weight budget. **/ - OverweightEnqueued: AugmentedEvent; + OverweightEnqueued: AugmentedEvent; /** * An XCM from the overweight queue was executed with the given actual weight used. **/ - OverweightServiced: AugmentedEvent; + OverweightServiced: AugmentedEvent; /** * Some XCM was executed ok. **/ - Success: AugmentedEvent, weight: Weight], { messageHash: Option, weight: Weight }>; + Success: AugmentedEvent, weight: SpWeightsWeightV2Weight], { messageHash: Option, weight: SpWeightsWeightV2Weight }>; /** * An upward message was sent to the relay chain. **/ diff --git a/tests/src/interfaces/augment-api-query.ts b/tests/src/interfaces/augment-api-query.ts index 17663ff95d..a7c7b1c1d3 100644 --- a/tests/src/interfaces/augment-api-query.ts +++ b/tests/src/interfaces/augment-api-query.ts @@ -8,8 +8,8 @@ import '@polkadot/api-base/types/storage'; import type { ApiTypes, AugmentedQuery, QueryableStorageEntry } from '@polkadot/api-base/types'; import type { BTreeMap, Bytes, Option, U256, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec'; import type { AnyNumber, ITuple } from '@polkadot/types-codec/types'; -import type { AccountId32, H160, H256, Weight } from '@polkadot/types/interfaces/runtime'; -import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueQueueConfigData, EthereumBlock, EthereumLog, EthereumReceiptReceiptV3, EthereumTransactionTransactionV2, FpRpcTransactionStatus, FrameSupportDispatchPerDispatchClassWeight, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensReserveData, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesReleases, PalletBalancesReserveData, PalletConfigurationAppPromotionConfiguration, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmContractHelpersSponsoringModeT, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletNonfungibleItemData, PalletRefungibleItemData, PalletTransactionPaymentReleases, PalletTreasuryProposal, PhantomTypeUpDataStructs, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpRuntimeDigest, SpTrieStorageProof, UpDataStructsCollection, UpDataStructsCollectionStats, UpDataStructsProperties, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, XcmV1MultiLocation } from '@polkadot/types/lookup'; +import type { AccountId32, H160, H256 } from '@polkadot/types/interfaces/runtime'; +import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueQueueConfigData, EthereumBlock, EthereumLog, EthereumReceiptReceiptV3, EthereumTransactionTransactionV2, FpRpcTransactionStatus, FrameSupportDispatchPerDispatchClassWeight, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensReserveData, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesReserveData, PalletConfigurationAppPromotionConfiguration, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmContractHelpersSponsoringModeT, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletNonfungibleItemData, PalletTransactionPaymentReleases, PalletTreasuryProposal, PhantomTypeUpDataStructs, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpRuntimeDigest, SpTrieStorageProof, SpWeightsWeightV2Weight, UpDataStructsCollection, UpDataStructsCollectionStats, UpDataStructsProperties, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, XcmV1MultiLocation } from '@polkadot/types/lookup'; import type { Observable } from '@polkadot/types/types'; export type __AugmentedQuery = AugmentedQuery unknown>; @@ -87,6 +87,10 @@ declare module '@polkadot/api-base/types/storage' { * NOTE: This is only used in the case that this pallet is used to store balances. **/ account: AugmentedQuery Observable, [AccountId32]> & QueryableStorageEntry; + /** + * The total units of outstanding deactivated balance in the system. + **/ + inactiveIssuance: AugmentedQuery Observable, []> & QueryableStorageEntry; /** * Any liquidity locks on some account balances. * NOTE: Should only be accessed when setting, changing and freeing a lock. @@ -96,12 +100,6 @@ declare module '@polkadot/api-base/types/storage' { * Named reserves on some account balances. **/ reserves: AugmentedQuery Observable>, [AccountId32]> & QueryableStorageEntry; - /** - * Storage version of the pallet. - * - * This is set to v2.0.0 for new networks. - **/ - storageVersion: AugmentedQuery Observable, []> & QueryableStorageEntry; /** * The total units issued in the system. **/ @@ -162,7 +160,7 @@ declare module '@polkadot/api-base/types/storage' { configuration: { appPromomotionConfigurationOverride: AugmentedQuery Observable, []> & QueryableStorageEntry; minGasPriceOverride: AugmentedQuery Observable, []> & QueryableStorageEntry; - weightToFeeCoefficientOverride: AugmentedQuery Observable, []> & QueryableStorageEntry; + weightToFeeCoefficientOverride: AugmentedQuery Observable, []> & QueryableStorageEntry; xcmAllowedLocationsOverride: AugmentedQuery Observable>>, []> & QueryableStorageEntry; /** * Generic query @@ -407,6 +405,10 @@ declare module '@polkadot/api-base/types/storage' { * Allowance set by a token owner for another user to perform one of certain transactions on a token. **/ allowance: AugmentedQuery Observable>, [u32, u32]> & QueryableStorageEntry; + /** + * Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet. + **/ + collectionAllowance: AugmentedQuery Observable, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry; /** * Used to enumerate tokens owned by account. **/ @@ -564,12 +566,12 @@ declare module '@polkadot/api-base/types/storage' { * The weight we reserve at the beginning of the block for processing DMP messages. This * overrides the amount set in the Config trait. **/ - reservedDmpWeightOverride: AugmentedQuery Observable>, []> & QueryableStorageEntry; + reservedDmpWeightOverride: AugmentedQuery Observable>, []> & QueryableStorageEntry; /** * The weight we reserve at the beginning of the block for processing XCMP messages. This * overrides the amount set in the Config trait. **/ - reservedXcmpWeightOverride: AugmentedQuery Observable>, []> & QueryableStorageEntry; + reservedXcmpWeightOverride: AugmentedQuery Observable>, []> & QueryableStorageEntry; /** * An option which indicates if the relay-chain restricts signalling a validation code upgrade. * In other words, if this is `Some` and [`NewValidationCode`] is `Some` then the produced @@ -623,13 +625,13 @@ declare module '@polkadot/api-base/types/storage' { **/ balance: AugmentedQuery Observable, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry; /** - * Used to enumerate tokens owned by account. + * Operator set by a wallet owner that could perform certain transactions on all tokens in the wallet. **/ - owned: AugmentedQuery Observable, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry; + collectionAllowance: AugmentedQuery Observable, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr]> & QueryableStorageEntry; /** - * Token data, used to partially describe a token. + * Used to enumerate tokens owned by account. **/ - tokenData: AugmentedQuery Observable, [u32, u32]> & QueryableStorageEntry; + owned: AugmentedQuery Observable, [u32, PalletEvmAccountBasicCrossAccountIdRepr, u32]> & QueryableStorageEntry; /** * Amount of pieces a refungible token is split into. **/ @@ -651,6 +653,34 @@ declare module '@polkadot/api-base/types/storage' { **/ [key: string]: QueryableStorageEntry; }; + rmrkCore: { + /** + * Latest yet-unused collection ID. + **/ + collectionIndex: AugmentedQuery Observable, []> & QueryableStorageEntry; + /** + * Mapping from RMRK collection ID to Unique's. + **/ + uniqueCollectionId: AugmentedQuery Observable, [u32]> & QueryableStorageEntry; + /** + * Generic query + **/ + [key: string]: QueryableStorageEntry; + }; + rmrkEquip: { + /** + * Checkmark that a Base has a Theme NFT named "default". + **/ + baseHasDefaultTheme: AugmentedQuery Observable, [u32]> & QueryableStorageEntry; + /** + * Map of a Base ID and a Part ID to an NFT in the Base collection serving as the Part. + **/ + inernalPartId: AugmentedQuery Observable>, [u32, u32]> & QueryableStorageEntry; + /** + * Generic query + **/ + [key: string]: QueryableStorageEntry; + }; structure: { /** * Generic query @@ -753,6 +783,14 @@ declare module '@polkadot/api-base/types/storage' { **/ [key: string]: QueryableStorageEntry; }; + testUtils: { + enabled: AugmentedQuery Observable, []> & QueryableStorageEntry; + testValue: AugmentedQuery Observable, []> & QueryableStorageEntry; + /** + * Generic query + **/ + [key: string]: QueryableStorageEntry; + }; timestamp: { /** * Did the timestamp get updated in this block? @@ -808,6 +846,10 @@ declare module '@polkadot/api-base/types/storage' { * Proposal indices that have been approved but not yet awarded. **/ approvals: AugmentedQuery Observable>, []> & QueryableStorageEntry; + /** + * The amount which has been reported as inactive to Currency. + **/ + inactive: AugmentedQuery Observable, []> & QueryableStorageEntry; /** * Number of proposals that have been made. **/ diff --git a/tests/src/interfaces/augment-api-rpc.ts b/tests/src/interfaces/augment-api-rpc.ts index da52e95281..89fae429c8 100644 --- a/tests/src/interfaces/augment-api-rpc.ts +++ b/tests/src/interfaces/augment-api-rpc.ts @@ -5,7 +5,7 @@ // this is required to allow for ambient/previous definitions import '@polkadot/rpc-core/types/jsonrpc'; -import type { PalletEvmAccountBasicCrossAccountIdRepr, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsPartPartType, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceResourceInfo, RmrkTraitsTheme, UpDataStructsCollectionLimits, UpDataStructsCollectionStats, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsRpcCollection, UpDataStructsTokenChild, UpDataStructsTokenData } from './default'; +import type { PalletEvmAccountBasicCrossAccountIdRepr, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsPartPartType, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceResourceInfo, RmrkTraitsTheme, UpDataStructsCollectionLimits, UpDataStructsCollectionStats, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsRpcCollection, UpDataStructsTokenChild, UpDataStructsTokenData, UpPovEstimateRpcPovInfo } from './default'; import type { AugmentedRpc } from '@polkadot/rpc-core/types'; import type { Metadata, StorageKey } from '@polkadot/types'; import type { Bytes, HashMap, Json, Null, Option, Text, U256, U64, Vec, bool, f64, u128, u32, u64 } from '@polkadot/types-codec'; @@ -436,6 +436,12 @@ declare module '@polkadot/rpc-core/types/jsonrpc' { **/ queryInfo: AugmentedRpc<(extrinsic: Bytes | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable>; }; + povinfo: { + /** + * Estimate PoV size of encoded signed extrinsics + **/ + estimateExtrinsicPoV: AugmentedRpc<(encodedXt: Vec | (Bytes | string | Uint8Array)[], at?: Hash | string | Uint8Array) => Observable>; + }; rmrk: { /** * Get tokens owned by an account in a collection @@ -685,6 +691,10 @@ declare module '@polkadot/rpc-core/types/jsonrpc' { * Get the amount of currently possible sponsored transactions on a token for the fee to be taken off a sponsor **/ allowance: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, sender: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, spender: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable>; + /** + * Tells whether the given `owner` approves the `operator`. + **/ + allowanceForAll: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, owner: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, operator: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, at?: Hash | string | Uint8Array) => Observable>>; /** * Check if a user is allowed to operate within a collection **/ diff --git a/tests/src/interfaces/augment-api-runtime.ts b/tests/src/interfaces/augment-api-runtime.ts index 7eb79bd3b4..b98b998ea8 100644 --- a/tests/src/interfaces/augment-api-runtime.ts +++ b/tests/src/interfaces/augment-api-runtime.ts @@ -229,7 +229,7 @@ declare module '@polkadot/api-base/types/calls' { **/ [key: string]: DecoratedCallBase; }; - /** 0x37c8bb1350a9a2a8/1 */ + /** 0x37c8bb1350a9a2a8/2 */ transactionPaymentApi: { /** * The transaction fee details diff --git a/tests/src/interfaces/augment-api-tx.ts b/tests/src/interfaces/augment-api-tx.ts index 2553e79a1a..fa4fe06c9e 100644 --- a/tests/src/interfaces/augment-api-tx.ts +++ b/tests/src/interfaces/augment-api-tx.ts @@ -8,8 +8,8 @@ import '@polkadot/api-base/types/submittable'; import type { ApiTypes, AugmentedSubmittable, SubmittableExtrinsic, SubmittableExtrinsicFunction } from '@polkadot/api-base/types'; import type { Bytes, Compact, Option, U256, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec'; import type { AnyNumber, IMethod, ITuple } from '@polkadot/types-codec/types'; -import type { AccountId32, Call, H160, H256, MultiAddress, Perbill, Weight } from '@polkadot/types/interfaces/runtime'; -import type { CumulusPrimitivesParachainInherentParachainInherentData, EthereumLog, EthereumTransactionTransactionV2, OrmlVestingVestingSchedule, PalletConfigurationAppPromotionConfiguration, PalletEvmAccountBasicCrossAccountIdRepr, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCreateCollectionData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, XcmV1MultiLocation, XcmV2WeightLimit, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup'; +import type { AccountId32, Call, H160, H256, MultiAddress, Permill } from '@polkadot/types/interfaces/runtime'; +import type { CumulusPrimitivesParachainInherentParachainInherentData, EthereumLog, EthereumTransactionTransactionV2, OrmlVestingVestingSchedule, PalletConfigurationAppPromotionConfiguration, PalletEvmAccountBasicCrossAccountIdRepr, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsPartEquippableList, RmrkTraitsPartPartType, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, SpWeightsWeightV2Weight, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCreateCollectionData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, XcmV1MultiLocation, XcmV2WeightLimit, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup'; export type __AugmentedSubmittable = AugmentedSubmittable<() => unknown>; export type __SubmittableExtrinsic = SubmittableExtrinsic; @@ -217,7 +217,7 @@ declare module '@polkadot/api-base/types/submittable' { configuration: { setAppPromotionConfigurationOverride: AugmentedSubmittable<(configuration: PalletConfigurationAppPromotionConfiguration | { recalculationInterval?: any; pendingInterval?: any; intervalIncome?: any; maxStakersPerCalculation?: any } | string | Uint8Array) => SubmittableExtrinsic, [PalletConfigurationAppPromotionConfiguration]>; setMinGasPriceOverride: AugmentedSubmittable<(coeff: Option | null | Uint8Array | u64 | AnyNumber) => SubmittableExtrinsic, [Option]>; - setWeightToFeeCoefficientOverride: AugmentedSubmittable<(coeff: Option | null | Uint8Array | u32 | AnyNumber) => SubmittableExtrinsic, [Option]>; + setWeightToFeeCoefficientOverride: AugmentedSubmittable<(coeff: Option | null | Uint8Array | u64 | AnyNumber) => SubmittableExtrinsic, [Option]>; setXcmAllowedLocations: AugmentedSubmittable<(locations: Option> | null | Uint8Array | Vec | (XcmV1MultiLocation | { parents?: any; interior?: any } | string | Uint8Array)[]) => SubmittableExtrinsic, [Option>]>; /** * Generic tx @@ -245,7 +245,7 @@ declare module '@polkadot/api-base/types/submittable' { * Events: * - `OverweightServiced`: On success. **/ - serviceOverweight: AugmentedSubmittable<(index: u64 | AnyNumber | Uint8Array, weightLimit: Weight | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u64, Weight]>; + serviceOverweight: AugmentedSubmittable<(index: u64 | AnyNumber | Uint8Array, weightLimit: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u64, u64]>; /** * Generic tx **/ @@ -385,7 +385,7 @@ declare module '@polkadot/api-base/types/submittable' { * NOTE: A successful return to this does *not* imply that the `msg` was executed successfully * to completion; only that *some* of it was executed. **/ - execute: AugmentedSubmittable<(message: XcmVersionedXcm | { V0: any } | { V1: any } | { V2: any } | string | Uint8Array, maxWeight: Weight | AnyNumber | Uint8Array) => SubmittableExtrinsic, [XcmVersionedXcm, Weight]>; + execute: AugmentedSubmittable<(message: XcmVersionedXcm | { V0: any } | { V1: any } | { V2: any } | string | Uint8Array, maxWeight: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [XcmVersionedXcm, u64]>; /** * Set a safe XCM version (the version that XCM should be encoded with if the most recent * version a destination can accept is unknown). @@ -503,6 +503,342 @@ declare module '@polkadot/api-base/types/submittable' { **/ [key: string]: SubmittableExtrinsicFunction; }; + rmrkCore: { + /** + * Accept an NFT sent from another account to self or an owned NFT. + * + * The NFT in question must be pending, and, thus, be [sent](`Pallet::send`) first. + * + * # Permissions: + * - Token-owner-to-be + * + * # Arguments: + * - `origin`: sender of the transaction + * - `rmrk_collection_id`: RMRK collection ID of the NFT to be accepted. + * - `rmrk_nft_id`: ID of the NFT to be accepted. + * - `new_owner`: Either the sender's account ID or a sender-owned NFT, + * whichever the accepted NFT was sent to. + **/ + acceptNft: AugmentedSubmittable<(rmrkCollectionId: u32 | AnyNumber | Uint8Array, rmrkNftId: u32 | AnyNumber | Uint8Array, newOwner: RmrkTraitsNftAccountIdOrCollectionNftTuple | { AccountId: any } | { CollectionAndNftTuple: any } | string | Uint8Array) => SubmittableExtrinsic, [u32, u32, RmrkTraitsNftAccountIdOrCollectionNftTuple]>; + /** + * Accept the addition of a newly created pending resource to an existing NFT. + * + * This transaction is needed when a resource is created and assigned to an NFT + * by a non-owner, i.e. the collection issuer, with one of the + * [`add_...` transactions](Pallet::add_basic_resource). + * + * # Permissions: + * - Token owner + * + * # Arguments: + * - `origin`: sender of the transaction + * - `rmrk_collection_id`: RMRK collection ID of the NFT. + * - `rmrk_nft_id`: ID of the NFT with a pending resource to be accepted. + * - `resource_id`: ID of the newly created pending resource. + * accept the addition of a new resource to an existing NFT + **/ + acceptResource: AugmentedSubmittable<(rmrkCollectionId: u32 | AnyNumber | Uint8Array, rmrkNftId: u32 | AnyNumber | Uint8Array, resourceId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32, u32, u32]>; + /** + * Accept the removal of a removal-pending resource from an NFT. + * + * This transaction is needed when a non-owner, i.e. the collection issuer, + * requests a [removal](`Pallet::remove_resource`) of a resource from an NFT. + * + * # Permissions: + * - Token owner + * + * # Arguments: + * - `origin`: sender of the transaction + * - `rmrk_collection_id`: RMRK collection ID of the NFT. + * - `rmrk_nft_id`: ID of the NFT with a resource to be removed. + * - `resource_id`: ID of the removal-pending resource. + **/ + acceptResourceRemoval: AugmentedSubmittable<(rmrkCollectionId: u32 | AnyNumber | Uint8Array, rmrkNftId: u32 | AnyNumber | Uint8Array, resourceId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32, u32, u32]>; + /** + * Create and set/propose a basic resource for an NFT. + * + * A basic resource is the simplest, lacking a Base and anything that comes with it. + * See RMRK docs for more information and examples. + * + * # Permissions: + * - Collection issuer - if not the token owner, adding the resource will warrant + * the owner's [acceptance](Pallet::accept_resource). + * + * # Arguments: + * - `origin`: sender of the transaction + * - `rmrk_collection_id`: RMRK collection ID of the NFT. + * - `nft_id`: ID of the NFT to assign a resource to. + * - `resource`: Data of the resource to be created. + **/ + addBasicResource: AugmentedSubmittable<(rmrkCollectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, resource: RmrkTraitsResourceBasicResource | { src?: any; metadata?: any; license?: any; thumb?: any } | string | Uint8Array) => SubmittableExtrinsic, [u32, u32, RmrkTraitsResourceBasicResource]>; + /** + * Create and set/propose a composable resource for an NFT. + * + * A composable resource links to a Base and has a subset of its Parts it is composed of. + * See RMRK docs for more information and examples. + * + * # Permissions: + * - Collection issuer - if not the token owner, adding the resource will warrant + * the owner's [acceptance](Pallet::accept_resource). + * + * # Arguments: + * - `origin`: sender of the transaction + * - `rmrk_collection_id`: RMRK collection ID of the NFT. + * - `nft_id`: ID of the NFT to assign a resource to. + * - `resource`: Data of the resource to be created. + **/ + addComposableResource: AugmentedSubmittable<(rmrkCollectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, resource: RmrkTraitsResourceComposableResource | { parts?: any; base?: any; src?: any; metadata?: any; license?: any; thumb?: any } | string | Uint8Array) => SubmittableExtrinsic, [u32, u32, RmrkTraitsResourceComposableResource]>; + /** + * Create and set/propose a slot resource for an NFT. + * + * A slot resource links to a Base and a slot ID in it which it can fit into. + * See RMRK docs for more information and examples. + * + * # Permissions: + * - Collection issuer - if not the token owner, adding the resource will warrant + * the owner's [acceptance](Pallet::accept_resource). + * + * # Arguments: + * - `origin`: sender of the transaction + * - `rmrk_collection_id`: RMRK collection ID of the NFT. + * - `nft_id`: ID of the NFT to assign a resource to. + * - `resource`: Data of the resource to be created. + **/ + addSlotResource: AugmentedSubmittable<(rmrkCollectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, resource: RmrkTraitsResourceSlotResource | { base?: any; src?: any; metadata?: any; slot?: any; license?: any; thumb?: any } | string | Uint8Array) => SubmittableExtrinsic, [u32, u32, RmrkTraitsResourceSlotResource]>; + /** + * Burn an NFT, destroying it and its nested tokens up to the specified limit. + * If the burning budget is exceeded, the transaction is reverted. + * + * This is the way to burn a nested token as well. + * + * For more information, see [`burn_recursively`](pallet_nonfungible::pallet::Pallet::burn_recursively). + * + * # Permissions: + * * Token owner + * + * # Arguments: + * - `origin`: sender of the transaction + * - `collection_id`: RMRK ID of the collection in which the NFT to burn belongs to. + * - `nft_id`: ID of the NFT to be destroyed. + * - `max_burns`: Maximum number of tokens to burn, assuming nesting. The transaction + * is reverted if there are more tokens to burn in the nesting tree than this number. + * This is primarily a mechanism of transaction weight control. + **/ + burnNft: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, maxBurns: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32, u32, u32]>; + /** + * Change the issuer of a collection. Analogous to Unique's collection's [`owner`](up_data_structs::Collection). + * + * # Permissions: + * * Collection issuer + * + * # Arguments: + * - `origin`: sender of the transaction + * - `collection_id`: RMRK collection ID to change the issuer of. + * - `new_issuer`: Collection's new issuer. + **/ + changeCollectionIssuer: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, newIssuer: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array) => SubmittableExtrinsic, [u32, MultiAddress]>; + /** + * Create a new collection of NFTs. + * + * # Permissions: + * * Anyone - will be assigned as the issuer of the collection. + * + * # Arguments: + * - `origin`: sender of the transaction + * - `metadata`: Metadata describing the collection, e.g. IPFS hash. Cannot be changed. + * - `max`: Optional maximum number of tokens. + * - `symbol`: UTF-8 string with token prefix, by which to represent the token in wallets and UIs. + * Analogous to Unique's [`token_prefix`](up_data_structs::Collection). Cannot be changed. + **/ + createCollection: AugmentedSubmittable<(metadata: Bytes | string | Uint8Array, max: Option | null | Uint8Array | u32 | AnyNumber, symbol: Bytes | string | Uint8Array) => SubmittableExtrinsic, [Bytes, Option, Bytes]>; + /** + * Destroy a collection. + * + * Only empty collections can be destroyed. If it has any tokens, they must be burned first. + * + * # Permissions: + * * Collection issuer + * + * # Arguments: + * - `origin`: sender of the transaction + * - `collection_id`: RMRK ID of the collection to destroy. + **/ + destroyCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32]>; + /** + * "Lock" the collection and prevent new token creation. Cannot be undone. + * + * # Permissions: + * * Collection issuer + * + * # Arguments: + * - `origin`: sender of the transaction + * - `collection_id`: RMRK ID of the collection to lock. + **/ + lockCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32]>; + /** + * Mint an NFT in a specified collection. + * + * # Permissions: + * * Collection issuer + * + * # Arguments: + * - `origin`: sender of the transaction + * - `owner`: Owner account of the NFT. If set to None, defaults to the sender (collection issuer). + * - `collection_id`: RMRK collection ID for the NFT to be minted within. Cannot be changed. + * - `recipient`: Receiver account of the royalty. Has no effect if the `royalty_amount` is not set. Cannot be changed. + * - `royalty_amount`: Optional permillage reward from each trade for the `recipient`. Cannot be changed. + * - `metadata`: Arbitrary data about an NFT, e.g. IPFS hash. Cannot be changed. + * - `transferable`: Can this NFT be transferred? Cannot be changed. + * - `resources`: Resource data to be added to the NFT immediately after minting. + **/ + mintNft: AugmentedSubmittable<(owner: Option | null | Uint8Array | AccountId32 | string, collectionId: u32 | AnyNumber | Uint8Array, recipient: Option | null | Uint8Array | AccountId32 | string, royaltyAmount: Option | null | Uint8Array | Permill | AnyNumber, metadata: Bytes | string | Uint8Array, transferable: bool | boolean | Uint8Array, resources: Option> | null | Uint8Array | Vec | (RmrkTraitsResourceResourceTypes | { Basic: any } | { Composable: any } | { Slot: any } | string | Uint8Array)[]) => SubmittableExtrinsic, [Option, u32, Option, Option, Bytes, bool, Option>]>; + /** + * Reject an NFT sent from another account to self or owned NFT. + * The NFT in question will not be sent back and burnt instead. + * + * The NFT in question must be pending, and, thus, be [sent](`Pallet::send`) first. + * + * # Permissions: + * - Token-owner-to-be-not + * + * # Arguments: + * - `origin`: sender of the transaction + * - `rmrk_collection_id`: RMRK ID of the NFT to be rejected. + * - `rmrk_nft_id`: ID of the NFT to be rejected. + **/ + rejectNft: AugmentedSubmittable<(rmrkCollectionId: u32 | AnyNumber | Uint8Array, rmrkNftId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32, u32]>; + /** + * Remove and erase a resource from an NFT. + * + * If the sender does not own the NFT, then it will be pending confirmation, + * and will have to be [accepted](Pallet::accept_resource_removal) by the token owner. + * + * # Permissions + * - Collection issuer + * + * # Arguments + * - `origin`: sender of the transaction + * - `rmrk_collection_id`: RMRK ID of a collection to which the NFT making use of the resource belongs to. + * - `nft_id`: ID of the NFT with a resource to be removed. + * - `resource_id`: ID of the resource to be removed. + **/ + removeResource: AugmentedSubmittable<(rmrkCollectionId: u32 | AnyNumber | Uint8Array, nftId: u32 | AnyNumber | Uint8Array, resourceId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32, u32, u32]>; + /** + * Transfer an NFT from an account/NFT A to another account/NFT B. + * The token must be transferable. Nesting cannot occur deeper than the [`NESTING_BUDGET`]. + * + * If the target owner is an NFT owned by another account, then the NFT will enter + * the pending state and will have to be accepted by the other account. + * + * # Permissions: + * - Token owner + * + * # Arguments: + * - `origin`: sender of the transaction + * - `rmrk_collection_id`: RMRK ID of the collection of the NFT to be transferred. + * - `rmrk_nft_id`: ID of the NFT to be transferred. + * - `new_owner`: New owner of the nft which can be either an account or a NFT. + **/ + send: AugmentedSubmittable<(rmrkCollectionId: u32 | AnyNumber | Uint8Array, rmrkNftId: u32 | AnyNumber | Uint8Array, newOwner: RmrkTraitsNftAccountIdOrCollectionNftTuple | { AccountId: any } | { CollectionAndNftTuple: any } | string | Uint8Array) => SubmittableExtrinsic, [u32, u32, RmrkTraitsNftAccountIdOrCollectionNftTuple]>; + /** + * Set a different order of resource priorities for an NFT. Priorities can be used, + * for example, for order of rendering. + * + * Note that the priorities are not updated automatically, and are an empty vector + * by default. There is no pre-set definition for the order to be particular, + * it can be interpreted arbitrarily use-case by use-case. + * + * # Permissions: + * - Token owner + * + * # Arguments: + * - `origin`: sender of the transaction + * - `rmrk_collection_id`: RMRK collection ID of the NFT. + * - `rmrk_nft_id`: ID of the NFT to rearrange resource priorities for. + * - `priorities`: Ordered vector of resource IDs. + **/ + setPriority: AugmentedSubmittable<(rmrkCollectionId: u32 | AnyNumber | Uint8Array, rmrkNftId: u32 | AnyNumber | Uint8Array, priorities: Vec | (u32 | AnyNumber | Uint8Array)[]) => SubmittableExtrinsic, [u32, u32, Vec]>; + /** + * Add or edit a custom user property, a key-value pair, describing the metadata + * of a token or a collection, on either one of these. + * + * Note that in this proxy implementation many details regarding RMRK are stored + * as scoped properties prefixed with "rmrk:", normally inaccessible + * to external transactions and RPCs. + * + * # Permissions: + * - Collection issuer - in case of collection property + * - Token owner - in case of NFT property + * + * # Arguments: + * - `origin`: sender of the transaction + * - `rmrk_collection_id`: RMRK collection ID. + * - `maybe_nft_id`: Optional ID of the NFT. If left empty, then the property is set for the collection. + * - `key`: Key of the custom property to be referenced by. + * - `value`: Value of the custom property to be stored. + **/ + setProperty: AugmentedSubmittable<(rmrkCollectionId: Compact | AnyNumber | Uint8Array, maybeNftId: Option | null | Uint8Array | u32 | AnyNumber, key: Bytes | string | Uint8Array, value: Bytes | string | Uint8Array) => SubmittableExtrinsic, [Compact, Option, Bytes, Bytes]>; + /** + * Generic tx + **/ + [key: string]: SubmittableExtrinsicFunction; + }; + rmrkEquip: { + /** + * Create a new Base. + * + * Modeled after the [Base interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/base.md) + * + * # Permissions + * - Anyone - will be assigned as the issuer of the Base. + * + * # Arguments: + * - `origin`: Caller, will be assigned as the issuer of the Base + * - `base_type`: Arbitrary media type, e.g. "svg". + * - `symbol`: Arbitrary client-chosen symbol. + * - `parts`: Array of Fixed and Slot Parts composing the Base, + * confined in length by [`RmrkPartsLimit`](up_data_structs::RmrkPartsLimit). + **/ + createBase: AugmentedSubmittable<(baseType: Bytes | string | Uint8Array, symbol: Bytes | string | Uint8Array, parts: Vec | (RmrkTraitsPartPartType | { FixedPart: any } | { SlotPart: any } | string | Uint8Array)[]) => SubmittableExtrinsic, [Bytes, Bytes, Vec]>; + /** + * Update the array of Collections allowed to be equipped to a Base's specified Slot Part. + * + * Modeled after [equippable interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/equippable.md). + * + * # Permissions: + * - Base issuer + * + * # Arguments: + * - `origin`: sender of the transaction + * - `base_id`: Base containing the Slot Part to be updated. + * - `slot_id`: Slot Part whose Equippable List is being updated . + * - `equippables`: List of equippables that will override the current Equippables list. + **/ + equippable: AugmentedSubmittable<(baseId: u32 | AnyNumber | Uint8Array, slotId: u32 | AnyNumber | Uint8Array, equippables: RmrkTraitsPartEquippableList | { All: any } | { Empty: any } | { Custom: any } | string | Uint8Array) => SubmittableExtrinsic, [u32, u32, RmrkTraitsPartEquippableList]>; + /** + * Add a Theme to a Base. + * A Theme named "default" is required prior to adding other Themes. + * + * Modeled after [Themeadd interaction](https://github.com/rmrk-team/rmrk-spec/blob/master/standards/rmrk2.0.0/interactions/themeadd.md). + * + * # Permissions: + * - Base issuer + * + * # Arguments: + * - `origin`: sender of the transaction + * - `base_id`: Base ID containing the Theme to be updated. + * - `theme`: Theme to add to the Base. A Theme has a name and properties, which are an + * array of [key, value, inherit]. + * - `key`: Arbitrary BoundedString, defined by client. + * - `value`: Arbitrary BoundedString, defined by client. + * - `inherit`: Optional bool. + **/ + themeAdd: AugmentedSubmittable<(baseId: u32 | AnyNumber | Uint8Array, theme: RmrkTraitsTheme | { name?: any; properties?: any; inherit?: any } | string | Uint8Array) => SubmittableExtrinsic, [u32, RmrkTraitsTheme]>; + /** + * Generic tx + **/ + [key: string]: SubmittableExtrinsicFunction; + }; structure: { /** * Generic tx @@ -562,17 +898,13 @@ declare module '@polkadot/api-base/types/submittable' { * - The weight of this call is defined by the caller. * # **/ - sudoUncheckedWeight: AugmentedSubmittable<(call: Call | IMethod | string | Uint8Array, weight: Weight | AnyNumber | Uint8Array) => SubmittableExtrinsic, [Call, Weight]>; + sudoUncheckedWeight: AugmentedSubmittable<(call: Call | IMethod | string | Uint8Array, weight: SpWeightsWeightV2Weight | { refTime?: any; proofSize?: any } | string | Uint8Array) => SubmittableExtrinsic, [Call, SpWeightsWeightV2Weight]>; /** * Generic tx **/ [key: string]: SubmittableExtrinsicFunction; }; system: { - /** - * A dispatch that will fill the block weight up to the given ratio. - **/ - fillBlock: AugmentedSubmittable<(ratio: Perbill | AnyNumber | Uint8Array) => SubmittableExtrinsic, [Perbill]>; /** * Kill all storage items with a key that starts with the given prefix. * @@ -636,6 +968,18 @@ declare module '@polkadot/api-base/types/submittable' { **/ [key: string]: SubmittableExtrinsicFunction; }; + testUtils: { + batchAll: AugmentedSubmittable<(calls: Vec | (Call | IMethod | string | Uint8Array)[]) => SubmittableExtrinsic, [Vec]>; + enable: AugmentedSubmittable<() => SubmittableExtrinsic, []>; + incTestValue: AugmentedSubmittable<() => SubmittableExtrinsic, []>; + justTakeFee: AugmentedSubmittable<() => SubmittableExtrinsic, []>; + setTestValue: AugmentedSubmittable<(value: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32]>; + setTestValueAndRollback: AugmentedSubmittable<(value: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32]>; + /** + * Generic tx + **/ + [key: string]: SubmittableExtrinsicFunction; + }; timestamp: { /** * Set the current time. @@ -1083,6 +1427,23 @@ declare module '@polkadot/api-base/types/submittable' { * * `collection_id`: Collection to destroy. **/ destroyCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32]>; + /** + * Repairs a collection if the data was somehow corrupted. + * + * # Arguments + * + * * `collection_id`: ID of the collection to repair. + **/ + forceRepairCollection: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32]>; + /** + * Repairs a token if the data was somehow corrupted. + * + * # Arguments + * + * * `collection_id`: ID of the collection the item belongs to. + * * `item_id`: ID of the item. + **/ + forceRepairItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32, u32]>; /** * Remove admin of a collection. * @@ -1126,15 +1487,6 @@ declare module '@polkadot/api-base/types/submittable' { * * `address`: ID of the address to be removed from the allowlist. **/ removeFromAllowList: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, address: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array) => SubmittableExtrinsic, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>; - /** - * Repairs a broken item - * - * # Arguments - * - * * `collection_id`: ID of the collection the item belongs to. - * * `item_id`: ID of the item. - **/ - repairItem: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, itemId: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32, u32]>; /** * Re-partition a refungible token, while owning all of its parts/pieces. * @@ -1149,6 +1501,18 @@ declare module '@polkadot/api-base/types/submittable' { * * `amount`: New number of parts/pieces into which the token shall be partitioned. **/ repartition: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, amount: u128 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u32, u32, u128]>; + /** + * Sets or unsets the approval of a given operator. + * + * The `operator` is allowed to transfer all tokens of the `owner` on their behalf. + * + * # Arguments + * + * * `owner`: Token owner + * * `operator`: Operator + * * `approve`: Should operator status be granted or revoked? + **/ + setAllowanceForAll: AugmentedSubmittable<(collectionId: u32 | AnyNumber | Uint8Array, operator: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, approve: bool | boolean | Uint8Array) => SubmittableExtrinsic, [u32, PalletEvmAccountBasicCrossAccountIdRepr, bool]>; /** * Set specific limits of a collection. Empty, or None fields mean chain default. * @@ -1352,7 +1716,7 @@ declare module '@polkadot/api-base/types/submittable' { * Events: * - `OverweightServiced`: On success. **/ - serviceOverweight: AugmentedSubmittable<(index: u64 | AnyNumber | Uint8Array, weightLimit: Weight | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u64, Weight]>; + serviceOverweight: AugmentedSubmittable<(index: u64 | AnyNumber | Uint8Array, weightLimit: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u64, u64]>; /** * Suspends all XCM executions for the XCMP queue, regardless of the sender's origin. * @@ -1389,7 +1753,7 @@ declare module '@polkadot/api-base/types/submittable' { * - `origin`: Must pass `Root`. * - `new`: Desired value for `QueueConfigData.threshold_weight` **/ - updateThresholdWeight: AugmentedSubmittable<(updated: Weight | AnyNumber | Uint8Array) => SubmittableExtrinsic, [Weight]>; + updateThresholdWeight: AugmentedSubmittable<(updated: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u64]>; /** * Overwrites the speed to which the available weight approaches the maximum weight. * A lower number results in a faster progression. A value of 1 makes the entire weight available initially. @@ -1397,7 +1761,7 @@ declare module '@polkadot/api-base/types/submittable' { * - `origin`: Must pass `Root`. * - `new`: Desired value for `QueueConfigData.weight_restrict_decay`. **/ - updateWeightRestrictDecay: AugmentedSubmittable<(updated: Weight | AnyNumber | Uint8Array) => SubmittableExtrinsic, [Weight]>; + updateWeightRestrictDecay: AugmentedSubmittable<(updated: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u64]>; /** * Overwrite the maximum amount of weight any individual message may consume. * Messages above this weight go into the overweight queue and may only be serviced explicitly. @@ -1405,7 +1769,7 @@ declare module '@polkadot/api-base/types/submittable' { * - `origin`: Must pass `Root`. * - `new`: Desired value for `QueueConfigData.xcmp_max_individual_weight`. **/ - updateXcmpMaxIndividualWeight: AugmentedSubmittable<(updated: Weight | AnyNumber | Uint8Array) => SubmittableExtrinsic, [Weight]>; + updateXcmpMaxIndividualWeight: AugmentedSubmittable<(updated: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [u64]>; /** * Generic tx **/ @@ -1415,9 +1779,9 @@ declare module '@polkadot/api-base/types/submittable' { /** * Transfer native currencies. * - * `dest_weight` is the weight for XCM execution on the dest chain, and - * it would be charged from the transferred assets. If set below - * requirements, the execution may fail and assets wouldn't be + * `dest_weight_limit` is the weight for XCM execution on the dest + * chain, and it would be charged from the transferred assets. If set + * below requirements, the execution may fail and assets wouldn't be * received. * * It's a no-op if any error on local XCM execution or message sending. @@ -1426,13 +1790,13 @@ declare module '@polkadot/api-base/types/submittable' { * by the network, and if the receiving chain would handle * messages correctly. **/ - transfer: AugmentedSubmittable<(currencyId: PalletForeignAssetsAssetIds | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: u128 | AnyNumber | Uint8Array, dest: XcmVersionedMultiLocation | { V0: any } | { V1: any } | string | Uint8Array, destWeight: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [PalletForeignAssetsAssetIds, u128, XcmVersionedMultiLocation, u64]>; + transfer: AugmentedSubmittable<(currencyId: PalletForeignAssetsAssetIds | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: u128 | AnyNumber | Uint8Array, dest: XcmVersionedMultiLocation | { V0: any } | { V1: any } | string | Uint8Array, destWeightLimit: XcmV2WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic, [PalletForeignAssetsAssetIds, u128, XcmVersionedMultiLocation, XcmV2WeightLimit]>; /** * Transfer `MultiAsset`. * - * `dest_weight` is the weight for XCM execution on the dest chain, and - * it would be charged from the transferred assets. If set below - * requirements, the execution may fail and assets wouldn't be + * `dest_weight_limit` is the weight for XCM execution on the dest + * chain, and it would be charged from the transferred assets. If set + * below requirements, the execution may fail and assets wouldn't be * received. * * It's a no-op if any error on local XCM execution or message sending. @@ -1441,13 +1805,13 @@ declare module '@polkadot/api-base/types/submittable' { * by the network, and if the receiving chain would handle * messages correctly. **/ - transferMultiasset: AugmentedSubmittable<(asset: XcmVersionedMultiAsset | { V0: any } | { V1: any } | string | Uint8Array, dest: XcmVersionedMultiLocation | { V0: any } | { V1: any } | string | Uint8Array, destWeight: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [XcmVersionedMultiAsset, XcmVersionedMultiLocation, u64]>; + transferMultiasset: AugmentedSubmittable<(asset: XcmVersionedMultiAsset | { V0: any } | { V1: any } | string | Uint8Array, dest: XcmVersionedMultiLocation | { V0: any } | { V1: any } | string | Uint8Array, destWeightLimit: XcmV2WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic, [XcmVersionedMultiAsset, XcmVersionedMultiLocation, XcmV2WeightLimit]>; /** * Transfer several `MultiAsset` specifying the item to be used as fee * - * `dest_weight` is the weight for XCM execution on the dest chain, and - * it would be charged from the transferred assets. If set below - * requirements, the execution may fail and assets wouldn't be + * `dest_weight_limit` is the weight for XCM execution on the dest + * chain, and it would be charged from the transferred assets. If set + * below requirements, the execution may fail and assets wouldn't be * received. * * `fee_item` is index of the MultiAssets that we want to use for @@ -1459,13 +1823,13 @@ declare module '@polkadot/api-base/types/submittable' { * by the network, and if the receiving chain would handle * messages correctly. **/ - transferMultiassets: AugmentedSubmittable<(assets: XcmVersionedMultiAssets | { V0: any } | { V1: any } | string | Uint8Array, feeItem: u32 | AnyNumber | Uint8Array, dest: XcmVersionedMultiLocation | { V0: any } | { V1: any } | string | Uint8Array, destWeight: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [XcmVersionedMultiAssets, u32, XcmVersionedMultiLocation, u64]>; + transferMultiassets: AugmentedSubmittable<(assets: XcmVersionedMultiAssets | { V0: any } | { V1: any } | string | Uint8Array, feeItem: u32 | AnyNumber | Uint8Array, dest: XcmVersionedMultiLocation | { V0: any } | { V1: any } | string | Uint8Array, destWeightLimit: XcmV2WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic, [XcmVersionedMultiAssets, u32, XcmVersionedMultiLocation, XcmV2WeightLimit]>; /** * Transfer `MultiAsset` specifying the fee and amount as separate. * - * `dest_weight` is the weight for XCM execution on the dest chain, and - * it would be charged from the transferred assets. If set below - * requirements, the execution may fail and assets wouldn't be + * `dest_weight_limit` is the weight for XCM execution on the dest + * chain, and it would be charged from the transferred assets. If set + * below requirements, the execution may fail and assets wouldn't be * received. * * `fee` is the multiasset to be spent to pay for execution in @@ -1483,13 +1847,13 @@ declare module '@polkadot/api-base/types/submittable' { * by the network, and if the receiving chain would handle * messages correctly. **/ - transferMultiassetWithFee: AugmentedSubmittable<(asset: XcmVersionedMultiAsset | { V0: any } | { V1: any } | string | Uint8Array, fee: XcmVersionedMultiAsset | { V0: any } | { V1: any } | string | Uint8Array, dest: XcmVersionedMultiLocation | { V0: any } | { V1: any } | string | Uint8Array, destWeight: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [XcmVersionedMultiAsset, XcmVersionedMultiAsset, XcmVersionedMultiLocation, u64]>; + transferMultiassetWithFee: AugmentedSubmittable<(asset: XcmVersionedMultiAsset | { V0: any } | { V1: any } | string | Uint8Array, fee: XcmVersionedMultiAsset | { V0: any } | { V1: any } | string | Uint8Array, dest: XcmVersionedMultiLocation | { V0: any } | { V1: any } | string | Uint8Array, destWeightLimit: XcmV2WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic, [XcmVersionedMultiAsset, XcmVersionedMultiAsset, XcmVersionedMultiLocation, XcmV2WeightLimit]>; /** * Transfer several currencies specifying the item to be used as fee * - * `dest_weight` is the weight for XCM execution on the dest chain, and - * it would be charged from the transferred assets. If set below - * requirements, the execution may fail and assets wouldn't be + * `dest_weight_limit` is the weight for XCM execution on the dest + * chain, and it would be charged from the transferred assets. If set + * below requirements, the execution may fail and assets wouldn't be * received. * * `fee_item` is index of the currencies tuple that we want to use for @@ -1501,14 +1865,14 @@ declare module '@polkadot/api-base/types/submittable' { * by the network, and if the receiving chain would handle * messages correctly. **/ - transferMulticurrencies: AugmentedSubmittable<(currencies: Vec> | ([PalletForeignAssetsAssetIds | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, u128 | AnyNumber | Uint8Array])[], feeItem: u32 | AnyNumber | Uint8Array, dest: XcmVersionedMultiLocation | { V0: any } | { V1: any } | string | Uint8Array, destWeight: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [Vec>, u32, XcmVersionedMultiLocation, u64]>; + transferMulticurrencies: AugmentedSubmittable<(currencies: Vec> | ([PalletForeignAssetsAssetIds | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, u128 | AnyNumber | Uint8Array])[], feeItem: u32 | AnyNumber | Uint8Array, dest: XcmVersionedMultiLocation | { V0: any } | { V1: any } | string | Uint8Array, destWeightLimit: XcmV2WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic, [Vec>, u32, XcmVersionedMultiLocation, XcmV2WeightLimit]>; /** * Transfer native currencies specifying the fee and amount as * separate. * - * `dest_weight` is the weight for XCM execution on the dest chain, and - * it would be charged from the transferred assets. If set below - * requirements, the execution may fail and assets wouldn't be + * `dest_weight_limit` is the weight for XCM execution on the dest + * chain, and it would be charged from the transferred assets. If set + * below requirements, the execution may fail and assets wouldn't be * received. * * `fee` is the amount to be spent to pay for execution in destination @@ -1525,7 +1889,7 @@ declare module '@polkadot/api-base/types/submittable' { * by the network, and if the receiving chain would handle * messages correctly. **/ - transferWithFee: AugmentedSubmittable<(currencyId: PalletForeignAssetsAssetIds | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: u128 | AnyNumber | Uint8Array, fee: u128 | AnyNumber | Uint8Array, dest: XcmVersionedMultiLocation | { V0: any } | { V1: any } | string | Uint8Array, destWeight: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic, [PalletForeignAssetsAssetIds, u128, u128, XcmVersionedMultiLocation, u64]>; + transferWithFee: AugmentedSubmittable<(currencyId: PalletForeignAssetsAssetIds | { ForeignAssetId: any } | { NativeAssetId: any } | string | Uint8Array, amount: u128 | AnyNumber | Uint8Array, fee: u128 | AnyNumber | Uint8Array, dest: XcmVersionedMultiLocation | { V0: any } | { V1: any } | string | Uint8Array, destWeightLimit: XcmV2WeightLimit | { Unlimited: any } | { Limited: any } | string | Uint8Array) => SubmittableExtrinsic, [PalletForeignAssetsAssetIds, u128, u128, XcmVersionedMultiLocation, XcmV2WeightLimit]>; /** * Generic tx **/ diff --git a/tests/src/interfaces/augment-types.ts b/tests/src/interfaces/augment-types.ts index 40042ad18d..42f1a06119 100644 --- a/tests/src/interfaces/augment-types.ts +++ b/tests/src/interfaces/augment-types.ts @@ -5,7 +5,7 @@ // this is required to allow for ambient/previous definitions import '@polkadot/types/types/registry'; -import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationAppPromotionConfiguration, PalletConfigurationCall, PalletConfigurationError, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './default'; +import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationAppPromotionConfiguration, PalletConfigurationCall, PalletConfigurationError, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionValidityInvalidTransaction, SpRuntimeTransactionValidityTransactionValidityError, SpRuntimeTransactionValidityUnknownTransaction, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, UpPovEstimateRpcPovInfo, UpPovEstimateRpcTrieKeyValue, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './default'; import type { Data, StorageKey } from '@polkadot/types'; import type { BitVec, Bool, Bytes, F32, F64, I128, I16, I256, I32, I64, I8, Json, Null, OptionBool, Raw, Text, Type, U128, U16, U256, U32, U64, U8, USize, bool, f32, f64, i128, i16, i256, i32, i64, i8, u128, u16, u256, u32, u64, u8, usize } from '@polkadot/types-codec'; import type { AssetApproval, AssetApprovalKey, AssetBalance, AssetDestroyWitness, AssetDetails, AssetMetadata, TAssetBalance, TAssetDepositBalance } from '@polkadot/types/interfaces/assets'; @@ -823,7 +823,6 @@ declare module '@polkadot/types/types/registry' { PalletBalancesError: PalletBalancesError; PalletBalancesEvent: PalletBalancesEvent; PalletBalancesReasons: PalletBalancesReasons; - PalletBalancesReleases: PalletBalancesReleases; PalletBalancesReserveData: PalletBalancesReserveData; PalletCallMetadataLatest: PalletCallMetadataLatest; PalletCallMetadataV14: PalletCallMetadataV14; @@ -870,7 +869,12 @@ declare module '@polkadot/types/types/registry' { PalletNonfungibleError: PalletNonfungibleError; PalletNonfungibleItemData: PalletNonfungibleItemData; PalletRefungibleError: PalletRefungibleError; - PalletRefungibleItemData: PalletRefungibleItemData; + PalletRmrkCoreCall: PalletRmrkCoreCall; + PalletRmrkCoreError: PalletRmrkCoreError; + PalletRmrkCoreEvent: PalletRmrkCoreEvent; + PalletRmrkEquipCall: PalletRmrkEquipCall; + PalletRmrkEquipError: PalletRmrkEquipError; + PalletRmrkEquipEvent: PalletRmrkEquipEvent; PalletsOrigin: PalletsOrigin; PalletStorageMetadataLatest: PalletStorageMetadataLatest; PalletStorageMetadataV14: PalletStorageMetadataV14; @@ -882,6 +886,9 @@ declare module '@polkadot/types/types/registry' { PalletSudoEvent: PalletSudoEvent; PalletTemplateTransactionPaymentCall: PalletTemplateTransactionPaymentCall; PalletTemplateTransactionPaymentChargeTransactionPayment: PalletTemplateTransactionPaymentChargeTransactionPayment; + PalletTestUtilsCall: PalletTestUtilsCall; + PalletTestUtilsError: PalletTestUtilsError; + PalletTestUtilsEvent: PalletTestUtilsEvent; PalletTimestampCall: PalletTimestampCall; PalletTransactionPaymentEvent: PalletTransactionPaymentEvent; PalletTransactionPaymentReleases: PalletTransactionPaymentReleases; @@ -891,7 +898,6 @@ declare module '@polkadot/types/types/registry' { PalletTreasuryProposal: PalletTreasuryProposal; PalletUniqueCall: PalletUniqueCall; PalletUniqueError: PalletUniqueError; - PalletUniqueRawEvent: PalletUniqueRawEvent; PalletVersion: PalletVersion; PalletXcmCall: PalletXcmCall; PalletXcmError: PalletXcmError; @@ -1180,9 +1186,13 @@ declare module '@polkadot/types/types/registry' { SpRuntimeMultiSignature: SpRuntimeMultiSignature; SpRuntimeTokenError: SpRuntimeTokenError; SpRuntimeTransactionalError: SpRuntimeTransactionalError; + SpRuntimeTransactionValidityInvalidTransaction: SpRuntimeTransactionValidityInvalidTransaction; + SpRuntimeTransactionValidityTransactionValidityError: SpRuntimeTransactionValidityTransactionValidityError; + SpRuntimeTransactionValidityUnknownTransaction: SpRuntimeTransactionValidityUnknownTransaction; SpTrieStorageProof: SpTrieStorageProof; SpVersionRuntimeVersion: SpVersionRuntimeVersion; SpWeightsRuntimeDbWeight: SpWeightsRuntimeDbWeight; + SpWeightsWeightV2Weight: SpWeightsWeightV2Weight; Sr25519Signature: Sr25519Signature; StakingLedger: StakingLedger; StakingLedgerTo223: StakingLedgerTo223; @@ -1318,6 +1328,8 @@ declare module '@polkadot/types/types/registry' { UpDataStructsTokenData: UpDataStructsTokenData; UpgradeGoAhead: UpgradeGoAhead; UpgradeRestriction: UpgradeRestriction; + UpPovEstimateRpcPovInfo: UpPovEstimateRpcPovInfo; + UpPovEstimateRpcTrieKeyValue: UpPovEstimateRpcTrieKeyValue; UpwardMessage: UpwardMessage; usize: usize; USize: USize; diff --git a/tests/src/interfaces/default/types.ts b/tests/src/interfaces/default/types.ts index ba73ee9633..d14e3c0ced 100644 --- a/tests/src/interfaces/default/types.ts +++ b/tests/src/interfaces/default/types.ts @@ -3,7 +3,7 @@ import type { BTreeMap, BTreeSet, Bytes, Compact, Enum, Null, Option, Result, Struct, Text, U256, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec'; import type { ITuple } from '@polkadot/types-codec/types'; -import type { AccountId32, Call, H160, H256, MultiAddress, Perbill, Permill, Weight } from '@polkadot/types/interfaces/runtime'; +import type { AccountId32, Call, H160, H256, MultiAddress, Perbill, Permill } from '@polkadot/types/interfaces/runtime'; import type { Event } from '@polkadot/types/interfaces/system'; /** @name CumulusPalletDmpQueueCall */ @@ -11,14 +11,14 @@ export interface CumulusPalletDmpQueueCall extends Enum { readonly isServiceOverweight: boolean; readonly asServiceOverweight: { readonly index: u64; - readonly weightLimit: Weight; + readonly weightLimit: u64; } & Struct; readonly type: 'ServiceOverweight'; } /** @name CumulusPalletDmpQueueConfigData */ export interface CumulusPalletDmpQueueConfigData extends Struct { - readonly maxIndividual: Weight; + readonly maxIndividual: SpWeightsWeightV2Weight; } /** @name CumulusPalletDmpQueueError */ @@ -46,19 +46,19 @@ export interface CumulusPalletDmpQueueEvent extends Enum { readonly isWeightExhausted: boolean; readonly asWeightExhausted: { readonly messageId: U8aFixed; - readonly remainingWeight: Weight; - readonly requiredWeight: Weight; + readonly remainingWeight: SpWeightsWeightV2Weight; + readonly requiredWeight: SpWeightsWeightV2Weight; } & Struct; readonly isOverweightEnqueued: boolean; readonly asOverweightEnqueued: { readonly messageId: U8aFixed; readonly overweightIndex: u64; - readonly requiredWeight: Weight; + readonly requiredWeight: SpWeightsWeightV2Weight; } & Struct; readonly isOverweightServiced: boolean; readonly asOverweightServiced: { readonly overweightIndex: u64; - readonly weightUsed: Weight; + readonly weightUsed: SpWeightsWeightV2Weight; } & Struct; readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward' | 'WeightExhausted' | 'OverweightEnqueued' | 'OverweightServiced'; } @@ -122,7 +122,7 @@ export interface CumulusPalletParachainSystemEvent extends Enum { } & Struct; readonly isDownwardMessagesProcessed: boolean; readonly asDownwardMessagesProcessed: { - readonly weightUsed: Weight; + readonly weightUsed: SpWeightsWeightV2Weight; readonly dmqHead: H256; } & Struct; readonly type: 'ValidationFunctionStored' | 'ValidationFunctionApplied' | 'ValidationFunctionDiscarded' | 'UpgradeAuthorized' | 'DownwardMessagesReceived' | 'DownwardMessagesProcessed'; @@ -158,7 +158,7 @@ export interface CumulusPalletXcmpQueueCall extends Enum { readonly isServiceOverweight: boolean; readonly asServiceOverweight: { readonly index: u64; - readonly weightLimit: Weight; + readonly weightLimit: u64; } & Struct; readonly isSuspendXcmExecution: boolean; readonly isResumeXcmExecution: boolean; @@ -176,15 +176,15 @@ export interface CumulusPalletXcmpQueueCall extends Enum { } & Struct; readonly isUpdateThresholdWeight: boolean; readonly asUpdateThresholdWeight: { - readonly new_: Weight; + readonly new_: u64; } & Struct; readonly isUpdateWeightRestrictDecay: boolean; readonly asUpdateWeightRestrictDecay: { - readonly new_: Weight; + readonly new_: u64; } & Struct; readonly isUpdateXcmpMaxIndividualWeight: boolean; readonly asUpdateXcmpMaxIndividualWeight: { - readonly new_: Weight; + readonly new_: u64; } & Struct; readonly type: 'ServiceOverweight' | 'SuspendXcmExecution' | 'ResumeXcmExecution' | 'UpdateSuspendThreshold' | 'UpdateDropThreshold' | 'UpdateResumeThreshold' | 'UpdateThresholdWeight' | 'UpdateWeightRestrictDecay' | 'UpdateXcmpMaxIndividualWeight'; } @@ -204,13 +204,13 @@ export interface CumulusPalletXcmpQueueEvent extends Enum { readonly isSuccess: boolean; readonly asSuccess: { readonly messageHash: Option; - readonly weight: Weight; + readonly weight: SpWeightsWeightV2Weight; } & Struct; readonly isFail: boolean; readonly asFail: { readonly messageHash: Option; readonly error: XcmV2TraitsError; - readonly weight: Weight; + readonly weight: SpWeightsWeightV2Weight; } & Struct; readonly isBadVersion: boolean; readonly asBadVersion: { @@ -233,12 +233,12 @@ export interface CumulusPalletXcmpQueueEvent extends Enum { readonly sender: u32; readonly sentAt: u32; readonly index: u64; - readonly required: Weight; + readonly required: SpWeightsWeightV2Weight; } & Struct; readonly isOverweightServiced: boolean; readonly asOverweightServiced: { readonly index: u64; - readonly used: Weight; + readonly used: SpWeightsWeightV2Weight; } & Struct; readonly type: 'Success' | 'Fail' | 'BadVersion' | 'BadFormat' | 'UpwardMessageSent' | 'XcmpMessageSent' | 'OverweightEnqueued' | 'OverweightServiced'; } @@ -278,9 +278,9 @@ export interface CumulusPalletXcmpQueueQueueConfigData extends Struct { readonly suspendThreshold: u32; readonly dropThreshold: u32; readonly resumeThreshold: u32; - readonly thresholdWeight: Weight; - readonly weightRestrictDecay: Weight; - readonly xcmpMaxIndividualWeight: Weight; + readonly thresholdWeight: SpWeightsWeightV2Weight; + readonly weightRestrictDecay: SpWeightsWeightV2Weight; + readonly xcmpMaxIndividualWeight: SpWeightsWeightV2Weight; } /** @name CumulusPrimitivesParachainInherentParachainInherentData */ @@ -503,7 +503,7 @@ export interface FrameSupportDispatchDispatchClass extends Enum { /** @name FrameSupportDispatchDispatchInfo */ export interface FrameSupportDispatchDispatchInfo extends Struct { - readonly weight: Weight; + readonly weight: SpWeightsWeightV2Weight; readonly class: FrameSupportDispatchDispatchClass; readonly paysFee: FrameSupportDispatchPays; } @@ -524,9 +524,9 @@ export interface FrameSupportDispatchPerDispatchClassU32 extends Struct { /** @name FrameSupportDispatchPerDispatchClassWeight */ export interface FrameSupportDispatchPerDispatchClassWeight extends Struct { - readonly normal: Weight; - readonly operational: Weight; - readonly mandatory: Weight; + readonly normal: SpWeightsWeightV2Weight; + readonly operational: SpWeightsWeightV2Weight; + readonly mandatory: SpWeightsWeightV2Weight; } /** @name FrameSupportDispatchPerDispatchClassWeightsPerClass */ @@ -557,10 +557,6 @@ export interface FrameSystemAccountInfo extends Struct { /** @name FrameSystemCall */ export interface FrameSystemCall extends Enum { - readonly isFillBlock: boolean; - readonly asFillBlock: { - readonly ratio: Perbill; - } & Struct; readonly isRemark: boolean; readonly asRemark: { readonly remark: Bytes; @@ -594,7 +590,7 @@ export interface FrameSystemCall extends Enum { readonly asRemarkWithEvent: { readonly remark: Bytes; } & Struct; - readonly type: 'FillBlock' | 'Remark' | 'SetHeapPages' | 'SetCode' | 'SetCodeWithoutChecks' | 'SetStorage' | 'KillStorage' | 'KillPrefix' | 'RemarkWithEvent'; + readonly type: 'Remark' | 'SetHeapPages' | 'SetCode' | 'SetCodeWithoutChecks' | 'SetStorage' | 'KillStorage' | 'KillPrefix' | 'RemarkWithEvent'; } /** @name FrameSystemError */ @@ -671,17 +667,17 @@ export interface FrameSystemLimitsBlockLength extends Struct { /** @name FrameSystemLimitsBlockWeights */ export interface FrameSystemLimitsBlockWeights extends Struct { - readonly baseBlock: Weight; - readonly maxBlock: Weight; + readonly baseBlock: SpWeightsWeightV2Weight; + readonly maxBlock: SpWeightsWeightV2Weight; readonly perClass: FrameSupportDispatchPerDispatchClassWeightsPerClass; } /** @name FrameSystemLimitsWeightsPerClass */ export interface FrameSystemLimitsWeightsPerClass extends Struct { - readonly baseExtrinsic: Weight; - readonly maxExtrinsic: Option; - readonly maxTotal: Option; - readonly reserved: Option; + readonly baseExtrinsic: SpWeightsWeightV2Weight; + readonly maxExtrinsic: Option; + readonly maxTotal: Option; + readonly reserved: Option; } /** @name FrameSystemPhase */ @@ -922,13 +918,13 @@ export interface OrmlXtokensModuleCall extends Enum { readonly currencyId: PalletForeignAssetsAssetIds; readonly amount: u128; readonly dest: XcmVersionedMultiLocation; - readonly destWeight: u64; + readonly destWeightLimit: XcmV2WeightLimit; } & Struct; readonly isTransferMultiasset: boolean; readonly asTransferMultiasset: { readonly asset: XcmVersionedMultiAsset; readonly dest: XcmVersionedMultiLocation; - readonly destWeight: u64; + readonly destWeightLimit: XcmV2WeightLimit; } & Struct; readonly isTransferWithFee: boolean; readonly asTransferWithFee: { @@ -936,28 +932,28 @@ export interface OrmlXtokensModuleCall extends Enum { readonly amount: u128; readonly fee: u128; readonly dest: XcmVersionedMultiLocation; - readonly destWeight: u64; + readonly destWeightLimit: XcmV2WeightLimit; } & Struct; readonly isTransferMultiassetWithFee: boolean; readonly asTransferMultiassetWithFee: { readonly asset: XcmVersionedMultiAsset; readonly fee: XcmVersionedMultiAsset; readonly dest: XcmVersionedMultiLocation; - readonly destWeight: u64; + readonly destWeightLimit: XcmV2WeightLimit; } & Struct; readonly isTransferMulticurrencies: boolean; readonly asTransferMulticurrencies: { readonly currencies: Vec>; readonly feeItem: u32; readonly dest: XcmVersionedMultiLocation; - readonly destWeight: u64; + readonly destWeightLimit: XcmV2WeightLimit; } & Struct; readonly isTransferMultiassets: boolean; readonly asTransferMultiassets: { readonly assets: XcmVersionedMultiAssets; readonly feeItem: u32; readonly dest: XcmVersionedMultiLocation; - readonly destWeight: u64; + readonly destWeightLimit: XcmV2WeightLimit; } & Struct; readonly type: 'Transfer' | 'TransferMultiasset' | 'TransferWithFee' | 'TransferMultiassetWithFee' | 'TransferMulticurrencies' | 'TransferMultiassets'; } @@ -1188,13 +1184,6 @@ export interface PalletBalancesReasons extends Enum { readonly type: 'Fee' | 'Misc' | 'All'; } -/** @name PalletBalancesReleases */ -export interface PalletBalancesReleases extends Enum { - readonly isV100: boolean; - readonly isV200: boolean; - readonly type: 'V100' | 'V200'; -} - /** @name PalletBalancesReserveData */ export interface PalletBalancesReserveData extends Struct { readonly id: U8aFixed; @@ -1237,7 +1226,9 @@ export interface PalletCommonError extends Enum { readonly isEmptyPropertyKey: boolean; readonly isCollectionIsExternal: boolean; readonly isCollectionIsInternal: boolean; - readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal'; + readonly isConfirmSponsorshipFail: boolean; + readonly isUserIsNotCollectionAdmin: boolean; + readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal' | 'ConfirmSponsorshipFail' | 'UserIsNotCollectionAdmin'; } /** @name PalletCommonEvent */ @@ -1254,6 +1245,8 @@ export interface PalletCommonEvent extends Enum { readonly asTransfer: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>; readonly isApproved: boolean; readonly asApproved: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>; + readonly isApprovedForAll: boolean; + readonly asApprovedForAll: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>; readonly isCollectionPropertySet: boolean; readonly asCollectionPropertySet: ITuple<[u32, Bytes]>; readonly isCollectionPropertyDeleted: boolean; @@ -1264,7 +1257,27 @@ export interface PalletCommonEvent extends Enum { readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>; readonly isPropertyPermissionSet: boolean; readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>; - readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet'; + readonly isAllowListAddressAdded: boolean; + readonly asAllowListAddressAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; + readonly isAllowListAddressRemoved: boolean; + readonly asAllowListAddressRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; + readonly isCollectionAdminAdded: boolean; + readonly asCollectionAdminAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; + readonly isCollectionAdminRemoved: boolean; + readonly asCollectionAdminRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; + readonly isCollectionLimitSet: boolean; + readonly asCollectionLimitSet: u32; + readonly isCollectionOwnerChanged: boolean; + readonly asCollectionOwnerChanged: ITuple<[u32, AccountId32]>; + readonly isCollectionPermissionSet: boolean; + readonly asCollectionPermissionSet: u32; + readonly isCollectionSponsorSet: boolean; + readonly asCollectionSponsorSet: ITuple<[u32, AccountId32]>; + readonly isSponsorshipConfirmed: boolean; + readonly asSponsorshipConfirmed: ITuple<[u32, AccountId32]>; + readonly isCollectionSponsorRemoved: boolean; + readonly asCollectionSponsorRemoved: u32; + readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet' | 'AllowListAddressAdded' | 'AllowListAddressRemoved' | 'CollectionAdminAdded' | 'CollectionAdminRemoved' | 'CollectionLimitSet' | 'CollectionOwnerChanged' | 'CollectionPermissionSet' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionSponsorRemoved'; } /** @name PalletConfigurationAppPromotionConfiguration */ @@ -1279,7 +1292,7 @@ export interface PalletConfigurationAppPromotionConfiguration extends Struct { export interface PalletConfigurationCall extends Enum { readonly isSetWeightToFeeCoefficientOverride: boolean; readonly asSetWeightToFeeCoefficientOverride: { - readonly coeff: Option; + readonly coeff: Option; } & Struct; readonly isSetMinGasPriceOverride: boolean; readonly asSetMinGasPriceOverride: { @@ -1321,7 +1334,12 @@ export interface PalletEthereumError extends Enum { /** @name PalletEthereumEvent */ export interface PalletEthereumEvent extends Enum { readonly isExecuted: boolean; - readonly asExecuted: ITuple<[H160, H160, H256, EvmCoreErrorExitReason]>; + readonly asExecuted: { + readonly from: H160; + readonly to: H160; + readonly transactionHash: H256; + readonly exitReason: EvmCoreErrorExitReason; + } & Struct; readonly type: 'Executed'; } @@ -1424,26 +1442,37 @@ export interface PalletEvmError extends Enum { readonly isWithdrawFailed: boolean; readonly isGasPriceTooLow: boolean; readonly isInvalidNonce: boolean; - readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce'; + readonly isGasLimitTooLow: boolean; + readonly isGasLimitTooHigh: boolean; + readonly isUndefined: boolean; + readonly isReentrancy: boolean; + readonly isTransactionMustComeFromEOA: boolean; + readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce' | 'GasLimitTooLow' | 'GasLimitTooHigh' | 'Undefined' | 'Reentrancy' | 'TransactionMustComeFromEOA'; } /** @name PalletEvmEvent */ export interface PalletEvmEvent extends Enum { readonly isLog: boolean; - readonly asLog: EthereumLog; + readonly asLog: { + readonly log: EthereumLog; + } & Struct; readonly isCreated: boolean; - readonly asCreated: H160; + readonly asCreated: { + readonly address: H160; + } & Struct; readonly isCreatedFailed: boolean; - readonly asCreatedFailed: H160; + readonly asCreatedFailed: { + readonly address: H160; + } & Struct; readonly isExecuted: boolean; - readonly asExecuted: H160; + readonly asExecuted: { + readonly address: H160; + } & Struct; readonly isExecutedFailed: boolean; - readonly asExecutedFailed: H160; - readonly isBalanceDeposit: boolean; - readonly asBalanceDeposit: ITuple<[AccountId32, H160, U256]>; - readonly isBalanceWithdraw: boolean; - readonly asBalanceWithdraw: ITuple<[AccountId32, H160, U256]>; - readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed' | 'BalanceDeposit' | 'BalanceWithdraw'; + readonly asExecutedFailed: { + readonly address: H160; + } & Struct; + readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed'; } /** @name PalletEvmMigrationCall */ @@ -1571,8 +1600,9 @@ export interface PalletFungibleError extends Enum { readonly isFungibleItemsDontHaveData: boolean; readonly isFungibleDisallowsNesting: boolean; readonly isSettingPropertiesNotAllowed: boolean; + readonly isSettingAllowanceForAllNotAllowed: boolean; readonly isFungibleTokensAreAlwaysValid: boolean; - readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'FungibleTokensAreAlwaysValid'; + readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'SettingAllowanceForAllNotAllowed' | 'FungibleTokensAreAlwaysValid'; } /** @name PalletInflationCall */ @@ -1624,9 +1654,273 @@ export interface PalletRefungibleError extends Enum { readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RepartitionWhileNotOwningAllPieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed'; } -/** @name PalletRefungibleItemData */ -export interface PalletRefungibleItemData extends Struct { - readonly constData: Bytes; +/** @name PalletRmrkCoreCall */ +export interface PalletRmrkCoreCall extends Enum { + readonly isCreateCollection: boolean; + readonly asCreateCollection: { + readonly metadata: Bytes; + readonly max: Option; + readonly symbol: Bytes; + } & Struct; + readonly isDestroyCollection: boolean; + readonly asDestroyCollection: { + readonly collectionId: u32; + } & Struct; + readonly isChangeCollectionIssuer: boolean; + readonly asChangeCollectionIssuer: { + readonly collectionId: u32; + readonly newIssuer: MultiAddress; + } & Struct; + readonly isLockCollection: boolean; + readonly asLockCollection: { + readonly collectionId: u32; + } & Struct; + readonly isMintNft: boolean; + readonly asMintNft: { + readonly owner: Option; + readonly collectionId: u32; + readonly recipient: Option; + readonly royaltyAmount: Option; + readonly metadata: Bytes; + readonly transferable: bool; + readonly resources: Option>; + } & Struct; + readonly isBurnNft: boolean; + readonly asBurnNft: { + readonly collectionId: u32; + readonly nftId: u32; + readonly maxBurns: u32; + } & Struct; + readonly isSend: boolean; + readonly asSend: { + readonly rmrkCollectionId: u32; + readonly rmrkNftId: u32; + readonly newOwner: RmrkTraitsNftAccountIdOrCollectionNftTuple; + } & Struct; + readonly isAcceptNft: boolean; + readonly asAcceptNft: { + readonly rmrkCollectionId: u32; + readonly rmrkNftId: u32; + readonly newOwner: RmrkTraitsNftAccountIdOrCollectionNftTuple; + } & Struct; + readonly isRejectNft: boolean; + readonly asRejectNft: { + readonly rmrkCollectionId: u32; + readonly rmrkNftId: u32; + } & Struct; + readonly isAcceptResource: boolean; + readonly asAcceptResource: { + readonly rmrkCollectionId: u32; + readonly rmrkNftId: u32; + readonly resourceId: u32; + } & Struct; + readonly isAcceptResourceRemoval: boolean; + readonly asAcceptResourceRemoval: { + readonly rmrkCollectionId: u32; + readonly rmrkNftId: u32; + readonly resourceId: u32; + } & Struct; + readonly isSetProperty: boolean; + readonly asSetProperty: { + readonly rmrkCollectionId: Compact; + readonly maybeNftId: Option; + readonly key: Bytes; + readonly value: Bytes; + } & Struct; + readonly isSetPriority: boolean; + readonly asSetPriority: { + readonly rmrkCollectionId: u32; + readonly rmrkNftId: u32; + readonly priorities: Vec; + } & Struct; + readonly isAddBasicResource: boolean; + readonly asAddBasicResource: { + readonly rmrkCollectionId: u32; + readonly nftId: u32; + readonly resource: RmrkTraitsResourceBasicResource; + } & Struct; + readonly isAddComposableResource: boolean; + readonly asAddComposableResource: { + readonly rmrkCollectionId: u32; + readonly nftId: u32; + readonly resource: RmrkTraitsResourceComposableResource; + } & Struct; + readonly isAddSlotResource: boolean; + readonly asAddSlotResource: { + readonly rmrkCollectionId: u32; + readonly nftId: u32; + readonly resource: RmrkTraitsResourceSlotResource; + } & Struct; + readonly isRemoveResource: boolean; + readonly asRemoveResource: { + readonly rmrkCollectionId: u32; + readonly nftId: u32; + readonly resourceId: u32; + } & Struct; + readonly type: 'CreateCollection' | 'DestroyCollection' | 'ChangeCollectionIssuer' | 'LockCollection' | 'MintNft' | 'BurnNft' | 'Send' | 'AcceptNft' | 'RejectNft' | 'AcceptResource' | 'AcceptResourceRemoval' | 'SetProperty' | 'SetPriority' | 'AddBasicResource' | 'AddComposableResource' | 'AddSlotResource' | 'RemoveResource'; +} + +/** @name PalletRmrkCoreError */ +export interface PalletRmrkCoreError extends Enum { + readonly isCorruptedCollectionType: boolean; + readonly isRmrkPropertyKeyIsTooLong: boolean; + readonly isRmrkPropertyValueIsTooLong: boolean; + readonly isRmrkPropertyIsNotFound: boolean; + readonly isUnableToDecodeRmrkData: boolean; + readonly isCollectionNotEmpty: boolean; + readonly isNoAvailableCollectionId: boolean; + readonly isNoAvailableNftId: boolean; + readonly isCollectionUnknown: boolean; + readonly isNoPermission: boolean; + readonly isNonTransferable: boolean; + readonly isCollectionFullOrLocked: boolean; + readonly isResourceDoesntExist: boolean; + readonly isCannotSendToDescendentOrSelf: boolean; + readonly isCannotAcceptNonOwnedNft: boolean; + readonly isCannotRejectNonOwnedNft: boolean; + readonly isCannotRejectNonPendingNft: boolean; + readonly isResourceNotPending: boolean; + readonly isNoAvailableResourceId: boolean; + readonly type: 'CorruptedCollectionType' | 'RmrkPropertyKeyIsTooLong' | 'RmrkPropertyValueIsTooLong' | 'RmrkPropertyIsNotFound' | 'UnableToDecodeRmrkData' | 'CollectionNotEmpty' | 'NoAvailableCollectionId' | 'NoAvailableNftId' | 'CollectionUnknown' | 'NoPermission' | 'NonTransferable' | 'CollectionFullOrLocked' | 'ResourceDoesntExist' | 'CannotSendToDescendentOrSelf' | 'CannotAcceptNonOwnedNft' | 'CannotRejectNonOwnedNft' | 'CannotRejectNonPendingNft' | 'ResourceNotPending' | 'NoAvailableResourceId'; +} + +/** @name PalletRmrkCoreEvent */ +export interface PalletRmrkCoreEvent extends Enum { + readonly isCollectionCreated: boolean; + readonly asCollectionCreated: { + readonly issuer: AccountId32; + readonly collectionId: u32; + } & Struct; + readonly isCollectionDestroyed: boolean; + readonly asCollectionDestroyed: { + readonly issuer: AccountId32; + readonly collectionId: u32; + } & Struct; + readonly isIssuerChanged: boolean; + readonly asIssuerChanged: { + readonly oldIssuer: AccountId32; + readonly newIssuer: AccountId32; + readonly collectionId: u32; + } & Struct; + readonly isCollectionLocked: boolean; + readonly asCollectionLocked: { + readonly issuer: AccountId32; + readonly collectionId: u32; + } & Struct; + readonly isNftMinted: boolean; + readonly asNftMinted: { + readonly owner: AccountId32; + readonly collectionId: u32; + readonly nftId: u32; + } & Struct; + readonly isNftBurned: boolean; + readonly asNftBurned: { + readonly owner: AccountId32; + readonly nftId: u32; + } & Struct; + readonly isNftSent: boolean; + readonly asNftSent: { + readonly sender: AccountId32; + readonly recipient: RmrkTraitsNftAccountIdOrCollectionNftTuple; + readonly collectionId: u32; + readonly nftId: u32; + readonly approvalRequired: bool; + } & Struct; + readonly isNftAccepted: boolean; + readonly asNftAccepted: { + readonly sender: AccountId32; + readonly recipient: RmrkTraitsNftAccountIdOrCollectionNftTuple; + readonly collectionId: u32; + readonly nftId: u32; + } & Struct; + readonly isNftRejected: boolean; + readonly asNftRejected: { + readonly sender: AccountId32; + readonly collectionId: u32; + readonly nftId: u32; + } & Struct; + readonly isPropertySet: boolean; + readonly asPropertySet: { + readonly collectionId: u32; + readonly maybeNftId: Option; + readonly key: Bytes; + readonly value: Bytes; + } & Struct; + readonly isResourceAdded: boolean; + readonly asResourceAdded: { + readonly nftId: u32; + readonly resourceId: u32; + } & Struct; + readonly isResourceRemoval: boolean; + readonly asResourceRemoval: { + readonly nftId: u32; + readonly resourceId: u32; + } & Struct; + readonly isResourceAccepted: boolean; + readonly asResourceAccepted: { + readonly nftId: u32; + readonly resourceId: u32; + } & Struct; + readonly isResourceRemovalAccepted: boolean; + readonly asResourceRemovalAccepted: { + readonly nftId: u32; + readonly resourceId: u32; + } & Struct; + readonly isPrioritySet: boolean; + readonly asPrioritySet: { + readonly collectionId: u32; + readonly nftId: u32; + } & Struct; + readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'IssuerChanged' | 'CollectionLocked' | 'NftMinted' | 'NftBurned' | 'NftSent' | 'NftAccepted' | 'NftRejected' | 'PropertySet' | 'ResourceAdded' | 'ResourceRemoval' | 'ResourceAccepted' | 'ResourceRemovalAccepted' | 'PrioritySet'; +} + +/** @name PalletRmrkEquipCall */ +export interface PalletRmrkEquipCall extends Enum { + readonly isCreateBase: boolean; + readonly asCreateBase: { + readonly baseType: Bytes; + readonly symbol: Bytes; + readonly parts: Vec; + } & Struct; + readonly isThemeAdd: boolean; + readonly asThemeAdd: { + readonly baseId: u32; + readonly theme: RmrkTraitsTheme; + } & Struct; + readonly isEquippable: boolean; + readonly asEquippable: { + readonly baseId: u32; + readonly slotId: u32; + readonly equippables: RmrkTraitsPartEquippableList; + } & Struct; + readonly type: 'CreateBase' | 'ThemeAdd' | 'Equippable'; +} + +/** @name PalletRmrkEquipError */ +export interface PalletRmrkEquipError extends Enum { + readonly isPermissionError: boolean; + readonly isNoAvailableBaseId: boolean; + readonly isNoAvailablePartId: boolean; + readonly isBaseDoesntExist: boolean; + readonly isNeedsDefaultThemeFirst: boolean; + readonly isPartDoesntExist: boolean; + readonly isNoEquippableOnFixedPart: boolean; + readonly type: 'PermissionError' | 'NoAvailableBaseId' | 'NoAvailablePartId' | 'BaseDoesntExist' | 'NeedsDefaultThemeFirst' | 'PartDoesntExist' | 'NoEquippableOnFixedPart'; +} + +/** @name PalletRmrkEquipEvent */ +export interface PalletRmrkEquipEvent extends Enum { + readonly isBaseCreated: boolean; + readonly asBaseCreated: { + readonly issuer: AccountId32; + readonly baseId: u32; + } & Struct; + readonly isEquippablesUpdated: boolean; + readonly asEquippablesUpdated: { + readonly baseId: u32; + readonly slotId: u32; + } & Struct; + readonly type: 'BaseCreated' | 'EquippablesUpdated'; } /** @name PalletStructureCall */ @@ -1657,7 +1951,7 @@ export interface PalletSudoCall extends Enum { readonly isSudoUncheckedWeight: boolean; readonly asSudoUncheckedWeight: { readonly call: Call; - readonly weight: Weight; + readonly weight: SpWeightsWeightV2Weight; } & Struct; readonly isSetKey: boolean; readonly asSetKey: { @@ -1700,6 +1994,41 @@ export interface PalletTemplateTransactionPaymentCall extends Null {} /** @name PalletTemplateTransactionPaymentChargeTransactionPayment */ export interface PalletTemplateTransactionPaymentChargeTransactionPayment extends Compact {} +/** @name PalletTestUtilsCall */ +export interface PalletTestUtilsCall extends Enum { + readonly isEnable: boolean; + readonly isSetTestValue: boolean; + readonly asSetTestValue: { + readonly value: u32; + } & Struct; + readonly isSetTestValueAndRollback: boolean; + readonly asSetTestValueAndRollback: { + readonly value: u32; + } & Struct; + readonly isIncTestValue: boolean; + readonly isJustTakeFee: boolean; + readonly isBatchAll: boolean; + readonly asBatchAll: { + readonly calls: Vec; + } & Struct; + readonly type: 'Enable' | 'SetTestValue' | 'SetTestValueAndRollback' | 'IncTestValue' | 'JustTakeFee' | 'BatchAll'; +} + +/** @name PalletTestUtilsError */ +export interface PalletTestUtilsError extends Enum { + readonly isTestPalletDisabled: boolean; + readonly isTriggerRollback: boolean; + readonly type: 'TestPalletDisabled' | 'TriggerRollback'; +} + +/** @name PalletTestUtilsEvent */ +export interface PalletTestUtilsEvent extends Enum { + readonly isValueIsSet: boolean; + readonly isShouldRollback: boolean; + readonly isBatchCompleted: boolean; + readonly type: 'ValueIsSet' | 'ShouldRollback' | 'BatchCompleted'; +} + /** @name PalletTimestampCall */ export interface PalletTimestampCall extends Enum { readonly isSet: boolean; @@ -1969,46 +2298,30 @@ export interface PalletUniqueCall extends Enum { readonly tokenId: u32; readonly amount: u128; } & Struct; - readonly isRepairItem: boolean; - readonly asRepairItem: { + readonly isSetAllowanceForAll: boolean; + readonly asSetAllowanceForAll: { + readonly collectionId: u32; + readonly operator: PalletEvmAccountBasicCrossAccountIdRepr; + readonly approve: bool; + } & Struct; + readonly isForceRepairCollection: boolean; + readonly asForceRepairCollection: { + readonly collectionId: u32; + } & Struct; + readonly isForceRepairItem: boolean; + readonly asForceRepairItem: { readonly collectionId: u32; readonly itemId: u32; } & Struct; - readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'RepairItem'; + readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'SetAllowanceForAll' | 'ForceRepairCollection' | 'ForceRepairItem'; } /** @name PalletUniqueError */ export interface PalletUniqueError extends Enum { readonly isCollectionDecimalPointLimitExceeded: boolean; - readonly isConfirmUnsetSponsorFail: boolean; readonly isEmptyArgument: boolean; readonly isRepartitionCalledOnNonRefungibleCollection: boolean; - readonly type: 'CollectionDecimalPointLimitExceeded' | 'ConfirmUnsetSponsorFail' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection'; -} - -/** @name PalletUniqueRawEvent */ -export interface PalletUniqueRawEvent extends Enum { - readonly isCollectionSponsorRemoved: boolean; - readonly asCollectionSponsorRemoved: u32; - readonly isCollectionAdminAdded: boolean; - readonly asCollectionAdminAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; - readonly isCollectionOwnedChanged: boolean; - readonly asCollectionOwnedChanged: ITuple<[u32, AccountId32]>; - readonly isCollectionSponsorSet: boolean; - readonly asCollectionSponsorSet: ITuple<[u32, AccountId32]>; - readonly isSponsorshipConfirmed: boolean; - readonly asSponsorshipConfirmed: ITuple<[u32, AccountId32]>; - readonly isCollectionAdminRemoved: boolean; - readonly asCollectionAdminRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; - readonly isAllowListAddressRemoved: boolean; - readonly asAllowListAddressRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; - readonly isAllowListAddressAdded: boolean; - readonly asAllowListAddressAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; - readonly isCollectionLimitSet: boolean; - readonly asCollectionLimitSet: u32; - readonly isCollectionPermissionSet: boolean; - readonly asCollectionPermissionSet: u32; - readonly type: 'CollectionSponsorRemoved' | 'CollectionAdminAdded' | 'CollectionOwnedChanged' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionAdminRemoved' | 'AllowListAddressRemoved' | 'AllowListAddressAdded' | 'CollectionLimitSet' | 'CollectionPermissionSet'; + readonly type: 'CollectionDecimalPointLimitExceeded' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection'; } /** @name PalletXcmCall */ @@ -2035,7 +2348,7 @@ export interface PalletXcmCall extends Enum { readonly isExecute: boolean; readonly asExecute: { readonly message: XcmVersionedXcm; - readonly maxWeight: Weight; + readonly maxWeight: u64; } & Struct; readonly isForceXcmVersion: boolean; readonly asForceXcmVersion: { @@ -2104,7 +2417,7 @@ export interface PalletXcmEvent extends Enum { readonly isNotified: boolean; readonly asNotified: ITuple<[u64, u8, u8]>; readonly isNotifyOverweight: boolean; - readonly asNotifyOverweight: ITuple<[u64, u8, u8, Weight, Weight]>; + readonly asNotifyOverweight: ITuple<[u64, u8, u8, SpWeightsWeightV2Weight, SpWeightsWeightV2Weight]>; readonly isNotifyDispatchError: boolean; readonly asNotifyDispatchError: ITuple<[u64, u8, u8]>; readonly isNotifyDecodeFailed: boolean; @@ -2125,11 +2438,13 @@ export interface PalletXcmEvent extends Enum { readonly asNotifyTargetSendFail: ITuple<[XcmV1MultiLocation, u64, XcmV2TraitsError]>; readonly isNotifyTargetMigrationFail: boolean; readonly asNotifyTargetMigrationFail: ITuple<[XcmVersionedMultiLocation, u64]>; - readonly type: 'Attempted' | 'Sent' | 'UnexpectedResponse' | 'ResponseReady' | 'Notified' | 'NotifyOverweight' | 'NotifyDispatchError' | 'NotifyDecodeFailed' | 'InvalidResponder' | 'InvalidResponderVersion' | 'ResponseTaken' | 'AssetsTrapped' | 'VersionChangeNotified' | 'SupportedVersionChanged' | 'NotifyTargetSendFail' | 'NotifyTargetMigrationFail'; + readonly isAssetsClaimed: boolean; + readonly asAssetsClaimed: ITuple<[H256, XcmV1MultiLocation, XcmVersionedMultiAssets]>; + readonly type: 'Attempted' | 'Sent' | 'UnexpectedResponse' | 'ResponseReady' | 'Notified' | 'NotifyOverweight' | 'NotifyDispatchError' | 'NotifyDecodeFailed' | 'InvalidResponder' | 'InvalidResponderVersion' | 'ResponseTaken' | 'AssetsTrapped' | 'VersionChangeNotified' | 'SupportedVersionChanged' | 'NotifyTargetSendFail' | 'NotifyTargetMigrationFail' | 'AssetsClaimed'; } /** @name PhantomTypeUpDataStructs */ -export interface PhantomTypeUpDataStructs extends Vec> {} +export interface PhantomTypeUpDataStructs extends Vec> {} /** @name PolkadotCorePrimitivesInboundDownwardMessage */ export interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct { @@ -2391,7 +2706,10 @@ export interface SpRuntimeDispatchError extends Enum { readonly asArithmetic: SpRuntimeArithmeticError; readonly isTransactional: boolean; readonly asTransactional: SpRuntimeTransactionalError; - readonly type: 'Other' | 'CannotLookup' | 'BadOrigin' | 'Module' | 'ConsumerRemaining' | 'NoProviders' | 'TooManyConsumers' | 'Token' | 'Arithmetic' | 'Transactional'; + readonly isExhausted: boolean; + readonly isCorruption: boolean; + readonly isUnavailable: boolean; + readonly type: 'Other' | 'CannotLookup' | 'BadOrigin' | 'Module' | 'ConsumerRemaining' | 'NoProviders' | 'TooManyConsumers' | 'Token' | 'Arithmetic' | 'Transactional' | 'Exhausted' | 'Corruption' | 'Unavailable'; } /** @name SpRuntimeModuleError */ @@ -2430,6 +2748,41 @@ export interface SpRuntimeTransactionalError extends Enum { readonly type: 'LimitReached' | 'NoLayer'; } +/** @name SpRuntimeTransactionValidityInvalidTransaction */ +export interface SpRuntimeTransactionValidityInvalidTransaction extends Enum { + readonly isCall: boolean; + readonly isPayment: boolean; + readonly isFuture: boolean; + readonly isStale: boolean; + readonly isBadProof: boolean; + readonly isAncientBirthBlock: boolean; + readonly isExhaustsResources: boolean; + readonly isCustom: boolean; + readonly asCustom: u8; + readonly isBadMandatory: boolean; + readonly isMandatoryValidation: boolean; + readonly isBadSigner: boolean; + readonly type: 'Call' | 'Payment' | 'Future' | 'Stale' | 'BadProof' | 'AncientBirthBlock' | 'ExhaustsResources' | 'Custom' | 'BadMandatory' | 'MandatoryValidation' | 'BadSigner'; +} + +/** @name SpRuntimeTransactionValidityTransactionValidityError */ +export interface SpRuntimeTransactionValidityTransactionValidityError extends Enum { + readonly isInvalid: boolean; + readonly asInvalid: SpRuntimeTransactionValidityInvalidTransaction; + readonly isUnknown: boolean; + readonly asUnknown: SpRuntimeTransactionValidityUnknownTransaction; + readonly type: 'Invalid' | 'Unknown'; +} + +/** @name SpRuntimeTransactionValidityUnknownTransaction */ +export interface SpRuntimeTransactionValidityUnknownTransaction extends Enum { + readonly isCannotLookup: boolean; + readonly isNoUnsignedValidator: boolean; + readonly isCustom: boolean; + readonly asCustom: u8; + readonly type: 'CannotLookup' | 'NoUnsignedValidator' | 'Custom'; +} + /** @name SpTrieStorageProof */ export interface SpTrieStorageProof extends Struct { readonly trieNodes: BTreeSet; @@ -2453,6 +2806,12 @@ export interface SpWeightsRuntimeDbWeight extends Struct { readonly write: u64; } +/** @name SpWeightsWeightV2Weight */ +export interface SpWeightsWeightV2Weight extends Struct { + readonly refTime: Compact; + readonly proofSize: Compact; +} + /** @name UpDataStructsAccessMode */ export interface UpDataStructsAccessMode extends Enum { readonly isNormal: boolean; @@ -2694,6 +3053,21 @@ export interface UpDataStructsTokenData extends Struct { readonly pieces: u128; } +/** @name UpPovEstimateRpcPovInfo */ +export interface UpPovEstimateRpcPovInfo extends Struct { + readonly proofSize: u64; + readonly compactProofSize: u64; + readonly compressedProofSize: u64; + readonly results: Vec, SpRuntimeTransactionValidityTransactionValidityError>>; + readonly keyValues: Vec; +} + +/** @name UpPovEstimateRpcTrieKeyValue */ +export interface UpPovEstimateRpcTrieKeyValue extends Struct { + readonly key: Bytes; + readonly value: Bytes; +} + /** @name XcmDoubleEncoded */ export interface XcmDoubleEncoded extends Struct { readonly encoded: Bytes; diff --git a/tests/src/interfaces/definitions.ts b/tests/src/interfaces/definitions.ts index 3b01bbf892..c0b082a704 100644 --- a/tests/src/interfaces/definitions.ts +++ b/tests/src/interfaces/definitions.ts @@ -17,4 +17,5 @@ export {default as unique} from './unique/definitions'; export {default as appPromotion} from './appPromotion/definitions'; export {default as rmrk} from './rmrk/definitions'; -export {default as default} from './default/definitions'; \ No newline at end of file +export {default as povinfo} from './povinfo/definitions'; +export {default as default} from './default/definitions'; diff --git a/tests/src/interfaces/lookup.ts b/tests/src/interfaces/lookup.ts index 2b7aa099d1..308f727c22 100644 --- a/tests/src/interfaces/lookup.ts +++ b/tests/src/interfaces/lookup.ts @@ -27,18 +27,25 @@ export default { * Lookup7: frame_support::dispatch::PerDispatchClass **/ FrameSupportDispatchPerDispatchClassWeight: { - normal: 'Weight', - operational: 'Weight', - mandatory: 'Weight' + normal: 'SpWeightsWeightV2Weight', + operational: 'SpWeightsWeightV2Weight', + mandatory: 'SpWeightsWeightV2Weight' }, /** - * Lookup12: sp_runtime::generic::digest::Digest + * Lookup8: sp_weights::weight_v2::Weight + **/ + SpWeightsWeightV2Weight: { + refTime: 'Compact', + proofSize: 'Compact' + }, + /** + * Lookup13: sp_runtime::generic::digest::Digest **/ SpRuntimeDigest: { logs: 'Vec' }, /** - * Lookup14: sp_runtime::generic::digest::DigestItem + * Lookup15: sp_runtime::generic::digest::DigestItem **/ SpRuntimeDigestDigestItem: { _enum: { @@ -54,7 +61,7 @@ export default { } }, /** - * Lookup17: frame_system::EventRecord + * Lookup18: frame_system::EventRecord **/ FrameSystemEventRecord: { phase: 'FrameSystemPhase', @@ -62,7 +69,7 @@ export default { topics: 'Vec' }, /** - * Lookup19: frame_system::pallet::Event + * Lookup20: frame_system::pallet::Event **/ FrameSystemEvent: { _enum: { @@ -90,27 +97,27 @@ export default { } }, /** - * Lookup20: frame_support::dispatch::DispatchInfo + * Lookup21: frame_support::dispatch::DispatchInfo **/ FrameSupportDispatchDispatchInfo: { - weight: 'Weight', + weight: 'SpWeightsWeightV2Weight', class: 'FrameSupportDispatchDispatchClass', paysFee: 'FrameSupportDispatchPays' }, /** - * Lookup21: frame_support::dispatch::DispatchClass + * Lookup22: frame_support::dispatch::DispatchClass **/ FrameSupportDispatchDispatchClass: { _enum: ['Normal', 'Operational', 'Mandatory'] }, /** - * Lookup22: frame_support::dispatch::Pays + * Lookup23: frame_support::dispatch::Pays **/ FrameSupportDispatchPays: { _enum: ['Yes', 'No'] }, /** - * Lookup23: sp_runtime::DispatchError + * Lookup24: sp_runtime::DispatchError **/ SpRuntimeDispatchError: { _enum: { @@ -123,36 +130,39 @@ export default { TooManyConsumers: 'Null', Token: 'SpRuntimeTokenError', Arithmetic: 'SpRuntimeArithmeticError', - Transactional: 'SpRuntimeTransactionalError' + Transactional: 'SpRuntimeTransactionalError', + Exhausted: 'Null', + Corruption: 'Null', + Unavailable: 'Null' } }, /** - * Lookup24: sp_runtime::ModuleError + * Lookup25: sp_runtime::ModuleError **/ SpRuntimeModuleError: { index: 'u8', error: '[u8;4]' }, /** - * Lookup25: sp_runtime::TokenError + * Lookup26: sp_runtime::TokenError **/ SpRuntimeTokenError: { _enum: ['NoFunds', 'WouldDie', 'BelowMinimum', 'CannotCreate', 'UnknownAsset', 'Frozen', 'Unsupported'] }, /** - * Lookup26: sp_runtime::ArithmeticError + * Lookup27: sp_runtime::ArithmeticError **/ SpRuntimeArithmeticError: { _enum: ['Underflow', 'Overflow', 'DivisionByZero'] }, /** - * Lookup27: sp_runtime::TransactionalError + * Lookup28: sp_runtime::TransactionalError **/ SpRuntimeTransactionalError: { _enum: ['LimitReached', 'NoLayer'] }, /** - * Lookup28: cumulus_pallet_parachain_system::pallet::Event + * Lookup29: cumulus_pallet_parachain_system::pallet::Event **/ CumulusPalletParachainSystemEvent: { _enum: { @@ -168,13 +178,13 @@ export default { count: 'u32', }, DownwardMessagesProcessed: { - weightUsed: 'Weight', + weightUsed: 'SpWeightsWeightV2Weight', dmqHead: 'H256' } } }, /** - * Lookup29: pallet_balances::pallet::Event + * Lookup30: pallet_balances::pallet::Event **/ PalletBalancesEvent: { _enum: { @@ -225,13 +235,13 @@ export default { } }, /** - * Lookup30: frame_support::traits::tokens::misc::BalanceStatus + * Lookup31: frame_support::traits::tokens::misc::BalanceStatus **/ FrameSupportTokensMiscBalanceStatus: { _enum: ['Free', 'Reserved'] }, /** - * Lookup31: pallet_transaction_payment::pallet::Event + * Lookup32: pallet_transaction_payment::pallet::Event **/ PalletTransactionPaymentEvent: { _enum: { @@ -243,7 +253,7 @@ export default { } }, /** - * Lookup32: pallet_treasury::pallet::Event + * Lookup33: pallet_treasury::pallet::Event **/ PalletTreasuryEvent: { _enum: { @@ -279,7 +289,7 @@ export default { } }, /** - * Lookup33: pallet_sudo::pallet::Event + * Lookup34: pallet_sudo::pallet::Event **/ PalletSudoEvent: { _enum: { @@ -295,7 +305,7 @@ export default { } }, /** - * Lookup37: orml_vesting::module::Event + * Lookup38: orml_vesting::module::Event **/ OrmlVestingModuleEvent: { _enum: { @@ -314,7 +324,7 @@ export default { } }, /** - * Lookup38: orml_vesting::VestingSchedule + * Lookup39: orml_vesting::VestingSchedule **/ OrmlVestingVestingSchedule: { start: 'u32', @@ -323,7 +333,7 @@ export default { perPeriod: 'Compact' }, /** - * Lookup40: orml_xtokens::module::Event + * Lookup41: orml_xtokens::module::Event **/ OrmlXtokensModuleEvent: { _enum: { @@ -336,18 +346,18 @@ export default { } }, /** - * Lookup41: xcm::v1::multiasset::MultiAssets + * Lookup42: xcm::v1::multiasset::MultiAssets **/ XcmV1MultiassetMultiAssets: 'Vec', /** - * Lookup43: xcm::v1::multiasset::MultiAsset + * Lookup44: xcm::v1::multiasset::MultiAsset **/ XcmV1MultiAsset: { id: 'XcmV1MultiassetAssetId', fun: 'XcmV1MultiassetFungibility' }, /** - * Lookup44: xcm::v1::multiasset::AssetId + * Lookup45: xcm::v1::multiasset::AssetId **/ XcmV1MultiassetAssetId: { _enum: { @@ -356,14 +366,14 @@ export default { } }, /** - * Lookup45: xcm::v1::multilocation::MultiLocation + * Lookup46: xcm::v1::multilocation::MultiLocation **/ XcmV1MultiLocation: { parents: 'u8', interior: 'XcmV1MultilocationJunctions' }, /** - * Lookup46: xcm::v1::multilocation::Junctions + * Lookup47: xcm::v1::multilocation::Junctions **/ XcmV1MultilocationJunctions: { _enum: { @@ -379,7 +389,7 @@ export default { } }, /** - * Lookup47: xcm::v1::junction::Junction + * Lookup48: xcm::v1::junction::Junction **/ XcmV1Junction: { _enum: { @@ -407,7 +417,7 @@ export default { } }, /** - * Lookup49: xcm::v0::junction::NetworkId + * Lookup50: xcm::v0::junction::NetworkId **/ XcmV0JunctionNetworkId: { _enum: { @@ -576,12 +586,12 @@ export default { _enum: { Success: { messageHash: 'Option', - weight: 'Weight', + weight: 'SpWeightsWeightV2Weight', }, Fail: { messageHash: 'Option', error: 'XcmV2TraitsError', - weight: 'Weight', + weight: 'SpWeightsWeightV2Weight', }, BadVersion: { messageHash: 'Option', @@ -599,11 +609,11 @@ export default { sender: 'u32', sentAt: 'u32', index: 'u64', - required: 'Weight', + required: 'SpWeightsWeightV2Weight', }, OverweightServiced: { index: 'u64', - used: 'Weight' + used: 'SpWeightsWeightV2Weight' } } }, @@ -650,7 +660,7 @@ export default { UnexpectedResponse: '(XcmV1MultiLocation,u64)', ResponseReady: '(u64,XcmV2Response)', Notified: '(u64,u8,u8)', - NotifyOverweight: '(u64,u8,u8,Weight,Weight)', + NotifyOverweight: '(u64,u8,u8,SpWeightsWeightV2Weight,SpWeightsWeightV2Weight)', NotifyDispatchError: '(u64,u8,u8)', NotifyDecodeFailed: '(u64,u8,u8)', InvalidResponder: '(XcmV1MultiLocation,u64,Option)', @@ -660,7 +670,8 @@ export default { VersionChangeNotified: '(XcmV1MultiLocation,u32)', SupportedVersionChanged: '(XcmV1MultiLocation,u32)', NotifyTargetSendFail: '(XcmV1MultiLocation,u64,XcmV2TraitsError)', - NotifyTargetMigrationFail: '(XcmVersionedMultiLocation,u64)' + NotifyTargetMigrationFail: '(XcmVersionedMultiLocation,u64)', + AssetsClaimed: '(H256,XcmV1MultiLocation,XcmVersionedMultiAssets)' } }, /** @@ -963,39 +974,51 @@ export default { }, WeightExhausted: { messageId: '[u8;32]', - remainingWeight: 'Weight', - requiredWeight: 'Weight', + remainingWeight: 'SpWeightsWeightV2Weight', + requiredWeight: 'SpWeightsWeightV2Weight', }, OverweightEnqueued: { messageId: '[u8;32]', overweightIndex: 'u64', - requiredWeight: 'Weight', + requiredWeight: 'SpWeightsWeightV2Weight', }, OverweightServiced: { overweightIndex: 'u64', - weightUsed: 'Weight' + weightUsed: 'SpWeightsWeightV2Weight' } } }, /** - * Lookup89: pallet_unique::RawEvent> + * Lookup89: pallet_common::pallet::Event **/ - PalletUniqueRawEvent: { + PalletCommonEvent: { _enum: { - CollectionSponsorRemoved: 'u32', + CollectionCreated: '(u32,u8,AccountId32)', + CollectionDestroyed: 'u32', + ItemCreated: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)', + ItemDestroyed: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)', + Transfer: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)', + Approved: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)', + ApprovedForAll: '(u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,bool)', + CollectionPropertySet: '(u32,Bytes)', + CollectionPropertyDeleted: '(u32,Bytes)', + TokenPropertySet: '(u32,u32,Bytes)', + TokenPropertyDeleted: '(u32,u32,Bytes)', + PropertyPermissionSet: '(u32,Bytes)', + AllowListAddressAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)', + AllowListAddressRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)', CollectionAdminAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)', - CollectionOwnedChanged: '(u32,AccountId32)', - CollectionSponsorSet: '(u32,AccountId32)', - SponsorshipConfirmed: '(u32,AccountId32)', CollectionAdminRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)', - AllowListAddressRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)', - AllowListAddressAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)', CollectionLimitSet: 'u32', - CollectionPermissionSet: 'u32' + CollectionOwnerChanged: '(u32,AccountId32)', + CollectionPermissionSet: 'u32', + CollectionSponsorSet: '(u32,AccountId32)', + SponsorshipConfirmed: '(u32,AccountId32)', + CollectionSponsorRemoved: 'u32' } }, /** - * Lookup90: pallet_evm::account::BasicCrossAccountIdRepr + * Lookup92: pallet_evm::account::BasicCrossAccountIdRepr **/ PalletEvmAccountBasicCrossAccountIdRepr: { _enum: { @@ -1004,33 +1027,116 @@ export default { } }, /** - * Lookup93: pallet_common::pallet::Event + * Lookup96: pallet_structure::pallet::Event **/ - PalletCommonEvent: { + PalletStructureEvent: { _enum: { - CollectionCreated: '(u32,u8,AccountId32)', - CollectionDestroyed: 'u32', - ItemCreated: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)', - ItemDestroyed: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,u128)', - Transfer: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)', - Approved: '(u32,u32,PalletEvmAccountBasicCrossAccountIdRepr,PalletEvmAccountBasicCrossAccountIdRepr,u128)', - CollectionPropertySet: '(u32,Bytes)', - CollectionPropertyDeleted: '(u32,Bytes)', - TokenPropertySet: '(u32,u32,Bytes)', - TokenPropertyDeleted: '(u32,u32,Bytes)', - PropertyPermissionSet: '(u32,Bytes)' + Executed: 'Result' } }, /** - * Lookup96: pallet_structure::pallet::Event + * Lookup97: pallet_rmrk_core::pallet::Event **/ - PalletStructureEvent: { + PalletRmrkCoreEvent: { _enum: { - Executed: 'Result' + CollectionCreated: { + issuer: 'AccountId32', + collectionId: 'u32', + }, + CollectionDestroyed: { + issuer: 'AccountId32', + collectionId: 'u32', + }, + IssuerChanged: { + oldIssuer: 'AccountId32', + newIssuer: 'AccountId32', + collectionId: 'u32', + }, + CollectionLocked: { + issuer: 'AccountId32', + collectionId: 'u32', + }, + NftMinted: { + owner: 'AccountId32', + collectionId: 'u32', + nftId: 'u32', + }, + NFTBurned: { + owner: 'AccountId32', + nftId: 'u32', + }, + NFTSent: { + sender: 'AccountId32', + recipient: 'RmrkTraitsNftAccountIdOrCollectionNftTuple', + collectionId: 'u32', + nftId: 'u32', + approvalRequired: 'bool', + }, + NFTAccepted: { + sender: 'AccountId32', + recipient: 'RmrkTraitsNftAccountIdOrCollectionNftTuple', + collectionId: 'u32', + nftId: 'u32', + }, + NFTRejected: { + sender: 'AccountId32', + collectionId: 'u32', + nftId: 'u32', + }, + PropertySet: { + collectionId: 'u32', + maybeNftId: 'Option', + key: 'Bytes', + value: 'Bytes', + }, + ResourceAdded: { + nftId: 'u32', + resourceId: 'u32', + }, + ResourceRemoval: { + nftId: 'u32', + resourceId: 'u32', + }, + ResourceAccepted: { + nftId: 'u32', + resourceId: 'u32', + }, + ResourceRemovalAccepted: { + nftId: 'u32', + resourceId: 'u32', + }, + PrioritySet: { + collectionId: 'u32', + nftId: 'u32' + } + } + }, + /** + * Lookup98: rmrk_traits::nft::AccountIdOrCollectionNftTuple + **/ + RmrkTraitsNftAccountIdOrCollectionNftTuple: { + _enum: { + AccountId: 'AccountId32', + CollectionAndNftTuple: '(u32,u32)' } }, /** - * Lookup97: pallet_app_promotion::pallet::Event + * Lookup102: pallet_rmrk_equip::pallet::Event + **/ + PalletRmrkEquipEvent: { + _enum: { + BaseCreated: { + issuer: 'AccountId32', + baseId: 'u32', + }, + EquippablesUpdated: { + baseId: 'u32', + slotId: 'u32' + } + } + }, + /** + * Lookup103: pallet_app_promotion::pallet::Event **/ PalletAppPromotionEvent: { _enum: { @@ -1041,7 +1147,7 @@ export default { } }, /** - * Lookup98: pallet_foreign_assets::module::Event + * Lookup104: pallet_foreign_assets::module::Event **/ PalletForeignAssetsModuleEvent: { _enum: { @@ -1066,7 +1172,7 @@ export default { } }, /** - * Lookup99: pallet_foreign_assets::module::AssetMetadata + * Lookup105: pallet_foreign_assets::module::AssetMetadata **/ PalletForeignAssetsModuleAssetMetadata: { name: 'Bytes', @@ -1075,21 +1181,29 @@ export default { minimalBalance: 'u128' }, /** - * Lookup100: pallet_evm::pallet::Event + * Lookup106: pallet_evm::pallet::Event **/ PalletEvmEvent: { _enum: { - Log: 'EthereumLog', - Created: 'H160', - CreatedFailed: 'H160', - Executed: 'H160', - ExecutedFailed: 'H160', - BalanceDeposit: '(AccountId32,H160,U256)', - BalanceWithdraw: '(AccountId32,H160,U256)' + Log: { + log: 'EthereumLog', + }, + Created: { + address: 'H160', + }, + CreatedFailed: { + address: 'H160', + }, + Executed: { + address: 'H160', + }, + ExecutedFailed: { + address: 'H160' + } } }, /** - * Lookup101: ethereum::log::Log + * Lookup107: ethereum::log::Log **/ EthereumLog: { address: 'H160', @@ -1097,15 +1211,20 @@ export default { data: 'Bytes' }, /** - * Lookup105: pallet_ethereum::pallet::Event + * Lookup109: pallet_ethereum::pallet::Event **/ PalletEthereumEvent: { _enum: { - Executed: '(H160,H160,H256,EvmCoreErrorExitReason)' + Executed: { + from: 'H160', + to: 'H160', + transactionHash: 'H256', + exitReason: 'EvmCoreErrorExitReason' + } } }, /** - * Lookup106: evm_core::error::ExitReason + * Lookup110: evm_core::error::ExitReason **/ EvmCoreErrorExitReason: { _enum: { @@ -1116,13 +1235,13 @@ export default { } }, /** - * Lookup107: evm_core::error::ExitSucceed + * Lookup111: evm_core::error::ExitSucceed **/ EvmCoreErrorExitSucceed: { _enum: ['Stopped', 'Returned', 'Suicided'] }, /** - * Lookup108: evm_core::error::ExitError + * Lookup112: evm_core::error::ExitError **/ EvmCoreErrorExitError: { _enum: { @@ -1144,13 +1263,13 @@ export default { } }, /** - * Lookup111: evm_core::error::ExitRevert + * Lookup115: evm_core::error::ExitRevert **/ EvmCoreErrorExitRevert: { _enum: ['Reverted'] }, /** - * Lookup112: evm_core::error::ExitFatal + * Lookup116: evm_core::error::ExitFatal **/ EvmCoreErrorExitFatal: { _enum: { @@ -1161,7 +1280,7 @@ export default { } }, /** - * Lookup113: pallet_evm_contract_helpers::pallet::Event + * Lookup117: pallet_evm_contract_helpers::pallet::Event **/ PalletEvmContractHelpersEvent: { _enum: { @@ -1171,19 +1290,25 @@ export default { } }, /** - * Lookup114: pallet_evm_migration::pallet::Event + * Lookup118: pallet_evm_migration::pallet::Event **/ PalletEvmMigrationEvent: { _enum: ['TestEvent'] }, /** - * Lookup115: pallet_maintenance::pallet::Event + * Lookup119: pallet_maintenance::pallet::Event **/ PalletMaintenanceEvent: { _enum: ['MaintenanceEnabled', 'MaintenanceDisabled'] }, /** - * Lookup116: frame_system::Phase + * Lookup120: pallet_test_utils::pallet::Event + **/ + PalletTestUtilsEvent: { + _enum: ['ValueIsSet', 'ShouldRollback', 'BatchCompleted'] + }, + /** + * Lookup121: frame_system::Phase **/ FrameSystemPhase: { _enum: { @@ -1193,20 +1318,17 @@ export default { } }, /** - * Lookup119: frame_system::LastRuntimeUpgradeInfo + * Lookup124: frame_system::LastRuntimeUpgradeInfo **/ FrameSystemLastRuntimeUpgradeInfo: { specVersion: 'Compact', specName: 'Text' }, /** - * Lookup121: frame_system::pallet::Call + * Lookup125: frame_system::pallet::Call **/ FrameSystemCall: { _enum: { - fill_block: { - ratio: 'Perbill', - }, remark: { remark: 'Bytes', }, @@ -1238,15 +1360,15 @@ export default { } }, /** - * Lookup126: frame_system::limits::BlockWeights + * Lookup129: frame_system::limits::BlockWeights **/ FrameSystemLimitsBlockWeights: { - baseBlock: 'Weight', - maxBlock: 'Weight', + baseBlock: 'SpWeightsWeightV2Weight', + maxBlock: 'SpWeightsWeightV2Weight', perClass: 'FrameSupportDispatchPerDispatchClassWeightsPerClass' }, /** - * Lookup127: frame_support::dispatch::PerDispatchClass + * Lookup130: frame_support::dispatch::PerDispatchClass **/ FrameSupportDispatchPerDispatchClassWeightsPerClass: { normal: 'FrameSystemLimitsWeightsPerClass', @@ -1254,22 +1376,22 @@ export default { mandatory: 'FrameSystemLimitsWeightsPerClass' }, /** - * Lookup128: frame_system::limits::WeightsPerClass + * Lookup131: frame_system::limits::WeightsPerClass **/ FrameSystemLimitsWeightsPerClass: { - baseExtrinsic: 'Weight', - maxExtrinsic: 'Option', - maxTotal: 'Option', - reserved: 'Option' + baseExtrinsic: 'SpWeightsWeightV2Weight', + maxExtrinsic: 'Option', + maxTotal: 'Option', + reserved: 'Option' }, /** - * Lookup130: frame_system::limits::BlockLength + * Lookup133: frame_system::limits::BlockLength **/ FrameSystemLimitsBlockLength: { max: 'FrameSupportDispatchPerDispatchClassU32' }, /** - * Lookup131: frame_support::dispatch::PerDispatchClass + * Lookup134: frame_support::dispatch::PerDispatchClass **/ FrameSupportDispatchPerDispatchClassU32: { normal: 'u32', @@ -1277,14 +1399,14 @@ export default { mandatory: 'u32' }, /** - * Lookup132: sp_weights::RuntimeDbWeight + * Lookup135: sp_weights::RuntimeDbWeight **/ SpWeightsRuntimeDbWeight: { read: 'u64', write: 'u64' }, /** - * Lookup133: sp_version::RuntimeVersion + * Lookup136: sp_version::RuntimeVersion **/ SpVersionRuntimeVersion: { specName: 'Text', @@ -1297,13 +1419,13 @@ export default { stateVersion: 'u8' }, /** - * Lookup138: frame_system::pallet::Error + * Lookup141: frame_system::pallet::Error **/ FrameSystemError: { _enum: ['InvalidSpecName', 'SpecVersionNeedsToIncrease', 'FailedToExtractRuntimeVersion', 'NonDefaultComposite', 'NonZeroRefCount', 'CallFiltered'] }, /** - * Lookup139: polkadot_primitives::v2::PersistedValidationData + * Lookup142: polkadot_primitives::v2::PersistedValidationData **/ PolkadotPrimitivesV2PersistedValidationData: { parentHead: 'Bytes', @@ -1312,19 +1434,19 @@ export default { maxPovSize: 'u32' }, /** - * Lookup142: polkadot_primitives::v2::UpgradeRestriction + * Lookup145: polkadot_primitives::v2::UpgradeRestriction **/ PolkadotPrimitivesV2UpgradeRestriction: { _enum: ['Present'] }, /** - * Lookup143: sp_trie::storage_proof::StorageProof + * Lookup146: sp_trie::storage_proof::StorageProof **/ SpTrieStorageProof: { trieNodes: 'BTreeSet' }, /** - * Lookup145: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot + * Lookup148: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot **/ CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot: { dmqMqcHead: 'H256', @@ -1333,7 +1455,7 @@ export default { egressChannels: 'Vec<(u32,PolkadotPrimitivesV2AbridgedHrmpChannel)>' }, /** - * Lookup148: polkadot_primitives::v2::AbridgedHrmpChannel + * Lookup151: polkadot_primitives::v2::AbridgedHrmpChannel **/ PolkadotPrimitivesV2AbridgedHrmpChannel: { maxCapacity: 'u32', @@ -1344,7 +1466,7 @@ export default { mqcHead: 'Option' }, /** - * Lookup149: polkadot_primitives::v2::AbridgedHostConfiguration + * Lookup152: polkadot_primitives::v2::AbridgedHostConfiguration **/ PolkadotPrimitivesV2AbridgedHostConfiguration: { maxCodeSize: 'u32', @@ -1358,14 +1480,14 @@ export default { validationUpgradeDelay: 'u32' }, /** - * Lookup155: polkadot_core_primitives::OutboundHrmpMessage + * Lookup158: polkadot_core_primitives::OutboundHrmpMessage **/ PolkadotCorePrimitivesOutboundHrmpMessage: { recipient: 'u32', data: 'Bytes' }, /** - * Lookup156: cumulus_pallet_parachain_system::pallet::Call + * Lookup159: cumulus_pallet_parachain_system::pallet::Call **/ CumulusPalletParachainSystemCall: { _enum: { @@ -1384,7 +1506,7 @@ export default { } }, /** - * Lookup157: cumulus_primitives_parachain_inherent::ParachainInherentData + * Lookup160: cumulus_primitives_parachain_inherent::ParachainInherentData **/ CumulusPrimitivesParachainInherentParachainInherentData: { validationData: 'PolkadotPrimitivesV2PersistedValidationData', @@ -1393,27 +1515,27 @@ export default { horizontalMessages: 'BTreeMap>' }, /** - * Lookup159: polkadot_core_primitives::InboundDownwardMessage + * Lookup162: polkadot_core_primitives::InboundDownwardMessage **/ PolkadotCorePrimitivesInboundDownwardMessage: { sentAt: 'u32', msg: 'Bytes' }, /** - * Lookup162: polkadot_core_primitives::InboundHrmpMessage + * Lookup165: polkadot_core_primitives::InboundHrmpMessage **/ PolkadotCorePrimitivesInboundHrmpMessage: { sentAt: 'u32', data: 'Bytes' }, /** - * Lookup165: cumulus_pallet_parachain_system::pallet::Error + * Lookup168: cumulus_pallet_parachain_system::pallet::Error **/ CumulusPalletParachainSystemError: { _enum: ['OverlappingUpgrades', 'ProhibitedByPolkadot', 'TooBig', 'ValidationDataNotAvailable', 'HostConfigurationNotAvailable', 'NotScheduled', 'NothingAuthorized', 'Unauthorized'] }, /** - * Lookup167: pallet_balances::BalanceLock + * Lookup170: pallet_balances::BalanceLock **/ PalletBalancesBalanceLock: { id: '[u8;8]', @@ -1421,26 +1543,20 @@ export default { reasons: 'PalletBalancesReasons' }, /** - * Lookup168: pallet_balances::Reasons + * Lookup171: pallet_balances::Reasons **/ PalletBalancesReasons: { _enum: ['Fee', 'Misc', 'All'] }, /** - * Lookup171: pallet_balances::ReserveData + * Lookup174: pallet_balances::ReserveData **/ PalletBalancesReserveData: { id: '[u8;16]', amount: 'u128' }, /** - * Lookup173: pallet_balances::Releases - **/ - PalletBalancesReleases: { - _enum: ['V1_0_0', 'V2_0_0'] - }, - /** - * Lookup174: pallet_balances::pallet::Call + * Lookup176: pallet_balances::pallet::Call **/ PalletBalancesCall: { _enum: { @@ -1473,13 +1589,13 @@ export default { } }, /** - * Lookup177: pallet_balances::pallet::Error + * Lookup179: pallet_balances::pallet::Error **/ PalletBalancesError: { _enum: ['VestingBalance', 'LiquidityRestrictions', 'InsufficientBalance', 'ExistentialDeposit', 'KeepAlive', 'ExistingVestingSchedule', 'DeadAccount', 'TooManyReserves'] }, /** - * Lookup179: pallet_timestamp::pallet::Call + * Lookup181: pallet_timestamp::pallet::Call **/ PalletTimestampCall: { _enum: { @@ -1489,13 +1605,13 @@ export default { } }, /** - * Lookup181: pallet_transaction_payment::Releases + * Lookup183: pallet_transaction_payment::Releases **/ PalletTransactionPaymentReleases: { _enum: ['V1Ancient', 'V2'] }, /** - * Lookup182: pallet_treasury::Proposal + * Lookup184: pallet_treasury::Proposal **/ PalletTreasuryProposal: { proposer: 'AccountId32', @@ -1504,7 +1620,7 @@ export default { bond: 'u128' }, /** - * Lookup185: pallet_treasury::pallet::Call + * Lookup187: pallet_treasury::pallet::Call **/ PalletTreasuryCall: { _enum: { @@ -1528,17 +1644,17 @@ export default { } }, /** - * Lookup188: frame_support::PalletId + * Lookup190: frame_support::PalletId **/ FrameSupportPalletId: '[u8;8]', /** - * Lookup189: pallet_treasury::pallet::Error + * Lookup191: pallet_treasury::pallet::Error **/ PalletTreasuryError: { _enum: ['InsufficientProposersBalance', 'InvalidIndex', 'TooManyApprovals', 'InsufficientPermission', 'ProposalNotApproved'] }, /** - * Lookup190: pallet_sudo::pallet::Call + * Lookup192: pallet_sudo::pallet::Call **/ PalletSudoCall: { _enum: { @@ -1547,7 +1663,7 @@ export default { }, sudo_unchecked_weight: { call: 'Call', - weight: 'Weight', + weight: 'SpWeightsWeightV2Weight', }, set_key: { _alias: { @@ -1562,7 +1678,7 @@ export default { } }, /** - * Lookup192: orml_vesting::module::Call + * Lookup194: orml_vesting::module::Call **/ OrmlVestingModuleCall: { _enum: { @@ -1581,7 +1697,7 @@ export default { } }, /** - * Lookup194: orml_xtokens::module::Call + * Lookup196: orml_xtokens::module::Call **/ OrmlXtokensModuleCall: { _enum: { @@ -1589,42 +1705,42 @@ export default { currencyId: 'PalletForeignAssetsAssetIds', amount: 'u128', dest: 'XcmVersionedMultiLocation', - destWeight: 'u64', + destWeightLimit: 'XcmV2WeightLimit', }, transfer_multiasset: { asset: 'XcmVersionedMultiAsset', dest: 'XcmVersionedMultiLocation', - destWeight: 'u64', + destWeightLimit: 'XcmV2WeightLimit', }, transfer_with_fee: { currencyId: 'PalletForeignAssetsAssetIds', amount: 'u128', fee: 'u128', dest: 'XcmVersionedMultiLocation', - destWeight: 'u64', + destWeightLimit: 'XcmV2WeightLimit', }, transfer_multiasset_with_fee: { asset: 'XcmVersionedMultiAsset', fee: 'XcmVersionedMultiAsset', dest: 'XcmVersionedMultiLocation', - destWeight: 'u64', + destWeightLimit: 'XcmV2WeightLimit', }, transfer_multicurrencies: { currencies: 'Vec<(PalletForeignAssetsAssetIds,u128)>', feeItem: 'u32', dest: 'XcmVersionedMultiLocation', - destWeight: 'u64', + destWeightLimit: 'XcmV2WeightLimit', }, transfer_multiassets: { assets: 'XcmVersionedMultiAssets', feeItem: 'u32', dest: 'XcmVersionedMultiLocation', - destWeight: 'u64' + destWeightLimit: 'XcmV2WeightLimit' } } }, /** - * Lookup195: xcm::VersionedMultiAsset + * Lookup197: xcm::VersionedMultiAsset **/ XcmVersionedMultiAsset: { _enum: { @@ -1633,7 +1749,7 @@ export default { } }, /** - * Lookup198: orml_tokens::module::Call + * Lookup200: orml_tokens::module::Call **/ OrmlTokensModuleCall: { _enum: { @@ -1667,13 +1783,13 @@ export default { } }, /** - * Lookup199: cumulus_pallet_xcmp_queue::pallet::Call + * Lookup201: cumulus_pallet_xcmp_queue::pallet::Call **/ CumulusPalletXcmpQueueCall: { _enum: { service_overweight: { index: 'u64', - weightLimit: 'Weight', + weightLimit: 'u64', }, suspend_xcm_execution: 'Null', resume_xcm_execution: 'Null', @@ -1699,24 +1815,24 @@ export default { _alias: { new_: 'new', }, - new_: 'Weight', + new_: 'u64', }, update_weight_restrict_decay: { _alias: { new_: 'new', }, - new_: 'Weight', + new_: 'u64', }, update_xcmp_max_individual_weight: { _alias: { new_: 'new', }, - new_: 'Weight' + new_: 'u64' } } }, /** - * Lookup200: pallet_xcm::pallet::Call + * Lookup202: pallet_xcm::pallet::Call **/ PalletXcmCall: { _enum: { @@ -1738,7 +1854,7 @@ export default { }, execute: { message: 'XcmVersionedXcm', - maxWeight: 'Weight', + maxWeight: 'u64', }, force_xcm_version: { location: 'XcmV1MultiLocation', @@ -1770,7 +1886,7 @@ export default { } }, /** - * Lookup201: xcm::VersionedXcm + * Lookup203: xcm::VersionedXcm **/ XcmVersionedXcm: { _enum: { @@ -1780,7 +1896,7 @@ export default { } }, /** - * Lookup202: xcm::v0::Xcm + * Lookup204: xcm::v0::Xcm **/ XcmV0Xcm: { _enum: { @@ -1834,7 +1950,7 @@ export default { } }, /** - * Lookup204: xcm::v0::order::Order + * Lookup206: xcm::v0::order::Order **/ XcmV0Order: { _enum: { @@ -1877,7 +1993,7 @@ export default { } }, /** - * Lookup206: xcm::v0::Response + * Lookup208: xcm::v0::Response **/ XcmV0Response: { _enum: { @@ -1885,7 +2001,7 @@ export default { } }, /** - * Lookup207: xcm::v1::Xcm + * Lookup209: xcm::v1::Xcm **/ XcmV1Xcm: { _enum: { @@ -1944,7 +2060,7 @@ export default { } }, /** - * Lookup209: xcm::v1::order::Order + * Lookup211: xcm::v1::order::Order **/ XcmV1Order: { _enum: { @@ -1989,7 +2105,7 @@ export default { } }, /** - * Lookup211: xcm::v1::Response + * Lookup213: xcm::v1::Response **/ XcmV1Response: { _enum: { @@ -1998,22 +2114,22 @@ export default { } }, /** - * Lookup226: cumulus_pallet_xcm::pallet::Call + * Lookup227: cumulus_pallet_xcm::pallet::Call **/ CumulusPalletXcmCall: 'Null', /** - * Lookup227: cumulus_pallet_dmp_queue::pallet::Call + * Lookup228: cumulus_pallet_dmp_queue::pallet::Call **/ CumulusPalletDmpQueueCall: { _enum: { service_overweight: { index: 'u64', - weightLimit: 'Weight' + weightLimit: 'u64' } } }, /** - * Lookup228: pallet_inflation::pallet::Call + * Lookup229: pallet_inflation::pallet::Call **/ PalletInflationCall: { _enum: { @@ -2023,7 +2139,7 @@ export default { } }, /** - * Lookup229: pallet_unique::Call + * Lookup230: pallet_unique::Call **/ PalletUniqueCall: { _enum: { @@ -2152,14 +2268,22 @@ export default { tokenId: 'u32', amount: 'u128', }, - repair_item: { + set_allowance_for_all: { + collectionId: 'u32', + operator: 'PalletEvmAccountBasicCrossAccountIdRepr', + approve: 'bool', + }, + force_repair_collection: { + collectionId: 'u32', + }, + force_repair_item: { collectionId: 'u32', itemId: 'u32' } } }, /** - * Lookup234: up_data_structs::CollectionMode + * Lookup235: up_data_structs::CollectionMode **/ UpDataStructsCollectionMode: { _enum: { @@ -2169,7 +2293,7 @@ export default { } }, /** - * Lookup235: up_data_structs::CreateCollectionData + * Lookup236: up_data_structs::CreateCollectionData **/ UpDataStructsCreateCollectionData: { mode: 'UpDataStructsCollectionMode', @@ -2184,13 +2308,13 @@ export default { properties: 'Vec' }, /** - * Lookup237: up_data_structs::AccessMode + * Lookup238: up_data_structs::AccessMode **/ UpDataStructsAccessMode: { _enum: ['Normal', 'AllowList'] }, /** - * Lookup239: up_data_structs::CollectionLimits + * Lookup240: up_data_structs::CollectionLimits **/ UpDataStructsCollectionLimits: { accountTokenOwnershipLimit: 'Option', @@ -2204,7 +2328,7 @@ export default { transfersEnabled: 'Option' }, /** - * Lookup241: up_data_structs::SponsoringRateLimit + * Lookup242: up_data_structs::SponsoringRateLimit **/ UpDataStructsSponsoringRateLimit: { _enum: { @@ -2213,7 +2337,7 @@ export default { } }, /** - * Lookup244: up_data_structs::CollectionPermissions + * Lookup245: up_data_structs::CollectionPermissions **/ UpDataStructsCollectionPermissions: { access: 'Option', @@ -2221,7 +2345,7 @@ export default { nesting: 'Option' }, /** - * Lookup246: up_data_structs::NestingPermissions + * Lookup247: up_data_structs::NestingPermissions **/ UpDataStructsNestingPermissions: { tokenOwner: 'bool', @@ -2229,18 +2353,18 @@ export default { restricted: 'Option' }, /** - * Lookup248: up_data_structs::OwnerRestrictedSet + * Lookup249: up_data_structs::OwnerRestrictedSet **/ UpDataStructsOwnerRestrictedSet: 'BTreeSet', /** - * Lookup253: up_data_structs::PropertyKeyPermission + * Lookup254: up_data_structs::PropertyKeyPermission **/ UpDataStructsPropertyKeyPermission: { key: 'Bytes', permission: 'UpDataStructsPropertyPermission' }, /** - * Lookup254: up_data_structs::PropertyPermission + * Lookup255: up_data_structs::PropertyPermission **/ UpDataStructsPropertyPermission: { mutable: 'bool', @@ -2248,14 +2372,14 @@ export default { tokenOwner: 'bool' }, /** - * Lookup257: up_data_structs::Property + * Lookup258: up_data_structs::Property **/ UpDataStructsProperty: { key: 'Bytes', value: 'Bytes' }, /** - * Lookup260: up_data_structs::CreateItemData + * Lookup261: up_data_structs::CreateItemData **/ UpDataStructsCreateItemData: { _enum: { @@ -2265,26 +2389,26 @@ export default { } }, /** - * Lookup261: up_data_structs::CreateNftData + * Lookup262: up_data_structs::CreateNftData **/ UpDataStructsCreateNftData: { properties: 'Vec' }, /** - * Lookup262: up_data_structs::CreateFungibleData + * Lookup263: up_data_structs::CreateFungibleData **/ UpDataStructsCreateFungibleData: { value: 'u128' }, /** - * Lookup263: up_data_structs::CreateReFungibleData + * Lookup264: up_data_structs::CreateReFungibleData **/ UpDataStructsCreateReFungibleData: { pieces: 'u128', properties: 'Vec' }, /** - * Lookup266: up_data_structs::CreateItemExData> + * Lookup267: up_data_structs::CreateItemExData> **/ UpDataStructsCreateItemExData: { _enum: { @@ -2295,14 +2419,14 @@ export default { } }, /** - * Lookup268: up_data_structs::CreateNftExData> + * Lookup269: up_data_structs::CreateNftExData> **/ UpDataStructsCreateNftExData: { properties: 'Vec', owner: 'PalletEvmAccountBasicCrossAccountIdRepr' }, /** - * Lookup275: up_data_structs::CreateRefungibleExSingleOwner> + * Lookup276: up_data_structs::CreateRefungibleExSingleOwner> **/ UpDataStructsCreateRefungibleExSingleOwner: { user: 'PalletEvmAccountBasicCrossAccountIdRepr', @@ -2310,19 +2434,19 @@ export default { properties: 'Vec' }, /** - * Lookup277: up_data_structs::CreateRefungibleExMultipleOwners> + * Lookup278: up_data_structs::CreateRefungibleExMultipleOwners> **/ UpDataStructsCreateRefungibleExMultipleOwners: { users: 'BTreeMap', properties: 'Vec' }, /** - * Lookup278: pallet_configuration::pallet::Call + * Lookup279: pallet_configuration::pallet::Call **/ PalletConfigurationCall: { _enum: { set_weight_to_fee_coefficient_override: { - coeff: 'Option', + coeff: 'Option', }, set_min_gas_price_override: { coeff: 'Option', @@ -2336,7 +2460,7 @@ export default { } }, /** - * Lookup283: pallet_configuration::AppPromotionConfiguration + * Lookup284: pallet_configuration::AppPromotionConfiguration **/ PalletConfigurationAppPromotionConfiguration: { recalculationInterval: 'Option', @@ -2345,15 +2469,219 @@ export default { maxStakersPerCalculation: 'Option' }, /** - * Lookup286: pallet_template_transaction_payment::Call + * Lookup288: pallet_template_transaction_payment::Call **/ PalletTemplateTransactionPaymentCall: 'Null', /** - * Lookup287: pallet_structure::pallet::Call + * Lookup289: pallet_structure::pallet::Call **/ PalletStructureCall: 'Null', /** - * Lookup288: pallet_app_promotion::pallet::Call + * Lookup290: pallet_rmrk_core::pallet::Call + **/ + PalletRmrkCoreCall: { + _enum: { + create_collection: { + metadata: 'Bytes', + max: 'Option', + symbol: 'Bytes', + }, + destroy_collection: { + collectionId: 'u32', + }, + change_collection_issuer: { + collectionId: 'u32', + newIssuer: 'MultiAddress', + }, + lock_collection: { + collectionId: 'u32', + }, + mint_nft: { + owner: 'Option', + collectionId: 'u32', + recipient: 'Option', + royaltyAmount: 'Option', + metadata: 'Bytes', + transferable: 'bool', + resources: 'Option>', + }, + burn_nft: { + collectionId: 'u32', + nftId: 'u32', + maxBurns: 'u32', + }, + send: { + rmrkCollectionId: 'u32', + rmrkNftId: 'u32', + newOwner: 'RmrkTraitsNftAccountIdOrCollectionNftTuple', + }, + accept_nft: { + rmrkCollectionId: 'u32', + rmrkNftId: 'u32', + newOwner: 'RmrkTraitsNftAccountIdOrCollectionNftTuple', + }, + reject_nft: { + rmrkCollectionId: 'u32', + rmrkNftId: 'u32', + }, + accept_resource: { + rmrkCollectionId: 'u32', + rmrkNftId: 'u32', + resourceId: 'u32', + }, + accept_resource_removal: { + rmrkCollectionId: 'u32', + rmrkNftId: 'u32', + resourceId: 'u32', + }, + set_property: { + rmrkCollectionId: 'Compact', + maybeNftId: 'Option', + key: 'Bytes', + value: 'Bytes', + }, + set_priority: { + rmrkCollectionId: 'u32', + rmrkNftId: 'u32', + priorities: 'Vec', + }, + add_basic_resource: { + rmrkCollectionId: 'u32', + nftId: 'u32', + resource: 'RmrkTraitsResourceBasicResource', + }, + add_composable_resource: { + rmrkCollectionId: 'u32', + nftId: 'u32', + resource: 'RmrkTraitsResourceComposableResource', + }, + add_slot_resource: { + rmrkCollectionId: 'u32', + nftId: 'u32', + resource: 'RmrkTraitsResourceSlotResource', + }, + remove_resource: { + rmrkCollectionId: 'u32', + nftId: 'u32', + resourceId: 'u32' + } + } + }, + /** + * Lookup296: rmrk_traits::resource::ResourceTypes, sp_core::bounded::bounded_vec::BoundedVec> + **/ + RmrkTraitsResourceResourceTypes: { + _enum: { + Basic: 'RmrkTraitsResourceBasicResource', + Composable: 'RmrkTraitsResourceComposableResource', + Slot: 'RmrkTraitsResourceSlotResource' + } + }, + /** + * Lookup298: rmrk_traits::resource::BasicResource> + **/ + RmrkTraitsResourceBasicResource: { + src: 'Option', + metadata: 'Option', + license: 'Option', + thumb: 'Option' + }, + /** + * Lookup300: rmrk_traits::resource::ComposableResource, sp_core::bounded::bounded_vec::BoundedVec> + **/ + RmrkTraitsResourceComposableResource: { + parts: 'Vec', + base: 'u32', + src: 'Option', + metadata: 'Option', + license: 'Option', + thumb: 'Option' + }, + /** + * Lookup301: rmrk_traits::resource::SlotResource> + **/ + RmrkTraitsResourceSlotResource: { + base: 'u32', + src: 'Option', + metadata: 'Option', + slot: 'u32', + license: 'Option', + thumb: 'Option' + }, + /** + * Lookup304: pallet_rmrk_equip::pallet::Call + **/ + PalletRmrkEquipCall: { + _enum: { + create_base: { + baseType: 'Bytes', + symbol: 'Bytes', + parts: 'Vec', + }, + theme_add: { + baseId: 'u32', + theme: 'RmrkTraitsTheme', + }, + equippable: { + baseId: 'u32', + slotId: 'u32', + equippables: 'RmrkTraitsPartEquippableList' + } + } + }, + /** + * Lookup307: rmrk_traits::part::PartType, sp_core::bounded::bounded_vec::BoundedVec> + **/ + RmrkTraitsPartPartType: { + _enum: { + FixedPart: 'RmrkTraitsPartFixedPart', + SlotPart: 'RmrkTraitsPartSlotPart' + } + }, + /** + * Lookup309: rmrk_traits::part::FixedPart> + **/ + RmrkTraitsPartFixedPart: { + id: 'u32', + z: 'u32', + src: 'Bytes' + }, + /** + * Lookup310: rmrk_traits::part::SlotPart, sp_core::bounded::bounded_vec::BoundedVec> + **/ + RmrkTraitsPartSlotPart: { + id: 'u32', + equippable: 'RmrkTraitsPartEquippableList', + src: 'Bytes', + z: 'u32' + }, + /** + * Lookup311: rmrk_traits::part::EquippableList> + **/ + RmrkTraitsPartEquippableList: { + _enum: { + All: 'Null', + Empty: 'Null', + Custom: 'Vec' + } + }, + /** + * Lookup313: rmrk_traits::theme::Theme, sp_core::bounded::bounded_vec::BoundedVec>, S>> + **/ + RmrkTraitsTheme: { + name: 'Bytes', + properties: 'Vec', + inherit: 'bool' + }, + /** + * Lookup315: rmrk_traits::theme::ThemeProperty> + **/ + RmrkTraitsThemeThemeProperty: { + key: 'Bytes', + value: 'Bytes' + }, + /** + * Lookup317: pallet_app_promotion::pallet::Call **/ PalletAppPromotionCall: { _enum: { @@ -2382,7 +2710,7 @@ export default { } }, /** - * Lookup289: pallet_foreign_assets::module::Call + * Lookup318: pallet_foreign_assets::module::Call **/ PalletForeignAssetsModuleCall: { _enum: { @@ -2399,7 +2727,7 @@ export default { } }, /** - * Lookup290: pallet_evm::pallet::Call + * Lookup319: pallet_evm::pallet::Call **/ PalletEvmCall: { _enum: { @@ -2442,7 +2770,7 @@ export default { } }, /** - * Lookup294: pallet_ethereum::pallet::Call + * Lookup325: pallet_ethereum::pallet::Call **/ PalletEthereumCall: { _enum: { @@ -2452,7 +2780,7 @@ export default { } }, /** - * Lookup295: ethereum::transaction::TransactionV2 + * Lookup326: ethereum::transaction::TransactionV2 **/ EthereumTransactionTransactionV2: { _enum: { @@ -2462,7 +2790,7 @@ export default { } }, /** - * Lookup296: ethereum::transaction::LegacyTransaction + * Lookup327: ethereum::transaction::LegacyTransaction **/ EthereumTransactionLegacyTransaction: { nonce: 'U256', @@ -2474,7 +2802,7 @@ export default { signature: 'EthereumTransactionTransactionSignature' }, /** - * Lookup297: ethereum::transaction::TransactionAction + * Lookup328: ethereum::transaction::TransactionAction **/ EthereumTransactionTransactionAction: { _enum: { @@ -2483,7 +2811,7 @@ export default { } }, /** - * Lookup298: ethereum::transaction::TransactionSignature + * Lookup329: ethereum::transaction::TransactionSignature **/ EthereumTransactionTransactionSignature: { v: 'u64', @@ -2491,7 +2819,7 @@ export default { s: 'H256' }, /** - * Lookup300: ethereum::transaction::EIP2930Transaction + * Lookup331: ethereum::transaction::EIP2930Transaction **/ EthereumTransactionEip2930Transaction: { chainId: 'u64', @@ -2507,14 +2835,14 @@ export default { s: 'H256' }, /** - * Lookup302: ethereum::transaction::AccessListItem + * Lookup333: ethereum::transaction::AccessListItem **/ EthereumTransactionAccessListItem: { address: 'H160', storageKeys: 'Vec' }, /** - * Lookup303: ethereum::transaction::EIP1559Transaction + * Lookup334: ethereum::transaction::EIP1559Transaction **/ EthereumTransactionEip1559Transaction: { chainId: 'u64', @@ -2531,7 +2859,7 @@ export default { s: 'H256' }, /** - * Lookup304: pallet_evm_migration::pallet::Call + * Lookup335: pallet_evm_migration::pallet::Call **/ PalletEvmMigrationCall: { _enum: { @@ -2555,38 +2883,57 @@ export default { } }, /** - * Lookup308: pallet_maintenance::pallet::Call + * Lookup339: pallet_maintenance::pallet::Call **/ PalletMaintenanceCall: { _enum: ['enable', 'disable'] }, /** - * Lookup309: pallet_sudo::pallet::Error + * Lookup340: pallet_test_utils::pallet::Call + **/ + PalletTestUtilsCall: { + _enum: { + enable: 'Null', + set_test_value: { + value: 'u32', + }, + set_test_value_and_rollback: { + value: 'u32', + }, + inc_test_value: 'Null', + just_take_fee: 'Null', + batch_all: { + calls: 'Vec' + } + } + }, + /** + * Lookup342: pallet_sudo::pallet::Error **/ PalletSudoError: { _enum: ['RequireSudo'] }, /** - * Lookup311: orml_vesting::module::Error + * Lookup344: orml_vesting::module::Error **/ OrmlVestingModuleError: { _enum: ['ZeroVestingPeriod', 'ZeroVestingPeriodCount', 'InsufficientBalanceToLock', 'TooManyVestingSchedules', 'AmountLow', 'MaxVestingSchedulesExceeded'] }, /** - * Lookup312: orml_xtokens::module::Error + * Lookup345: orml_xtokens::module::Error **/ OrmlXtokensModuleError: { _enum: ['AssetHasNoReserve', 'NotCrossChainTransfer', 'InvalidDest', 'NotCrossChainTransferableCurrency', 'UnweighableMessage', 'XcmExecutionFailed', 'CannotReanchor', 'InvalidAncestry', 'InvalidAsset', 'DestinationNotInvertible', 'BadVersion', 'DistinctReserveForAssetAndFee', 'ZeroFee', 'ZeroAmount', 'TooManyAssetsBeingSent', 'AssetIndexNonExistent', 'FeeNotEnough', 'NotSupportedMultiLocation', 'MinXcmFeeNotDefined'] }, /** - * Lookup315: orml_tokens::BalanceLock + * Lookup348: orml_tokens::BalanceLock **/ OrmlTokensBalanceLock: { id: '[u8;8]', amount: 'u128' }, /** - * Lookup317: orml_tokens::AccountData + * Lookup350: orml_tokens::AccountData **/ OrmlTokensAccountData: { free: 'u128', @@ -2594,20 +2941,20 @@ export default { frozen: 'u128' }, /** - * Lookup319: orml_tokens::ReserveData + * Lookup352: orml_tokens::ReserveData **/ OrmlTokensReserveData: { id: 'Null', amount: 'u128' }, /** - * Lookup321: orml_tokens::module::Error + * Lookup354: orml_tokens::module::Error **/ OrmlTokensModuleError: { _enum: ['BalanceTooLow', 'AmountIntoBalanceFailed', 'LiquidityRestrictions', 'MaxLocksExceeded', 'KeepAlive', 'ExistentialDeposit', 'DeadAccount', 'TooManyReserves'] }, /** - * Lookup323: cumulus_pallet_xcmp_queue::InboundChannelDetails + * Lookup356: cumulus_pallet_xcmp_queue::InboundChannelDetails **/ CumulusPalletXcmpQueueInboundChannelDetails: { sender: 'u32', @@ -2615,19 +2962,19 @@ export default { messageMetadata: 'Vec<(u32,PolkadotParachainPrimitivesXcmpMessageFormat)>' }, /** - * Lookup324: cumulus_pallet_xcmp_queue::InboundState + * Lookup357: cumulus_pallet_xcmp_queue::InboundState **/ CumulusPalletXcmpQueueInboundState: { _enum: ['Ok', 'Suspended'] }, /** - * Lookup327: polkadot_parachain::primitives::XcmpMessageFormat + * Lookup360: polkadot_parachain::primitives::XcmpMessageFormat **/ PolkadotParachainPrimitivesXcmpMessageFormat: { _enum: ['ConcatenatedVersionedXcm', 'ConcatenatedEncodedBlob', 'Signals'] }, /** - * Lookup330: cumulus_pallet_xcmp_queue::OutboundChannelDetails + * Lookup363: cumulus_pallet_xcmp_queue::OutboundChannelDetails **/ CumulusPalletXcmpQueueOutboundChannelDetails: { recipient: 'u32', @@ -2637,46 +2984,46 @@ export default { lastIndex: 'u16' }, /** - * Lookup331: cumulus_pallet_xcmp_queue::OutboundState + * Lookup364: cumulus_pallet_xcmp_queue::OutboundState **/ CumulusPalletXcmpQueueOutboundState: { _enum: ['Ok', 'Suspended'] }, /** - * Lookup333: cumulus_pallet_xcmp_queue::QueueConfigData + * Lookup366: cumulus_pallet_xcmp_queue::QueueConfigData **/ CumulusPalletXcmpQueueQueueConfigData: { suspendThreshold: 'u32', dropThreshold: 'u32', resumeThreshold: 'u32', - thresholdWeight: 'Weight', - weightRestrictDecay: 'Weight', - xcmpMaxIndividualWeight: 'Weight' + thresholdWeight: 'SpWeightsWeightV2Weight', + weightRestrictDecay: 'SpWeightsWeightV2Weight', + xcmpMaxIndividualWeight: 'SpWeightsWeightV2Weight' }, /** - * Lookup335: cumulus_pallet_xcmp_queue::pallet::Error + * Lookup368: cumulus_pallet_xcmp_queue::pallet::Error **/ CumulusPalletXcmpQueueError: { _enum: ['FailedToSend', 'BadXcmOrigin', 'BadXcm', 'BadOverweightIndex', 'WeightOverLimit'] }, /** - * Lookup336: pallet_xcm::pallet::Error + * Lookup369: pallet_xcm::pallet::Error **/ PalletXcmError: { _enum: ['Unreachable', 'SendFailure', 'Filtered', 'UnweighableMessage', 'DestinationNotInvertible', 'Empty', 'CannotReanchor', 'TooManyAssets', 'InvalidOrigin', 'BadVersion', 'BadLocation', 'NoSubscription', 'AlreadySubscribed'] }, /** - * Lookup337: cumulus_pallet_xcm::pallet::Error + * Lookup370: cumulus_pallet_xcm::pallet::Error **/ CumulusPalletXcmError: 'Null', /** - * Lookup338: cumulus_pallet_dmp_queue::ConfigData + * Lookup371: cumulus_pallet_dmp_queue::ConfigData **/ CumulusPalletDmpQueueConfigData: { - maxIndividual: 'Weight' + maxIndividual: 'SpWeightsWeightV2Weight' }, /** - * Lookup339: cumulus_pallet_dmp_queue::PageIndexData + * Lookup372: cumulus_pallet_dmp_queue::PageIndexData **/ CumulusPalletDmpQueuePageIndexData: { beginUsed: 'u32', @@ -2684,25 +3031,25 @@ export default { overweightCount: 'u64' }, /** - * Lookup342: cumulus_pallet_dmp_queue::pallet::Error + * Lookup375: cumulus_pallet_dmp_queue::pallet::Error **/ CumulusPalletDmpQueueError: { _enum: ['Unknown', 'OverLimit'] }, /** - * Lookup346: pallet_unique::Error + * Lookup379: pallet_unique::Error **/ PalletUniqueError: { - _enum: ['CollectionDecimalPointLimitExceeded', 'ConfirmUnsetSponsorFail', 'EmptyArgument', 'RepartitionCalledOnNonRefungibleCollection'] + _enum: ['CollectionDecimalPointLimitExceeded', 'EmptyArgument', 'RepartitionCalledOnNonRefungibleCollection'] }, /** - * Lookup347: pallet_configuration::pallet::Error + * Lookup380: pallet_configuration::pallet::Error **/ PalletConfigurationError: { _enum: ['InconsistentConfiguration'] }, /** - * Lookup348: up_data_structs::Collection + * Lookup381: up_data_structs::Collection **/ UpDataStructsCollection: { owner: 'AccountId32', @@ -2716,7 +3063,7 @@ export default { flags: '[u8;1]' }, /** - * Lookup349: up_data_structs::SponsorshipState + * Lookup382: up_data_structs::SponsorshipState **/ UpDataStructsSponsorshipStateAccountId32: { _enum: { @@ -2726,7 +3073,7 @@ export default { } }, /** - * Lookup351: up_data_structs::Properties + * Lookup384: up_data_structs::Properties **/ UpDataStructsProperties: { map: 'UpDataStructsPropertiesMapBoundedVec', @@ -2734,15 +3081,15 @@ export default { spaceLimit: 'u32' }, /** - * Lookup352: up_data_structs::PropertiesMap> + * Lookup385: up_data_structs::PropertiesMap> **/ UpDataStructsPropertiesMapBoundedVec: 'BTreeMap', /** - * Lookup357: up_data_structs::PropertiesMap + * Lookup390: up_data_structs::PropertiesMap **/ UpDataStructsPropertiesMapPropertyPermission: 'BTreeMap', /** - * Lookup364: up_data_structs::CollectionStats + * Lookup397: up_data_structs::CollectionStats **/ UpDataStructsCollectionStats: { created: 'u32', @@ -2750,18 +3097,18 @@ export default { alive: 'u32' }, /** - * Lookup365: up_data_structs::TokenChild + * Lookup398: up_data_structs::TokenChild **/ UpDataStructsTokenChild: { token: 'u32', collection: 'u32' }, /** - * Lookup366: PhantomType::up_data_structs + * Lookup399: PhantomType::up_data_structs **/ - PhantomTypeUpDataStructs: '[(UpDataStructsTokenData,UpDataStructsRpcCollection,RmrkTraitsCollectionCollectionInfo,RmrkTraitsNftNftInfo,RmrkTraitsResourceResourceInfo,RmrkTraitsPropertyPropertyInfo,RmrkTraitsBaseBaseInfo,RmrkTraitsPartPartType,RmrkTraitsTheme,RmrkTraitsNftNftChild);0]', + PhantomTypeUpDataStructs: '[(UpDataStructsTokenData,UpDataStructsRpcCollection,RmrkTraitsCollectionCollectionInfo,RmrkTraitsNftNftInfo,RmrkTraitsResourceResourceInfo,RmrkTraitsPropertyPropertyInfo,RmrkTraitsBaseBaseInfo,RmrkTraitsPartPartType,RmrkTraitsTheme,RmrkTraitsNftNftChild,UpPovEstimateRpcPovInfo);0]', /** - * Lookup368: up_data_structs::TokenData> + * Lookup401: up_data_structs::TokenData> **/ UpDataStructsTokenData: { properties: 'Vec', @@ -2769,7 +3116,7 @@ export default { pieces: 'u128' }, /** - * Lookup370: up_data_structs::RpcCollection + * Lookup403: up_data_structs::RpcCollection **/ UpDataStructsRpcCollection: { owner: 'AccountId32', @@ -2786,14 +3133,14 @@ export default { flags: 'UpDataStructsRpcCollectionFlags' }, /** - * Lookup371: up_data_structs::RpcCollectionFlags + * Lookup404: up_data_structs::RpcCollectionFlags **/ UpDataStructsRpcCollectionFlags: { foreign: 'bool', erc721metadata: 'bool' }, /** - * Lookup372: rmrk_traits::collection::CollectionInfo, sp_core::bounded::bounded_vec::BoundedVec, sp_core::crypto::AccountId32> + * Lookup405: rmrk_traits::collection::CollectionInfo, sp_core::bounded::bounded_vec::BoundedVec, sp_core::crypto::AccountId32> **/ RmrkTraitsCollectionCollectionInfo: { issuer: 'AccountId32', @@ -2803,7 +3150,7 @@ export default { nftsCount: 'u32' }, /** - * Lookup375: rmrk_traits::nft::NftInfo> + * Lookup406: rmrk_traits::nft::NftInfo> **/ RmrkTraitsNftNftInfo: { owner: 'RmrkTraitsNftAccountIdOrCollectionNftTuple', @@ -2813,23 +3160,14 @@ export default { pending: 'bool' }, /** - * Lookup376: rmrk_traits::nft::AccountIdOrCollectionNftTuple - **/ - RmrkTraitsNftAccountIdOrCollectionNftTuple: { - _enum: { - AccountId: 'AccountId32', - CollectionAndNftTuple: '(u32,u32)' - } - }, - /** - * Lookup378: rmrk_traits::nft::RoyaltyInfo + * Lookup408: rmrk_traits::nft::RoyaltyInfo **/ RmrkTraitsNftRoyaltyInfo: { recipient: 'AccountId32', amount: 'Permill' }, /** - * Lookup379: rmrk_traits::resource::ResourceInfo, sp_core::bounded::bounded_vec::BoundedVec> + * Lookup409: rmrk_traits::resource::ResourceInfo, sp_core::bounded::bounded_vec::BoundedVec> **/ RmrkTraitsResourceResourceInfo: { id: 'u32', @@ -2838,55 +3176,14 @@ export default { pendingRemoval: 'bool' }, /** - * Lookup381: rmrk_traits::resource::ResourceTypes, sp_core::bounded::bounded_vec::BoundedVec> - **/ - RmrkTraitsResourceResourceTypes: { - _enum: { - Basic: 'RmrkTraitsResourceBasicResource', - Composable: 'RmrkTraitsResourceComposableResource', - Slot: 'RmrkTraitsResourceSlotResource' - } - }, - /** - * Lookup382: rmrk_traits::resource::BasicResource> - **/ - RmrkTraitsResourceBasicResource: { - src: 'Option', - metadata: 'Option', - license: 'Option', - thumb: 'Option' - }, - /** - * Lookup384: rmrk_traits::resource::ComposableResource, sp_core::bounded::bounded_vec::BoundedVec> - **/ - RmrkTraitsResourceComposableResource: { - parts: 'Vec', - base: 'u32', - src: 'Option', - metadata: 'Option', - license: 'Option', - thumb: 'Option' - }, - /** - * Lookup385: rmrk_traits::resource::SlotResource> - **/ - RmrkTraitsResourceSlotResource: { - base: 'u32', - src: 'Option', - metadata: 'Option', - slot: 'u32', - license: 'Option', - thumb: 'Option' - }, - /** - * Lookup386: rmrk_traits::property::PropertyInfo, sp_core::bounded::bounded_vec::BoundedVec> + * Lookup410: rmrk_traits::property::PropertyInfo, sp_core::bounded::bounded_vec::BoundedVec> **/ RmrkTraitsPropertyPropertyInfo: { key: 'Bytes', value: 'Bytes' }, /** - * Lookup389: rmrk_traits::base::BaseInfo> + * Lookup411: rmrk_traits::base::BaseInfo> **/ RmrkTraitsBaseBaseInfo: { issuer: 'AccountId32', @@ -2894,131 +3191,140 @@ export default { symbol: 'Bytes' }, /** - * Lookup390: rmrk_traits::part::PartType, sp_core::bounded::bounded_vec::BoundedVec> + * Lookup412: rmrk_traits::nft::NftChild **/ - RmrkTraitsPartPartType: { - _enum: { - FixedPart: 'RmrkTraitsPartFixedPart', - SlotPart: 'RmrkTraitsPartSlotPart' - } + RmrkTraitsNftNftChild: { + collectionId: 'u32', + nftId: 'u32' }, /** - * Lookup392: rmrk_traits::part::FixedPart> + * Lookup413: up_pov_estimate_rpc::PovInfo **/ - RmrkTraitsPartFixedPart: { - id: 'u32', - z: 'u32', - src: 'Bytes' + UpPovEstimateRpcPovInfo: { + proofSize: 'u64', + compactProofSize: 'u64', + compressedProofSize: 'u64', + results: 'Vec, SpRuntimeTransactionValidityTransactionValidityError>>', + keyValues: 'Vec' }, /** - * Lookup393: rmrk_traits::part::SlotPart, sp_core::bounded::bounded_vec::BoundedVec> + * Lookup416: sp_runtime::transaction_validity::TransactionValidityError **/ - RmrkTraitsPartSlotPart: { - id: 'u32', - equippable: 'RmrkTraitsPartEquippableList', - src: 'Bytes', - z: 'u32' + SpRuntimeTransactionValidityTransactionValidityError: { + _enum: { + Invalid: 'SpRuntimeTransactionValidityInvalidTransaction', + Unknown: 'SpRuntimeTransactionValidityUnknownTransaction' + } }, /** - * Lookup394: rmrk_traits::part::EquippableList> + * Lookup417: sp_runtime::transaction_validity::InvalidTransaction **/ - RmrkTraitsPartEquippableList: { + SpRuntimeTransactionValidityInvalidTransaction: { _enum: { - All: 'Null', - Empty: 'Null', - Custom: 'Vec' + Call: 'Null', + Payment: 'Null', + Future: 'Null', + Stale: 'Null', + BadProof: 'Null', + AncientBirthBlock: 'Null', + ExhaustsResources: 'Null', + Custom: 'u8', + BadMandatory: 'Null', + MandatoryValidation: 'Null', + BadSigner: 'Null' } }, /** - * Lookup395: rmrk_traits::theme::Theme, sp_core::bounded::bounded_vec::BoundedVec>, S>> + * Lookup418: sp_runtime::transaction_validity::UnknownTransaction **/ - RmrkTraitsTheme: { - name: 'Bytes', - properties: 'Vec', - inherit: 'bool' + SpRuntimeTransactionValidityUnknownTransaction: { + _enum: { + CannotLookup: 'Null', + NoUnsignedValidator: 'Null', + Custom: 'u8' + } }, /** - * Lookup397: rmrk_traits::theme::ThemeProperty> + * Lookup420: up_pov_estimate_rpc::TrieKeyValue **/ - RmrkTraitsThemeThemeProperty: { + UpPovEstimateRpcTrieKeyValue: { key: 'Bytes', value: 'Bytes' }, /** - * Lookup399: rmrk_traits::nft::NftChild - **/ - RmrkTraitsNftNftChild: { - collectionId: 'u32', - nftId: 'u32' - }, - /** - * Lookup401: pallet_common::pallet::Error + * Lookup422: pallet_common::pallet::Error **/ PalletCommonError: { - _enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'CantDestroyNotEmptyCollection', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'UserIsNotAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached', 'PropertyKeyIsTooLong', 'InvalidCharacterInPropertyKey', 'EmptyPropertyKey', 'CollectionIsExternal', 'CollectionIsInternal'] + _enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'CantDestroyNotEmptyCollection', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'UserIsNotAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached', 'PropertyKeyIsTooLong', 'InvalidCharacterInPropertyKey', 'EmptyPropertyKey', 'CollectionIsExternal', 'CollectionIsInternal', 'ConfirmSponsorshipFail', 'UserIsNotCollectionAdmin'] }, /** - * Lookup403: pallet_fungible::pallet::Error + * Lookup424: pallet_fungible::pallet::Error **/ PalletFungibleError: { - _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed', 'FungibleTokensAreAlwaysValid'] - }, - /** - * Lookup404: pallet_refungible::ItemData - **/ - PalletRefungibleItemData: { - constData: 'Bytes' + _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed', 'SettingAllowanceForAllNotAllowed', 'FungibleTokensAreAlwaysValid'] }, /** - * Lookup409: pallet_refungible::pallet::Error + * Lookup428: pallet_refungible::pallet::Error **/ PalletRefungibleError: { _enum: ['NotRefungibleDataUsedToMintFungibleCollectionToken', 'WrongRefungiblePieces', 'RepartitionWhileNotOwningAllPieces', 'RefungibleDisallowsNesting', 'SettingPropertiesNotAllowed'] }, /** - * Lookup410: pallet_nonfungible::ItemData> + * Lookup429: pallet_nonfungible::ItemData> **/ PalletNonfungibleItemData: { owner: 'PalletEvmAccountBasicCrossAccountIdRepr' }, /** - * Lookup412: up_data_structs::PropertyScope + * Lookup431: up_data_structs::PropertyScope **/ UpDataStructsPropertyScope: { _enum: ['None', 'Rmrk'] }, /** - * Lookup414: pallet_nonfungible::pallet::Error + * Lookup434: pallet_nonfungible::pallet::Error **/ PalletNonfungibleError: { _enum: ['NotNonfungibleDataUsedToMintFungibleCollectionToken', 'NonfungibleItemsHaveNoAmount', 'CantBurnNftWithChildren'] }, /** - * Lookup415: pallet_structure::pallet::Error + * Lookup435: pallet_structure::pallet::Error **/ PalletStructureError: { _enum: ['OuroborosDetected', 'DepthLimit', 'BreadthLimit', 'TokenNotFound'] }, /** - * Lookup421: pallet_app_promotion::pallet::Error + * Lookup436: pallet_rmrk_core::pallet::Error + **/ + PalletRmrkCoreError: { + _enum: ['CorruptedCollectionType', 'RmrkPropertyKeyIsTooLong', 'RmrkPropertyValueIsTooLong', 'RmrkPropertyIsNotFound', 'UnableToDecodeRmrkData', 'CollectionNotEmpty', 'NoAvailableCollectionId', 'NoAvailableNftId', 'CollectionUnknown', 'NoPermission', 'NonTransferable', 'CollectionFullOrLocked', 'ResourceDoesntExist', 'CannotSendToDescendentOrSelf', 'CannotAcceptNonOwnedNft', 'CannotRejectNonOwnedNft', 'CannotRejectNonPendingNft', 'ResourceNotPending', 'NoAvailableResourceId'] + }, + /** + * Lookup438: pallet_rmrk_equip::pallet::Error + **/ + PalletRmrkEquipError: { + _enum: ['PermissionError', 'NoAvailableBaseId', 'NoAvailablePartId', 'BaseDoesntExist', 'NeedsDefaultThemeFirst', 'PartDoesntExist', 'NoEquippableOnFixedPart'] + }, + /** + * Lookup444: pallet_app_promotion::pallet::Error **/ PalletAppPromotionError: { _enum: ['AdminNotSet', 'NoPermission', 'NotSufficientFunds', 'PendingForBlockOverflow', 'SponsorNotSet', 'IncorrectLockedBalanceOperation'] }, /** - * Lookup422: pallet_foreign_assets::module::Error + * Lookup445: pallet_foreign_assets::module::Error **/ PalletForeignAssetsModuleError: { _enum: ['BadLocation', 'MultiLocationExisted', 'AssetIdNotExists', 'AssetIdExisted'] }, /** - * Lookup424: pallet_evm::pallet::Error + * Lookup447: pallet_evm::pallet::Error **/ PalletEvmError: { - _enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce'] + _enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce', 'GasLimitTooLow', 'GasLimitTooHigh', 'Undefined', 'Reentrancy', 'TransactionMustComeFromEOA'] }, /** - * Lookup427: fp_rpc::TransactionStatus + * Lookup450: fp_rpc::TransactionStatus **/ FpRpcTransactionStatus: { transactionHash: 'H256', @@ -3030,11 +3336,11 @@ export default { logsBloom: 'EthbloomBloom' }, /** - * Lookup429: ethbloom::Bloom + * Lookup452: ethbloom::Bloom **/ EthbloomBloom: '[u8;256]', /** - * Lookup431: ethereum::receipt::ReceiptV3 + * Lookup454: ethereum::receipt::ReceiptV3 **/ EthereumReceiptReceiptV3: { _enum: { @@ -3044,7 +3350,7 @@ export default { } }, /** - * Lookup432: ethereum::receipt::EIP658ReceiptData + * Lookup455: ethereum::receipt::EIP658ReceiptData **/ EthereumReceiptEip658ReceiptData: { statusCode: 'u8', @@ -3053,7 +3359,7 @@ export default { logs: 'Vec' }, /** - * Lookup433: ethereum::block::Block + * Lookup456: ethereum::block::Block **/ EthereumBlock: { header: 'EthereumHeader', @@ -3061,7 +3367,7 @@ export default { ommers: 'Vec' }, /** - * Lookup434: ethereum::header::Header + * Lookup457: ethereum::header::Header **/ EthereumHeader: { parentHash: 'H256', @@ -3081,23 +3387,23 @@ export default { nonce: 'EthereumTypesHashH64' }, /** - * Lookup435: ethereum_types::hash::H64 + * Lookup458: ethereum_types::hash::H64 **/ EthereumTypesHashH64: '[u8;8]', /** - * Lookup440: pallet_ethereum::pallet::Error + * Lookup463: pallet_ethereum::pallet::Error **/ PalletEthereumError: { _enum: ['InvalidSignature', 'PreLogExists'] }, /** - * Lookup441: pallet_evm_coder_substrate::pallet::Error + * Lookup464: pallet_evm_coder_substrate::pallet::Error **/ PalletEvmCoderSubstrateError: { _enum: ['OutOfGas', 'OutOfFund'] }, /** - * Lookup442: up_data_structs::SponsorshipState> + * Lookup465: up_data_structs::SponsorshipState> **/ UpDataStructsSponsorshipStateBasicCrossAccountIdRepr: { _enum: { @@ -3107,29 +3413,35 @@ export default { } }, /** - * Lookup443: pallet_evm_contract_helpers::SponsoringModeT + * Lookup466: pallet_evm_contract_helpers::SponsoringModeT **/ PalletEvmContractHelpersSponsoringModeT: { _enum: ['Disabled', 'Allowlisted', 'Generous'] }, /** - * Lookup449: pallet_evm_contract_helpers::pallet::Error + * Lookup472: pallet_evm_contract_helpers::pallet::Error **/ PalletEvmContractHelpersError: { _enum: ['NoPermission', 'NoPendingSponsor', 'TooManyMethodsHaveSponsoredLimit'] }, /** - * Lookup450: pallet_evm_migration::pallet::Error + * Lookup473: pallet_evm_migration::pallet::Error **/ PalletEvmMigrationError: { _enum: ['AccountNotEmpty', 'AccountIsNotMigrating', 'BadEvent'] }, /** - * Lookup451: pallet_maintenance::pallet::Error + * Lookup474: pallet_maintenance::pallet::Error **/ PalletMaintenanceError: 'Null', /** - * Lookup453: sp_runtime::MultiSignature + * Lookup475: pallet_test_utils::pallet::Error + **/ + PalletTestUtilsError: { + _enum: ['TestPalletDisabled', 'TriggerRollback'] + }, + /** + * Lookup477: sp_runtime::MultiSignature **/ SpRuntimeMultiSignature: { _enum: { @@ -3139,51 +3451,51 @@ export default { } }, /** - * Lookup454: sp_core::ed25519::Signature + * Lookup478: sp_core::ed25519::Signature **/ SpCoreEd25519Signature: '[u8;64]', /** - * Lookup456: sp_core::sr25519::Signature + * Lookup480: sp_core::sr25519::Signature **/ SpCoreSr25519Signature: '[u8;64]', /** - * Lookup457: sp_core::ecdsa::Signature + * Lookup481: sp_core::ecdsa::Signature **/ SpCoreEcdsaSignature: '[u8;65]', /** - * Lookup460: frame_system::extensions::check_spec_version::CheckSpecVersion + * Lookup484: frame_system::extensions::check_spec_version::CheckSpecVersion **/ FrameSystemExtensionsCheckSpecVersion: 'Null', /** - * Lookup461: frame_system::extensions::check_tx_version::CheckTxVersion + * Lookup485: frame_system::extensions::check_tx_version::CheckTxVersion **/ FrameSystemExtensionsCheckTxVersion: 'Null', /** - * Lookup462: frame_system::extensions::check_genesis::CheckGenesis + * Lookup486: frame_system::extensions::check_genesis::CheckGenesis **/ FrameSystemExtensionsCheckGenesis: 'Null', /** - * Lookup465: frame_system::extensions::check_nonce::CheckNonce + * Lookup489: frame_system::extensions::check_nonce::CheckNonce **/ FrameSystemExtensionsCheckNonce: 'Compact', /** - * Lookup466: frame_system::extensions::check_weight::CheckWeight + * Lookup490: frame_system::extensions::check_weight::CheckWeight **/ FrameSystemExtensionsCheckWeight: 'Null', /** - * Lookup467: opal_runtime::runtime_common::maintenance::CheckMaintenance + * Lookup491: opal_runtime::runtime_common::maintenance::CheckMaintenance **/ OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance: 'Null', /** - * Lookup468: pallet_template_transaction_payment::ChargeTransactionPayment + * Lookup492: pallet_template_transaction_payment::ChargeTransactionPayment **/ PalletTemplateTransactionPaymentChargeTransactionPayment: 'Compact', /** - * Lookup469: opal_runtime::Runtime + * Lookup493: opal_runtime::Runtime **/ OpalRuntimeRuntime: 'Null', /** - * Lookup470: pallet_ethereum::FakeTransactionFinalizer + * Lookup494: pallet_ethereum::FakeTransactionFinalizer **/ PalletEthereumFakeTransactionFinalizer: 'Null' }; diff --git a/tests/src/interfaces/povinfo/definitions.ts b/tests/src/interfaces/povinfo/definitions.ts new file mode 100644 index 0000000000..ccc58a44da --- /dev/null +++ b/tests/src/interfaces/povinfo/definitions.ts @@ -0,0 +1,40 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +type RpcParam = { + name: string; + type: string; + isOptional?: true; +}; + +const atParam = {name: 'at', type: 'Hash', isOptional: true}; + +const fun = (description: string, params: RpcParam[], type: string) => ({ + description, + params: [...params, atParam], + type, +}); + +export default { + types: {}, + rpc: { + estimateExtrinsicPoV: fun( + 'Estimate PoV size of encoded signed extrinsics', + [{name: 'encodedXt', type: 'Vec'}], + 'UpPovEstimateRpcPovInfo', + ), + }, +}; diff --git a/tests/src/interfaces/povinfo/index.ts b/tests/src/interfaces/povinfo/index.ts new file mode 100644 index 0000000000..2d307291c3 --- /dev/null +++ b/tests/src/interfaces/povinfo/index.ts @@ -0,0 +1,4 @@ +// Auto-generated via `yarn polkadot-types-from-defs`, do not edit +/* eslint-disable */ + +export * from './types'; diff --git a/tests/src/interfaces/povinfo/types.ts b/tests/src/interfaces/povinfo/types.ts new file mode 100644 index 0000000000..5788d92fa7 --- /dev/null +++ b/tests/src/interfaces/povinfo/types.ts @@ -0,0 +1,4 @@ +// Auto-generated via `yarn polkadot-types-from-defs`, do not edit +/* eslint-disable */ + +export type PHANTOM_POVINFO = 'povinfo'; diff --git a/tests/src/interfaces/registry.ts b/tests/src/interfaces/registry.ts index 340a018f48..06f076fcb0 100644 --- a/tests/src/interfaces/registry.ts +++ b/tests/src/interfaces/registry.ts @@ -5,7 +5,7 @@ // this is required to allow for ambient/previous definitions import '@polkadot/types/types/registry'; -import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationAppPromotionConfiguration, PalletConfigurationCall, PalletConfigurationError, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup'; +import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationAppPromotionConfiguration, PalletConfigurationCall, PalletConfigurationError, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionValidityInvalidTransaction, SpRuntimeTransactionValidityTransactionValidityError, SpRuntimeTransactionValidityUnknownTransaction, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, UpPovEstimateRpcPovInfo, UpPovEstimateRpcTrieKeyValue, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup'; declare module '@polkadot/types/types/registry' { interface InterfaceTypes { @@ -97,7 +97,6 @@ declare module '@polkadot/types/types/registry' { PalletBalancesError: PalletBalancesError; PalletBalancesEvent: PalletBalancesEvent; PalletBalancesReasons: PalletBalancesReasons; - PalletBalancesReleases: PalletBalancesReleases; PalletBalancesReserveData: PalletBalancesReserveData; PalletCommonError: PalletCommonError; PalletCommonEvent: PalletCommonEvent; @@ -133,7 +132,12 @@ declare module '@polkadot/types/types/registry' { PalletNonfungibleError: PalletNonfungibleError; PalletNonfungibleItemData: PalletNonfungibleItemData; PalletRefungibleError: PalletRefungibleError; - PalletRefungibleItemData: PalletRefungibleItemData; + PalletRmrkCoreCall: PalletRmrkCoreCall; + PalletRmrkCoreError: PalletRmrkCoreError; + PalletRmrkCoreEvent: PalletRmrkCoreEvent; + PalletRmrkEquipCall: PalletRmrkEquipCall; + PalletRmrkEquipError: PalletRmrkEquipError; + PalletRmrkEquipEvent: PalletRmrkEquipEvent; PalletStructureCall: PalletStructureCall; PalletStructureError: PalletStructureError; PalletStructureEvent: PalletStructureEvent; @@ -142,6 +146,9 @@ declare module '@polkadot/types/types/registry' { PalletSudoEvent: PalletSudoEvent; PalletTemplateTransactionPaymentCall: PalletTemplateTransactionPaymentCall; PalletTemplateTransactionPaymentChargeTransactionPayment: PalletTemplateTransactionPaymentChargeTransactionPayment; + PalletTestUtilsCall: PalletTestUtilsCall; + PalletTestUtilsError: PalletTestUtilsError; + PalletTestUtilsEvent: PalletTestUtilsEvent; PalletTimestampCall: PalletTimestampCall; PalletTransactionPaymentEvent: PalletTransactionPaymentEvent; PalletTransactionPaymentReleases: PalletTransactionPaymentReleases; @@ -151,7 +158,6 @@ declare module '@polkadot/types/types/registry' { PalletTreasuryProposal: PalletTreasuryProposal; PalletUniqueCall: PalletUniqueCall; PalletUniqueError: PalletUniqueError; - PalletUniqueRawEvent: PalletUniqueRawEvent; PalletXcmCall: PalletXcmCall; PalletXcmError: PalletXcmError; PalletXcmEvent: PalletXcmEvent; @@ -192,10 +198,14 @@ declare module '@polkadot/types/types/registry' { SpRuntimeModuleError: SpRuntimeModuleError; SpRuntimeMultiSignature: SpRuntimeMultiSignature; SpRuntimeTokenError: SpRuntimeTokenError; + SpRuntimeTransactionValidityInvalidTransaction: SpRuntimeTransactionValidityInvalidTransaction; + SpRuntimeTransactionValidityTransactionValidityError: SpRuntimeTransactionValidityTransactionValidityError; + SpRuntimeTransactionValidityUnknownTransaction: SpRuntimeTransactionValidityUnknownTransaction; SpRuntimeTransactionalError: SpRuntimeTransactionalError; SpTrieStorageProof: SpTrieStorageProof; SpVersionRuntimeVersion: SpVersionRuntimeVersion; SpWeightsRuntimeDbWeight: SpWeightsRuntimeDbWeight; + SpWeightsWeightV2Weight: SpWeightsWeightV2Weight; UpDataStructsAccessMode: UpDataStructsAccessMode; UpDataStructsCollection: UpDataStructsCollection; UpDataStructsCollectionLimits: UpDataStructsCollectionLimits; @@ -227,6 +237,8 @@ declare module '@polkadot/types/types/registry' { UpDataStructsSponsorshipStateBasicCrossAccountIdRepr: UpDataStructsSponsorshipStateBasicCrossAccountIdRepr; UpDataStructsTokenChild: UpDataStructsTokenChild; UpDataStructsTokenData: UpDataStructsTokenData; + UpPovEstimateRpcPovInfo: UpPovEstimateRpcPovInfo; + UpPovEstimateRpcTrieKeyValue: UpPovEstimateRpcTrieKeyValue; XcmDoubleEncoded: XcmDoubleEncoded; XcmV0Junction: XcmV0Junction; XcmV0JunctionBodyId: XcmV0JunctionBodyId; diff --git a/tests/src/interfaces/types-lookup.ts b/tests/src/interfaces/types-lookup.ts index cfd0882b60..f7dfca22ba 100644 --- a/tests/src/interfaces/types-lookup.ts +++ b/tests/src/interfaces/types-lookup.ts @@ -7,7 +7,7 @@ import '@polkadot/types/lookup'; import type { BTreeMap, BTreeSet, Bytes, Compact, Enum, Null, Option, Result, Struct, Text, U256, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec'; import type { ITuple } from '@polkadot/types-codec/types'; -import type { AccountId32, Call, H160, H256, MultiAddress, Perbill, Permill, Weight } from '@polkadot/types/interfaces/runtime'; +import type { AccountId32, Call, H160, H256, MultiAddress, Perbill, Permill } from '@polkadot/types/interfaces/runtime'; import type { Event } from '@polkadot/types/interfaces/system'; declare module '@polkadot/types/lookup' { @@ -30,17 +30,23 @@ declare module '@polkadot/types/lookup' { /** @name FrameSupportDispatchPerDispatchClassWeight (7) */ interface FrameSupportDispatchPerDispatchClassWeight extends Struct { - readonly normal: Weight; - readonly operational: Weight; - readonly mandatory: Weight; + readonly normal: SpWeightsWeightV2Weight; + readonly operational: SpWeightsWeightV2Weight; + readonly mandatory: SpWeightsWeightV2Weight; } - /** @name SpRuntimeDigest (12) */ + /** @name SpWeightsWeightV2Weight (8) */ + interface SpWeightsWeightV2Weight extends Struct { + readonly refTime: Compact; + readonly proofSize: Compact; + } + + /** @name SpRuntimeDigest (13) */ interface SpRuntimeDigest extends Struct { readonly logs: Vec; } - /** @name SpRuntimeDigestDigestItem (14) */ + /** @name SpRuntimeDigestDigestItem (15) */ interface SpRuntimeDigestDigestItem extends Enum { readonly isOther: boolean; readonly asOther: Bytes; @@ -54,14 +60,14 @@ declare module '@polkadot/types/lookup' { readonly type: 'Other' | 'Consensus' | 'Seal' | 'PreRuntime' | 'RuntimeEnvironmentUpdated'; } - /** @name FrameSystemEventRecord (17) */ + /** @name FrameSystemEventRecord (18) */ interface FrameSystemEventRecord extends Struct { readonly phase: FrameSystemPhase; readonly event: Event; readonly topics: Vec; } - /** @name FrameSystemEvent (19) */ + /** @name FrameSystemEvent (20) */ interface FrameSystemEvent extends Enum { readonly isExtrinsicSuccess: boolean; readonly asExtrinsicSuccess: { @@ -89,14 +95,14 @@ declare module '@polkadot/types/lookup' { readonly type: 'ExtrinsicSuccess' | 'ExtrinsicFailed' | 'CodeUpdated' | 'NewAccount' | 'KilledAccount' | 'Remarked'; } - /** @name FrameSupportDispatchDispatchInfo (20) */ + /** @name FrameSupportDispatchDispatchInfo (21) */ interface FrameSupportDispatchDispatchInfo extends Struct { - readonly weight: Weight; + readonly weight: SpWeightsWeightV2Weight; readonly class: FrameSupportDispatchDispatchClass; readonly paysFee: FrameSupportDispatchPays; } - /** @name FrameSupportDispatchDispatchClass (21) */ + /** @name FrameSupportDispatchDispatchClass (22) */ interface FrameSupportDispatchDispatchClass extends Enum { readonly isNormal: boolean; readonly isOperational: boolean; @@ -104,14 +110,14 @@ declare module '@polkadot/types/lookup' { readonly type: 'Normal' | 'Operational' | 'Mandatory'; } - /** @name FrameSupportDispatchPays (22) */ + /** @name FrameSupportDispatchPays (23) */ interface FrameSupportDispatchPays extends Enum { readonly isYes: boolean; readonly isNo: boolean; readonly type: 'Yes' | 'No'; } - /** @name SpRuntimeDispatchError (23) */ + /** @name SpRuntimeDispatchError (24) */ interface SpRuntimeDispatchError extends Enum { readonly isOther: boolean; readonly isCannotLookup: boolean; @@ -127,16 +133,19 @@ declare module '@polkadot/types/lookup' { readonly asArithmetic: SpRuntimeArithmeticError; readonly isTransactional: boolean; readonly asTransactional: SpRuntimeTransactionalError; - readonly type: 'Other' | 'CannotLookup' | 'BadOrigin' | 'Module' | 'ConsumerRemaining' | 'NoProviders' | 'TooManyConsumers' | 'Token' | 'Arithmetic' | 'Transactional'; + readonly isExhausted: boolean; + readonly isCorruption: boolean; + readonly isUnavailable: boolean; + readonly type: 'Other' | 'CannotLookup' | 'BadOrigin' | 'Module' | 'ConsumerRemaining' | 'NoProviders' | 'TooManyConsumers' | 'Token' | 'Arithmetic' | 'Transactional' | 'Exhausted' | 'Corruption' | 'Unavailable'; } - /** @name SpRuntimeModuleError (24) */ + /** @name SpRuntimeModuleError (25) */ interface SpRuntimeModuleError extends Struct { readonly index: u8; readonly error: U8aFixed; } - /** @name SpRuntimeTokenError (25) */ + /** @name SpRuntimeTokenError (26) */ interface SpRuntimeTokenError extends Enum { readonly isNoFunds: boolean; readonly isWouldDie: boolean; @@ -148,7 +157,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'NoFunds' | 'WouldDie' | 'BelowMinimum' | 'CannotCreate' | 'UnknownAsset' | 'Frozen' | 'Unsupported'; } - /** @name SpRuntimeArithmeticError (26) */ + /** @name SpRuntimeArithmeticError (27) */ interface SpRuntimeArithmeticError extends Enum { readonly isUnderflow: boolean; readonly isOverflow: boolean; @@ -156,14 +165,14 @@ declare module '@polkadot/types/lookup' { readonly type: 'Underflow' | 'Overflow' | 'DivisionByZero'; } - /** @name SpRuntimeTransactionalError (27) */ + /** @name SpRuntimeTransactionalError (28) */ interface SpRuntimeTransactionalError extends Enum { readonly isLimitReached: boolean; readonly isNoLayer: boolean; readonly type: 'LimitReached' | 'NoLayer'; } - /** @name CumulusPalletParachainSystemEvent (28) */ + /** @name CumulusPalletParachainSystemEvent (29) */ interface CumulusPalletParachainSystemEvent extends Enum { readonly isValidationFunctionStored: boolean; readonly isValidationFunctionApplied: boolean; @@ -181,13 +190,13 @@ declare module '@polkadot/types/lookup' { } & Struct; readonly isDownwardMessagesProcessed: boolean; readonly asDownwardMessagesProcessed: { - readonly weightUsed: Weight; + readonly weightUsed: SpWeightsWeightV2Weight; readonly dmqHead: H256; } & Struct; readonly type: 'ValidationFunctionStored' | 'ValidationFunctionApplied' | 'ValidationFunctionDiscarded' | 'UpgradeAuthorized' | 'DownwardMessagesReceived' | 'DownwardMessagesProcessed'; } - /** @name PalletBalancesEvent (29) */ + /** @name PalletBalancesEvent (30) */ interface PalletBalancesEvent extends Enum { readonly isEndowed: boolean; readonly asEndowed: { @@ -246,14 +255,14 @@ declare module '@polkadot/types/lookup' { readonly type: 'Endowed' | 'DustLost' | 'Transfer' | 'BalanceSet' | 'Reserved' | 'Unreserved' | 'ReserveRepatriated' | 'Deposit' | 'Withdraw' | 'Slashed'; } - /** @name FrameSupportTokensMiscBalanceStatus (30) */ + /** @name FrameSupportTokensMiscBalanceStatus (31) */ interface FrameSupportTokensMiscBalanceStatus extends Enum { readonly isFree: boolean; readonly isReserved: boolean; readonly type: 'Free' | 'Reserved'; } - /** @name PalletTransactionPaymentEvent (31) */ + /** @name PalletTransactionPaymentEvent (32) */ interface PalletTransactionPaymentEvent extends Enum { readonly isTransactionFeePaid: boolean; readonly asTransactionFeePaid: { @@ -264,7 +273,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'TransactionFeePaid'; } - /** @name PalletTreasuryEvent (32) */ + /** @name PalletTreasuryEvent (33) */ interface PalletTreasuryEvent extends Enum { readonly isProposed: boolean; readonly asProposed: { @@ -306,7 +315,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Proposed' | 'Spending' | 'Awarded' | 'Rejected' | 'Burnt' | 'Rollover' | 'Deposit' | 'SpendApproved'; } - /** @name PalletSudoEvent (33) */ + /** @name PalletSudoEvent (34) */ interface PalletSudoEvent extends Enum { readonly isSudid: boolean; readonly asSudid: { @@ -323,7 +332,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Sudid' | 'KeyChanged' | 'SudoAsDone'; } - /** @name OrmlVestingModuleEvent (37) */ + /** @name OrmlVestingModuleEvent (38) */ interface OrmlVestingModuleEvent extends Enum { readonly isVestingScheduleAdded: boolean; readonly asVestingScheduleAdded: { @@ -343,7 +352,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'VestingScheduleAdded' | 'Claimed' | 'VestingSchedulesUpdated'; } - /** @name OrmlVestingVestingSchedule (38) */ + /** @name OrmlVestingVestingSchedule (39) */ interface OrmlVestingVestingSchedule extends Struct { readonly start: u32; readonly period: u32; @@ -351,7 +360,7 @@ declare module '@polkadot/types/lookup' { readonly perPeriod: Compact; } - /** @name OrmlXtokensModuleEvent (40) */ + /** @name OrmlXtokensModuleEvent (41) */ interface OrmlXtokensModuleEvent extends Enum { readonly isTransferredMultiAssets: boolean; readonly asTransferredMultiAssets: { @@ -363,16 +372,16 @@ declare module '@polkadot/types/lookup' { readonly type: 'TransferredMultiAssets'; } - /** @name XcmV1MultiassetMultiAssets (41) */ + /** @name XcmV1MultiassetMultiAssets (42) */ interface XcmV1MultiassetMultiAssets extends Vec {} - /** @name XcmV1MultiAsset (43) */ + /** @name XcmV1MultiAsset (44) */ interface XcmV1MultiAsset extends Struct { readonly id: XcmV1MultiassetAssetId; readonly fun: XcmV1MultiassetFungibility; } - /** @name XcmV1MultiassetAssetId (44) */ + /** @name XcmV1MultiassetAssetId (45) */ interface XcmV1MultiassetAssetId extends Enum { readonly isConcrete: boolean; readonly asConcrete: XcmV1MultiLocation; @@ -381,13 +390,13 @@ declare module '@polkadot/types/lookup' { readonly type: 'Concrete' | 'Abstract'; } - /** @name XcmV1MultiLocation (45) */ + /** @name XcmV1MultiLocation (46) */ interface XcmV1MultiLocation extends Struct { readonly parents: u8; readonly interior: XcmV1MultilocationJunctions; } - /** @name XcmV1MultilocationJunctions (46) */ + /** @name XcmV1MultilocationJunctions (47) */ interface XcmV1MultilocationJunctions extends Enum { readonly isHere: boolean; readonly isX1: boolean; @@ -409,7 +418,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Here' | 'X1' | 'X2' | 'X3' | 'X4' | 'X5' | 'X6' | 'X7' | 'X8'; } - /** @name XcmV1Junction (47) */ + /** @name XcmV1Junction (48) */ interface XcmV1Junction extends Enum { readonly isParachain: boolean; readonly asParachain: Compact; @@ -443,7 +452,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Parachain' | 'AccountId32' | 'AccountIndex64' | 'AccountKey20' | 'PalletInstance' | 'GeneralIndex' | 'GeneralKey' | 'OnlyChild' | 'Plurality'; } - /** @name XcmV0JunctionNetworkId (49) */ + /** @name XcmV0JunctionNetworkId (50) */ interface XcmV0JunctionNetworkId extends Enum { readonly isAny: boolean; readonly isNamed: boolean; @@ -628,13 +637,13 @@ declare module '@polkadot/types/lookup' { readonly isSuccess: boolean; readonly asSuccess: { readonly messageHash: Option; - readonly weight: Weight; + readonly weight: SpWeightsWeightV2Weight; } & Struct; readonly isFail: boolean; readonly asFail: { readonly messageHash: Option; readonly error: XcmV2TraitsError; - readonly weight: Weight; + readonly weight: SpWeightsWeightV2Weight; } & Struct; readonly isBadVersion: boolean; readonly asBadVersion: { @@ -657,12 +666,12 @@ declare module '@polkadot/types/lookup' { readonly sender: u32; readonly sentAt: u32; readonly index: u64; - readonly required: Weight; + readonly required: SpWeightsWeightV2Weight; } & Struct; readonly isOverweightServiced: boolean; readonly asOverweightServiced: { readonly index: u64; - readonly used: Weight; + readonly used: SpWeightsWeightV2Weight; } & Struct; readonly type: 'Success' | 'Fail' | 'BadVersion' | 'BadFormat' | 'UpwardMessageSent' | 'XcmpMessageSent' | 'OverweightEnqueued' | 'OverweightServiced'; } @@ -713,7 +722,7 @@ declare module '@polkadot/types/lookup' { readonly isNotified: boolean; readonly asNotified: ITuple<[u64, u8, u8]>; readonly isNotifyOverweight: boolean; - readonly asNotifyOverweight: ITuple<[u64, u8, u8, Weight, Weight]>; + readonly asNotifyOverweight: ITuple<[u64, u8, u8, SpWeightsWeightV2Weight, SpWeightsWeightV2Weight]>; readonly isNotifyDispatchError: boolean; readonly asNotifyDispatchError: ITuple<[u64, u8, u8]>; readonly isNotifyDecodeFailed: boolean; @@ -734,7 +743,9 @@ declare module '@polkadot/types/lookup' { readonly asNotifyTargetSendFail: ITuple<[XcmV1MultiLocation, u64, XcmV2TraitsError]>; readonly isNotifyTargetMigrationFail: boolean; readonly asNotifyTargetMigrationFail: ITuple<[XcmVersionedMultiLocation, u64]>; - readonly type: 'Attempted' | 'Sent' | 'UnexpectedResponse' | 'ResponseReady' | 'Notified' | 'NotifyOverweight' | 'NotifyDispatchError' | 'NotifyDecodeFailed' | 'InvalidResponder' | 'InvalidResponderVersion' | 'ResponseTaken' | 'AssetsTrapped' | 'VersionChangeNotified' | 'SupportedVersionChanged' | 'NotifyTargetSendFail' | 'NotifyTargetMigrationFail'; + readonly isAssetsClaimed: boolean; + readonly asAssetsClaimed: ITuple<[H256, XcmV1MultiLocation, XcmVersionedMultiAssets]>; + readonly type: 'Attempted' | 'Sent' | 'UnexpectedResponse' | 'ResponseReady' | 'Notified' | 'NotifyOverweight' | 'NotifyDispatchError' | 'NotifyDecodeFailed' | 'InvalidResponder' | 'InvalidResponderVersion' | 'ResponseTaken' | 'AssetsTrapped' | 'VersionChangeNotified' | 'SupportedVersionChanged' | 'NotifyTargetSendFail' | 'NotifyTargetMigrationFail' | 'AssetsClaimed'; } /** @name XcmV2TraitsOutcome (67) */ @@ -1081,58 +1092,24 @@ declare module '@polkadot/types/lookup' { readonly isWeightExhausted: boolean; readonly asWeightExhausted: { readonly messageId: U8aFixed; - readonly remainingWeight: Weight; - readonly requiredWeight: Weight; + readonly remainingWeight: SpWeightsWeightV2Weight; + readonly requiredWeight: SpWeightsWeightV2Weight; } & Struct; readonly isOverweightEnqueued: boolean; readonly asOverweightEnqueued: { readonly messageId: U8aFixed; readonly overweightIndex: u64; - readonly requiredWeight: Weight; + readonly requiredWeight: SpWeightsWeightV2Weight; } & Struct; readonly isOverweightServiced: boolean; readonly asOverweightServiced: { readonly overweightIndex: u64; - readonly weightUsed: Weight; + readonly weightUsed: SpWeightsWeightV2Weight; } & Struct; readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward' | 'WeightExhausted' | 'OverweightEnqueued' | 'OverweightServiced'; } - /** @name PalletUniqueRawEvent (89) */ - interface PalletUniqueRawEvent extends Enum { - readonly isCollectionSponsorRemoved: boolean; - readonly asCollectionSponsorRemoved: u32; - readonly isCollectionAdminAdded: boolean; - readonly asCollectionAdminAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; - readonly isCollectionOwnedChanged: boolean; - readonly asCollectionOwnedChanged: ITuple<[u32, AccountId32]>; - readonly isCollectionSponsorSet: boolean; - readonly asCollectionSponsorSet: ITuple<[u32, AccountId32]>; - readonly isSponsorshipConfirmed: boolean; - readonly asSponsorshipConfirmed: ITuple<[u32, AccountId32]>; - readonly isCollectionAdminRemoved: boolean; - readonly asCollectionAdminRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; - readonly isAllowListAddressRemoved: boolean; - readonly asAllowListAddressRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; - readonly isAllowListAddressAdded: boolean; - readonly asAllowListAddressAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; - readonly isCollectionLimitSet: boolean; - readonly asCollectionLimitSet: u32; - readonly isCollectionPermissionSet: boolean; - readonly asCollectionPermissionSet: u32; - readonly type: 'CollectionSponsorRemoved' | 'CollectionAdminAdded' | 'CollectionOwnedChanged' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionAdminRemoved' | 'AllowListAddressRemoved' | 'AllowListAddressAdded' | 'CollectionLimitSet' | 'CollectionPermissionSet'; - } - - /** @name PalletEvmAccountBasicCrossAccountIdRepr (90) */ - interface PalletEvmAccountBasicCrossAccountIdRepr extends Enum { - readonly isSubstrate: boolean; - readonly asSubstrate: AccountId32; - readonly isEthereum: boolean; - readonly asEthereum: H160; - readonly type: 'Substrate' | 'Ethereum'; - } - - /** @name PalletCommonEvent (93) */ + /** @name PalletCommonEvent (89) */ interface PalletCommonEvent extends Enum { readonly isCollectionCreated: boolean; readonly asCollectionCreated: ITuple<[u32, u8, AccountId32]>; @@ -1146,6 +1123,8 @@ declare module '@polkadot/types/lookup' { readonly asTransfer: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>; readonly isApproved: boolean; readonly asApproved: ITuple<[u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>; + readonly isApprovedForAll: boolean; + readonly asApprovedForAll: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>; readonly isCollectionPropertySet: boolean; readonly asCollectionPropertySet: ITuple<[u32, Bytes]>; readonly isCollectionPropertyDeleted: boolean; @@ -1156,7 +1135,36 @@ declare module '@polkadot/types/lookup' { readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>; readonly isPropertyPermissionSet: boolean; readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>; - readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet'; + readonly isAllowListAddressAdded: boolean; + readonly asAllowListAddressAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; + readonly isAllowListAddressRemoved: boolean; + readonly asAllowListAddressRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; + readonly isCollectionAdminAdded: boolean; + readonly asCollectionAdminAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; + readonly isCollectionAdminRemoved: boolean; + readonly asCollectionAdminRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>; + readonly isCollectionLimitSet: boolean; + readonly asCollectionLimitSet: u32; + readonly isCollectionOwnerChanged: boolean; + readonly asCollectionOwnerChanged: ITuple<[u32, AccountId32]>; + readonly isCollectionPermissionSet: boolean; + readonly asCollectionPermissionSet: u32; + readonly isCollectionSponsorSet: boolean; + readonly asCollectionSponsorSet: ITuple<[u32, AccountId32]>; + readonly isSponsorshipConfirmed: boolean; + readonly asSponsorshipConfirmed: ITuple<[u32, AccountId32]>; + readonly isCollectionSponsorRemoved: boolean; + readonly asCollectionSponsorRemoved: u32; + readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet' | 'AllowListAddressAdded' | 'AllowListAddressRemoved' | 'CollectionAdminAdded' | 'CollectionAdminRemoved' | 'CollectionLimitSet' | 'CollectionOwnerChanged' | 'CollectionPermissionSet' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionSponsorRemoved'; + } + + /** @name PalletEvmAccountBasicCrossAccountIdRepr (92) */ + interface PalletEvmAccountBasicCrossAccountIdRepr extends Enum { + readonly isSubstrate: boolean; + readonly asSubstrate: AccountId32; + readonly isEthereum: boolean; + readonly asEthereum: H160; + readonly type: 'Substrate' | 'Ethereum'; } /** @name PalletStructureEvent (96) */ @@ -1166,7 +1174,121 @@ declare module '@polkadot/types/lookup' { readonly type: 'Executed'; } - /** @name PalletAppPromotionEvent (97) */ + /** @name PalletRmrkCoreEvent (97) */ + interface PalletRmrkCoreEvent extends Enum { + readonly isCollectionCreated: boolean; + readonly asCollectionCreated: { + readonly issuer: AccountId32; + readonly collectionId: u32; + } & Struct; + readonly isCollectionDestroyed: boolean; + readonly asCollectionDestroyed: { + readonly issuer: AccountId32; + readonly collectionId: u32; + } & Struct; + readonly isIssuerChanged: boolean; + readonly asIssuerChanged: { + readonly oldIssuer: AccountId32; + readonly newIssuer: AccountId32; + readonly collectionId: u32; + } & Struct; + readonly isCollectionLocked: boolean; + readonly asCollectionLocked: { + readonly issuer: AccountId32; + readonly collectionId: u32; + } & Struct; + readonly isNftMinted: boolean; + readonly asNftMinted: { + readonly owner: AccountId32; + readonly collectionId: u32; + readonly nftId: u32; + } & Struct; + readonly isNftBurned: boolean; + readonly asNftBurned: { + readonly owner: AccountId32; + readonly nftId: u32; + } & Struct; + readonly isNftSent: boolean; + readonly asNftSent: { + readonly sender: AccountId32; + readonly recipient: RmrkTraitsNftAccountIdOrCollectionNftTuple; + readonly collectionId: u32; + readonly nftId: u32; + readonly approvalRequired: bool; + } & Struct; + readonly isNftAccepted: boolean; + readonly asNftAccepted: { + readonly sender: AccountId32; + readonly recipient: RmrkTraitsNftAccountIdOrCollectionNftTuple; + readonly collectionId: u32; + readonly nftId: u32; + } & Struct; + readonly isNftRejected: boolean; + readonly asNftRejected: { + readonly sender: AccountId32; + readonly collectionId: u32; + readonly nftId: u32; + } & Struct; + readonly isPropertySet: boolean; + readonly asPropertySet: { + readonly collectionId: u32; + readonly maybeNftId: Option; + readonly key: Bytes; + readonly value: Bytes; + } & Struct; + readonly isResourceAdded: boolean; + readonly asResourceAdded: { + readonly nftId: u32; + readonly resourceId: u32; + } & Struct; + readonly isResourceRemoval: boolean; + readonly asResourceRemoval: { + readonly nftId: u32; + readonly resourceId: u32; + } & Struct; + readonly isResourceAccepted: boolean; + readonly asResourceAccepted: { + readonly nftId: u32; + readonly resourceId: u32; + } & Struct; + readonly isResourceRemovalAccepted: boolean; + readonly asResourceRemovalAccepted: { + readonly nftId: u32; + readonly resourceId: u32; + } & Struct; + readonly isPrioritySet: boolean; + readonly asPrioritySet: { + readonly collectionId: u32; + readonly nftId: u32; + } & Struct; + readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'IssuerChanged' | 'CollectionLocked' | 'NftMinted' | 'NftBurned' | 'NftSent' | 'NftAccepted' | 'NftRejected' | 'PropertySet' | 'ResourceAdded' | 'ResourceRemoval' | 'ResourceAccepted' | 'ResourceRemovalAccepted' | 'PrioritySet'; + } + + /** @name RmrkTraitsNftAccountIdOrCollectionNftTuple (98) */ + interface RmrkTraitsNftAccountIdOrCollectionNftTuple extends Enum { + readonly isAccountId: boolean; + readonly asAccountId: AccountId32; + readonly isCollectionAndNftTuple: boolean; + readonly asCollectionAndNftTuple: ITuple<[u32, u32]>; + readonly type: 'AccountId' | 'CollectionAndNftTuple'; + } + + /** @name PalletRmrkEquipEvent (102) */ + interface PalletRmrkEquipEvent extends Enum { + readonly isBaseCreated: boolean; + readonly asBaseCreated: { + readonly issuer: AccountId32; + readonly baseId: u32; + } & Struct; + readonly isEquippablesUpdated: boolean; + readonly asEquippablesUpdated: { + readonly baseId: u32; + readonly slotId: u32; + } & Struct; + readonly type: 'BaseCreated' | 'EquippablesUpdated'; + } + + /** @name PalletAppPromotionEvent (103) */ interface PalletAppPromotionEvent extends Enum { readonly isStakingRecalculation: boolean; readonly asStakingRecalculation: ITuple<[AccountId32, u128, u128]>; @@ -1179,7 +1301,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'StakingRecalculation' | 'Stake' | 'Unstake' | 'SetAdmin'; } - /** @name PalletForeignAssetsModuleEvent (98) */ + /** @name PalletForeignAssetsModuleEvent (104) */ interface PalletForeignAssetsModuleEvent extends Enum { readonly isForeignAssetRegistered: boolean; readonly asForeignAssetRegistered: { @@ -1206,7 +1328,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'ForeignAssetRegistered' | 'ForeignAssetUpdated' | 'AssetRegistered' | 'AssetUpdated'; } - /** @name PalletForeignAssetsModuleAssetMetadata (99) */ + /** @name PalletForeignAssetsModuleAssetMetadata (105) */ interface PalletForeignAssetsModuleAssetMetadata extends Struct { readonly name: Bytes; readonly symbol: Bytes; @@ -1214,40 +1336,51 @@ declare module '@polkadot/types/lookup' { readonly minimalBalance: u128; } - /** @name PalletEvmEvent (100) */ + /** @name PalletEvmEvent (106) */ interface PalletEvmEvent extends Enum { readonly isLog: boolean; - readonly asLog: EthereumLog; + readonly asLog: { + readonly log: EthereumLog; + } & Struct; readonly isCreated: boolean; - readonly asCreated: H160; + readonly asCreated: { + readonly address: H160; + } & Struct; readonly isCreatedFailed: boolean; - readonly asCreatedFailed: H160; + readonly asCreatedFailed: { + readonly address: H160; + } & Struct; readonly isExecuted: boolean; - readonly asExecuted: H160; + readonly asExecuted: { + readonly address: H160; + } & Struct; readonly isExecutedFailed: boolean; - readonly asExecutedFailed: H160; - readonly isBalanceDeposit: boolean; - readonly asBalanceDeposit: ITuple<[AccountId32, H160, U256]>; - readonly isBalanceWithdraw: boolean; - readonly asBalanceWithdraw: ITuple<[AccountId32, H160, U256]>; - readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed' | 'BalanceDeposit' | 'BalanceWithdraw'; + readonly asExecutedFailed: { + readonly address: H160; + } & Struct; + readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed'; } - /** @name EthereumLog (101) */ + /** @name EthereumLog (107) */ interface EthereumLog extends Struct { readonly address: H160; readonly topics: Vec; readonly data: Bytes; } - /** @name PalletEthereumEvent (105) */ + /** @name PalletEthereumEvent (109) */ interface PalletEthereumEvent extends Enum { readonly isExecuted: boolean; - readonly asExecuted: ITuple<[H160, H160, H256, EvmCoreErrorExitReason]>; + readonly asExecuted: { + readonly from: H160; + readonly to: H160; + readonly transactionHash: H256; + readonly exitReason: EvmCoreErrorExitReason; + } & Struct; readonly type: 'Executed'; } - /** @name EvmCoreErrorExitReason (106) */ + /** @name EvmCoreErrorExitReason (110) */ interface EvmCoreErrorExitReason extends Enum { readonly isSucceed: boolean; readonly asSucceed: EvmCoreErrorExitSucceed; @@ -1260,7 +1393,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Succeed' | 'Error' | 'Revert' | 'Fatal'; } - /** @name EvmCoreErrorExitSucceed (107) */ + /** @name EvmCoreErrorExitSucceed (111) */ interface EvmCoreErrorExitSucceed extends Enum { readonly isStopped: boolean; readonly isReturned: boolean; @@ -1268,7 +1401,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Stopped' | 'Returned' | 'Suicided'; } - /** @name EvmCoreErrorExitError (108) */ + /** @name EvmCoreErrorExitError (112) */ interface EvmCoreErrorExitError extends Enum { readonly isStackUnderflow: boolean; readonly isStackOverflow: boolean; @@ -1289,13 +1422,13 @@ declare module '@polkadot/types/lookup' { readonly type: 'StackUnderflow' | 'StackOverflow' | 'InvalidJump' | 'InvalidRange' | 'DesignatedInvalid' | 'CallTooDeep' | 'CreateCollision' | 'CreateContractLimit' | 'OutOfOffset' | 'OutOfGas' | 'OutOfFund' | 'PcUnderflow' | 'CreateEmpty' | 'Other' | 'InvalidCode'; } - /** @name EvmCoreErrorExitRevert (111) */ + /** @name EvmCoreErrorExitRevert (115) */ interface EvmCoreErrorExitRevert extends Enum { readonly isReverted: boolean; readonly type: 'Reverted'; } - /** @name EvmCoreErrorExitFatal (112) */ + /** @name EvmCoreErrorExitFatal (116) */ interface EvmCoreErrorExitFatal extends Enum { readonly isNotSupported: boolean; readonly isUnhandledInterrupt: boolean; @@ -1306,7 +1439,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'NotSupported' | 'UnhandledInterrupt' | 'CallErrorAsFatal' | 'Other'; } - /** @name PalletEvmContractHelpersEvent (113) */ + /** @name PalletEvmContractHelpersEvent (117) */ interface PalletEvmContractHelpersEvent extends Enum { readonly isContractSponsorSet: boolean; readonly asContractSponsorSet: ITuple<[H160, AccountId32]>; @@ -1317,20 +1450,28 @@ declare module '@polkadot/types/lookup' { readonly type: 'ContractSponsorSet' | 'ContractSponsorshipConfirmed' | 'ContractSponsorRemoved'; } - /** @name PalletEvmMigrationEvent (114) */ + /** @name PalletEvmMigrationEvent (118) */ interface PalletEvmMigrationEvent extends Enum { readonly isTestEvent: boolean; readonly type: 'TestEvent'; } - /** @name PalletMaintenanceEvent (115) */ + /** @name PalletMaintenanceEvent (119) */ interface PalletMaintenanceEvent extends Enum { readonly isMaintenanceEnabled: boolean; readonly isMaintenanceDisabled: boolean; readonly type: 'MaintenanceEnabled' | 'MaintenanceDisabled'; } - /** @name FrameSystemPhase (116) */ + /** @name PalletTestUtilsEvent (120) */ + interface PalletTestUtilsEvent extends Enum { + readonly isValueIsSet: boolean; + readonly isShouldRollback: boolean; + readonly isBatchCompleted: boolean; + readonly type: 'ValueIsSet' | 'ShouldRollback' | 'BatchCompleted'; + } + + /** @name FrameSystemPhase (121) */ interface FrameSystemPhase extends Enum { readonly isApplyExtrinsic: boolean; readonly asApplyExtrinsic: u32; @@ -1339,18 +1480,14 @@ declare module '@polkadot/types/lookup' { readonly type: 'ApplyExtrinsic' | 'Finalization' | 'Initialization'; } - /** @name FrameSystemLastRuntimeUpgradeInfo (119) */ + /** @name FrameSystemLastRuntimeUpgradeInfo (124) */ interface FrameSystemLastRuntimeUpgradeInfo extends Struct { readonly specVersion: Compact; readonly specName: Text; } - /** @name FrameSystemCall (121) */ + /** @name FrameSystemCall (125) */ interface FrameSystemCall extends Enum { - readonly isFillBlock: boolean; - readonly asFillBlock: { - readonly ratio: Perbill; - } & Struct; readonly isRemark: boolean; readonly asRemark: { readonly remark: Bytes; @@ -1384,50 +1521,50 @@ declare module '@polkadot/types/lookup' { readonly asRemarkWithEvent: { readonly remark: Bytes; } & Struct; - readonly type: 'FillBlock' | 'Remark' | 'SetHeapPages' | 'SetCode' | 'SetCodeWithoutChecks' | 'SetStorage' | 'KillStorage' | 'KillPrefix' | 'RemarkWithEvent'; + readonly type: 'Remark' | 'SetHeapPages' | 'SetCode' | 'SetCodeWithoutChecks' | 'SetStorage' | 'KillStorage' | 'KillPrefix' | 'RemarkWithEvent'; } - /** @name FrameSystemLimitsBlockWeights (126) */ + /** @name FrameSystemLimitsBlockWeights (129) */ interface FrameSystemLimitsBlockWeights extends Struct { - readonly baseBlock: Weight; - readonly maxBlock: Weight; + readonly baseBlock: SpWeightsWeightV2Weight; + readonly maxBlock: SpWeightsWeightV2Weight; readonly perClass: FrameSupportDispatchPerDispatchClassWeightsPerClass; } - /** @name FrameSupportDispatchPerDispatchClassWeightsPerClass (127) */ + /** @name FrameSupportDispatchPerDispatchClassWeightsPerClass (130) */ interface FrameSupportDispatchPerDispatchClassWeightsPerClass extends Struct { readonly normal: FrameSystemLimitsWeightsPerClass; readonly operational: FrameSystemLimitsWeightsPerClass; readonly mandatory: FrameSystemLimitsWeightsPerClass; } - /** @name FrameSystemLimitsWeightsPerClass (128) */ + /** @name FrameSystemLimitsWeightsPerClass (131) */ interface FrameSystemLimitsWeightsPerClass extends Struct { - readonly baseExtrinsic: Weight; - readonly maxExtrinsic: Option; - readonly maxTotal: Option; - readonly reserved: Option; + readonly baseExtrinsic: SpWeightsWeightV2Weight; + readonly maxExtrinsic: Option; + readonly maxTotal: Option; + readonly reserved: Option; } - /** @name FrameSystemLimitsBlockLength (130) */ + /** @name FrameSystemLimitsBlockLength (133) */ interface FrameSystemLimitsBlockLength extends Struct { readonly max: FrameSupportDispatchPerDispatchClassU32; } - /** @name FrameSupportDispatchPerDispatchClassU32 (131) */ + /** @name FrameSupportDispatchPerDispatchClassU32 (134) */ interface FrameSupportDispatchPerDispatchClassU32 extends Struct { readonly normal: u32; readonly operational: u32; readonly mandatory: u32; } - /** @name SpWeightsRuntimeDbWeight (132) */ + /** @name SpWeightsRuntimeDbWeight (135) */ interface SpWeightsRuntimeDbWeight extends Struct { readonly read: u64; readonly write: u64; } - /** @name SpVersionRuntimeVersion (133) */ + /** @name SpVersionRuntimeVersion (136) */ interface SpVersionRuntimeVersion extends Struct { readonly specName: Text; readonly implName: Text; @@ -1439,7 +1576,7 @@ declare module '@polkadot/types/lookup' { readonly stateVersion: u8; } - /** @name FrameSystemError (138) */ + /** @name FrameSystemError (141) */ interface FrameSystemError extends Enum { readonly isInvalidSpecName: boolean; readonly isSpecVersionNeedsToIncrease: boolean; @@ -1450,7 +1587,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'InvalidSpecName' | 'SpecVersionNeedsToIncrease' | 'FailedToExtractRuntimeVersion' | 'NonDefaultComposite' | 'NonZeroRefCount' | 'CallFiltered'; } - /** @name PolkadotPrimitivesV2PersistedValidationData (139) */ + /** @name PolkadotPrimitivesV2PersistedValidationData (142) */ interface PolkadotPrimitivesV2PersistedValidationData extends Struct { readonly parentHead: Bytes; readonly relayParentNumber: u32; @@ -1458,18 +1595,18 @@ declare module '@polkadot/types/lookup' { readonly maxPovSize: u32; } - /** @name PolkadotPrimitivesV2UpgradeRestriction (142) */ + /** @name PolkadotPrimitivesV2UpgradeRestriction (145) */ interface PolkadotPrimitivesV2UpgradeRestriction extends Enum { readonly isPresent: boolean; readonly type: 'Present'; } - /** @name SpTrieStorageProof (143) */ + /** @name SpTrieStorageProof (146) */ interface SpTrieStorageProof extends Struct { readonly trieNodes: BTreeSet; } - /** @name CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot (145) */ + /** @name CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot (148) */ interface CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot extends Struct { readonly dmqMqcHead: H256; readonly relayDispatchQueueSize: ITuple<[u32, u32]>; @@ -1477,7 +1614,7 @@ declare module '@polkadot/types/lookup' { readonly egressChannels: Vec>; } - /** @name PolkadotPrimitivesV2AbridgedHrmpChannel (148) */ + /** @name PolkadotPrimitivesV2AbridgedHrmpChannel (151) */ interface PolkadotPrimitivesV2AbridgedHrmpChannel extends Struct { readonly maxCapacity: u32; readonly maxTotalSize: u32; @@ -1487,7 +1624,7 @@ declare module '@polkadot/types/lookup' { readonly mqcHead: Option; } - /** @name PolkadotPrimitivesV2AbridgedHostConfiguration (149) */ + /** @name PolkadotPrimitivesV2AbridgedHostConfiguration (152) */ interface PolkadotPrimitivesV2AbridgedHostConfiguration extends Struct { readonly maxCodeSize: u32; readonly maxHeadDataSize: u32; @@ -1500,13 +1637,13 @@ declare module '@polkadot/types/lookup' { readonly validationUpgradeDelay: u32; } - /** @name PolkadotCorePrimitivesOutboundHrmpMessage (155) */ + /** @name PolkadotCorePrimitivesOutboundHrmpMessage (158) */ interface PolkadotCorePrimitivesOutboundHrmpMessage extends Struct { readonly recipient: u32; readonly data: Bytes; } - /** @name CumulusPalletParachainSystemCall (156) */ + /** @name CumulusPalletParachainSystemCall (159) */ interface CumulusPalletParachainSystemCall extends Enum { readonly isSetValidationData: boolean; readonly asSetValidationData: { @@ -1527,7 +1664,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'SetValidationData' | 'SudoSendUpwardMessage' | 'AuthorizeUpgrade' | 'EnactAuthorizedUpgrade'; } - /** @name CumulusPrimitivesParachainInherentParachainInherentData (157) */ + /** @name CumulusPrimitivesParachainInherentParachainInherentData (160) */ interface CumulusPrimitivesParachainInherentParachainInherentData extends Struct { readonly validationData: PolkadotPrimitivesV2PersistedValidationData; readonly relayChainState: SpTrieStorageProof; @@ -1535,19 +1672,19 @@ declare module '@polkadot/types/lookup' { readonly horizontalMessages: BTreeMap>; } - /** @name PolkadotCorePrimitivesInboundDownwardMessage (159) */ + /** @name PolkadotCorePrimitivesInboundDownwardMessage (162) */ interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct { readonly sentAt: u32; readonly msg: Bytes; } - /** @name PolkadotCorePrimitivesInboundHrmpMessage (162) */ + /** @name PolkadotCorePrimitivesInboundHrmpMessage (165) */ interface PolkadotCorePrimitivesInboundHrmpMessage extends Struct { readonly sentAt: u32; readonly data: Bytes; } - /** @name CumulusPalletParachainSystemError (165) */ + /** @name CumulusPalletParachainSystemError (168) */ interface CumulusPalletParachainSystemError extends Enum { readonly isOverlappingUpgrades: boolean; readonly isProhibitedByPolkadot: boolean; @@ -1560,14 +1697,14 @@ declare module '@polkadot/types/lookup' { readonly type: 'OverlappingUpgrades' | 'ProhibitedByPolkadot' | 'TooBig' | 'ValidationDataNotAvailable' | 'HostConfigurationNotAvailable' | 'NotScheduled' | 'NothingAuthorized' | 'Unauthorized'; } - /** @name PalletBalancesBalanceLock (167) */ + /** @name PalletBalancesBalanceLock (170) */ interface PalletBalancesBalanceLock extends Struct { readonly id: U8aFixed; readonly amount: u128; readonly reasons: PalletBalancesReasons; } - /** @name PalletBalancesReasons (168) */ + /** @name PalletBalancesReasons (171) */ interface PalletBalancesReasons extends Enum { readonly isFee: boolean; readonly isMisc: boolean; @@ -1575,20 +1712,13 @@ declare module '@polkadot/types/lookup' { readonly type: 'Fee' | 'Misc' | 'All'; } - /** @name PalletBalancesReserveData (171) */ + /** @name PalletBalancesReserveData (174) */ interface PalletBalancesReserveData extends Struct { readonly id: U8aFixed; readonly amount: u128; } - /** @name PalletBalancesReleases (173) */ - interface PalletBalancesReleases extends Enum { - readonly isV100: boolean; - readonly isV200: boolean; - readonly type: 'V100' | 'V200'; - } - - /** @name PalletBalancesCall (174) */ + /** @name PalletBalancesCall (176) */ interface PalletBalancesCall extends Enum { readonly isTransfer: boolean; readonly asTransfer: { @@ -1625,7 +1755,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Transfer' | 'SetBalance' | 'ForceTransfer' | 'TransferKeepAlive' | 'TransferAll' | 'ForceUnreserve'; } - /** @name PalletBalancesError (177) */ + /** @name PalletBalancesError (179) */ interface PalletBalancesError extends Enum { readonly isVestingBalance: boolean; readonly isLiquidityRestrictions: boolean; @@ -1638,7 +1768,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'VestingBalance' | 'LiquidityRestrictions' | 'InsufficientBalance' | 'ExistentialDeposit' | 'KeepAlive' | 'ExistingVestingSchedule' | 'DeadAccount' | 'TooManyReserves'; } - /** @name PalletTimestampCall (179) */ + /** @name PalletTimestampCall (181) */ interface PalletTimestampCall extends Enum { readonly isSet: boolean; readonly asSet: { @@ -1647,14 +1777,14 @@ declare module '@polkadot/types/lookup' { readonly type: 'Set'; } - /** @name PalletTransactionPaymentReleases (181) */ + /** @name PalletTransactionPaymentReleases (183) */ interface PalletTransactionPaymentReleases extends Enum { readonly isV1Ancient: boolean; readonly isV2: boolean; readonly type: 'V1Ancient' | 'V2'; } - /** @name PalletTreasuryProposal (182) */ + /** @name PalletTreasuryProposal (184) */ interface PalletTreasuryProposal extends Struct { readonly proposer: AccountId32; readonly value: u128; @@ -1662,7 +1792,7 @@ declare module '@polkadot/types/lookup' { readonly bond: u128; } - /** @name PalletTreasuryCall (185) */ + /** @name PalletTreasuryCall (187) */ interface PalletTreasuryCall extends Enum { readonly isProposeSpend: boolean; readonly asProposeSpend: { @@ -1689,10 +1819,10 @@ declare module '@polkadot/types/lookup' { readonly type: 'ProposeSpend' | 'RejectProposal' | 'ApproveProposal' | 'Spend' | 'RemoveApproval'; } - /** @name FrameSupportPalletId (188) */ + /** @name FrameSupportPalletId (190) */ interface FrameSupportPalletId extends U8aFixed {} - /** @name PalletTreasuryError (189) */ + /** @name PalletTreasuryError (191) */ interface PalletTreasuryError extends Enum { readonly isInsufficientProposersBalance: boolean; readonly isInvalidIndex: boolean; @@ -1702,7 +1832,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'InsufficientProposersBalance' | 'InvalidIndex' | 'TooManyApprovals' | 'InsufficientPermission' | 'ProposalNotApproved'; } - /** @name PalletSudoCall (190) */ + /** @name PalletSudoCall (192) */ interface PalletSudoCall extends Enum { readonly isSudo: boolean; readonly asSudo: { @@ -1711,7 +1841,7 @@ declare module '@polkadot/types/lookup' { readonly isSudoUncheckedWeight: boolean; readonly asSudoUncheckedWeight: { readonly call: Call; - readonly weight: Weight; + readonly weight: SpWeightsWeightV2Weight; } & Struct; readonly isSetKey: boolean; readonly asSetKey: { @@ -1725,7 +1855,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Sudo' | 'SudoUncheckedWeight' | 'SetKey' | 'SudoAs'; } - /** @name OrmlVestingModuleCall (192) */ + /** @name OrmlVestingModuleCall (194) */ interface OrmlVestingModuleCall extends Enum { readonly isClaim: boolean; readonly isVestedTransfer: boolean; @@ -1745,20 +1875,20 @@ declare module '@polkadot/types/lookup' { readonly type: 'Claim' | 'VestedTransfer' | 'UpdateVestingSchedules' | 'ClaimFor'; } - /** @name OrmlXtokensModuleCall (194) */ + /** @name OrmlXtokensModuleCall (196) */ interface OrmlXtokensModuleCall extends Enum { readonly isTransfer: boolean; readonly asTransfer: { readonly currencyId: PalletForeignAssetsAssetIds; readonly amount: u128; readonly dest: XcmVersionedMultiLocation; - readonly destWeight: u64; + readonly destWeightLimit: XcmV2WeightLimit; } & Struct; readonly isTransferMultiasset: boolean; readonly asTransferMultiasset: { readonly asset: XcmVersionedMultiAsset; readonly dest: XcmVersionedMultiLocation; - readonly destWeight: u64; + readonly destWeightLimit: XcmV2WeightLimit; } & Struct; readonly isTransferWithFee: boolean; readonly asTransferWithFee: { @@ -1766,33 +1896,33 @@ declare module '@polkadot/types/lookup' { readonly amount: u128; readonly fee: u128; readonly dest: XcmVersionedMultiLocation; - readonly destWeight: u64; + readonly destWeightLimit: XcmV2WeightLimit; } & Struct; readonly isTransferMultiassetWithFee: boolean; readonly asTransferMultiassetWithFee: { readonly asset: XcmVersionedMultiAsset; readonly fee: XcmVersionedMultiAsset; readonly dest: XcmVersionedMultiLocation; - readonly destWeight: u64; + readonly destWeightLimit: XcmV2WeightLimit; } & Struct; readonly isTransferMulticurrencies: boolean; readonly asTransferMulticurrencies: { readonly currencies: Vec>; readonly feeItem: u32; readonly dest: XcmVersionedMultiLocation; - readonly destWeight: u64; + readonly destWeightLimit: XcmV2WeightLimit; } & Struct; readonly isTransferMultiassets: boolean; readonly asTransferMultiassets: { readonly assets: XcmVersionedMultiAssets; readonly feeItem: u32; readonly dest: XcmVersionedMultiLocation; - readonly destWeight: u64; + readonly destWeightLimit: XcmV2WeightLimit; } & Struct; readonly type: 'Transfer' | 'TransferMultiasset' | 'TransferWithFee' | 'TransferMultiassetWithFee' | 'TransferMulticurrencies' | 'TransferMultiassets'; } - /** @name XcmVersionedMultiAsset (195) */ + /** @name XcmVersionedMultiAsset (197) */ interface XcmVersionedMultiAsset extends Enum { readonly isV0: boolean; readonly asV0: XcmV0MultiAsset; @@ -1801,7 +1931,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'V0' | 'V1'; } - /** @name OrmlTokensModuleCall (198) */ + /** @name OrmlTokensModuleCall (200) */ interface OrmlTokensModuleCall extends Enum { readonly isTransfer: boolean; readonly asTransfer: { @@ -1838,12 +1968,12 @@ declare module '@polkadot/types/lookup' { readonly type: 'Transfer' | 'TransferAll' | 'TransferKeepAlive' | 'ForceTransfer' | 'SetBalance'; } - /** @name CumulusPalletXcmpQueueCall (199) */ + /** @name CumulusPalletXcmpQueueCall (201) */ interface CumulusPalletXcmpQueueCall extends Enum { readonly isServiceOverweight: boolean; readonly asServiceOverweight: { readonly index: u64; - readonly weightLimit: Weight; + readonly weightLimit: u64; } & Struct; readonly isSuspendXcmExecution: boolean; readonly isResumeXcmExecution: boolean; @@ -1861,20 +1991,20 @@ declare module '@polkadot/types/lookup' { } & Struct; readonly isUpdateThresholdWeight: boolean; readonly asUpdateThresholdWeight: { - readonly new_: Weight; + readonly new_: u64; } & Struct; readonly isUpdateWeightRestrictDecay: boolean; readonly asUpdateWeightRestrictDecay: { - readonly new_: Weight; + readonly new_: u64; } & Struct; readonly isUpdateXcmpMaxIndividualWeight: boolean; readonly asUpdateXcmpMaxIndividualWeight: { - readonly new_: Weight; + readonly new_: u64; } & Struct; readonly type: 'ServiceOverweight' | 'SuspendXcmExecution' | 'ResumeXcmExecution' | 'UpdateSuspendThreshold' | 'UpdateDropThreshold' | 'UpdateResumeThreshold' | 'UpdateThresholdWeight' | 'UpdateWeightRestrictDecay' | 'UpdateXcmpMaxIndividualWeight'; } - /** @name PalletXcmCall (200) */ + /** @name PalletXcmCall (202) */ interface PalletXcmCall extends Enum { readonly isSend: boolean; readonly asSend: { @@ -1898,7 +2028,7 @@ declare module '@polkadot/types/lookup' { readonly isExecute: boolean; readonly asExecute: { readonly message: XcmVersionedXcm; - readonly maxWeight: Weight; + readonly maxWeight: u64; } & Struct; readonly isForceXcmVersion: boolean; readonly asForceXcmVersion: { @@ -1936,7 +2066,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Send' | 'TeleportAssets' | 'ReserveTransferAssets' | 'Execute' | 'ForceXcmVersion' | 'ForceDefaultXcmVersion' | 'ForceSubscribeVersionNotify' | 'ForceUnsubscribeVersionNotify' | 'LimitedReserveTransferAssets' | 'LimitedTeleportAssets'; } - /** @name XcmVersionedXcm (201) */ + /** @name XcmVersionedXcm (203) */ interface XcmVersionedXcm extends Enum { readonly isV0: boolean; readonly asV0: XcmV0Xcm; @@ -1947,7 +2077,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'V0' | 'V1' | 'V2'; } - /** @name XcmV0Xcm (202) */ + /** @name XcmV0Xcm (204) */ interface XcmV0Xcm extends Enum { readonly isWithdrawAsset: boolean; readonly asWithdrawAsset: { @@ -2010,7 +2140,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'WithdrawAsset' | 'ReserveAssetDeposit' | 'TeleportAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'RelayedFrom'; } - /** @name XcmV0Order (204) */ + /** @name XcmV0Order (206) */ interface XcmV0Order extends Enum { readonly isNull: boolean; readonly isDepositAsset: boolean; @@ -2058,14 +2188,14 @@ declare module '@polkadot/types/lookup' { readonly type: 'Null' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'QueryHolding' | 'BuyExecution'; } - /** @name XcmV0Response (206) */ + /** @name XcmV0Response (208) */ interface XcmV0Response extends Enum { readonly isAssets: boolean; readonly asAssets: Vec; readonly type: 'Assets'; } - /** @name XcmV1Xcm (207) */ + /** @name XcmV1Xcm (209) */ interface XcmV1Xcm extends Enum { readonly isWithdrawAsset: boolean; readonly asWithdrawAsset: { @@ -2134,7 +2264,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'WithdrawAsset' | 'ReserveAssetDeposited' | 'ReceiveTeleportedAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'RelayedFrom' | 'SubscribeVersion' | 'UnsubscribeVersion'; } - /** @name XcmV1Order (209) */ + /** @name XcmV1Order (211) */ interface XcmV1Order extends Enum { readonly isNoop: boolean; readonly isDepositAsset: boolean; @@ -2184,7 +2314,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Noop' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'QueryHolding' | 'BuyExecution'; } - /** @name XcmV1Response (211) */ + /** @name XcmV1Response (213) */ interface XcmV1Response extends Enum { readonly isAssets: boolean; readonly asAssets: XcmV1MultiassetMultiAssets; @@ -2193,20 +2323,20 @@ declare module '@polkadot/types/lookup' { readonly type: 'Assets' | 'Version'; } - /** @name CumulusPalletXcmCall (226) */ + /** @name CumulusPalletXcmCall (227) */ type CumulusPalletXcmCall = Null; - /** @name CumulusPalletDmpQueueCall (227) */ + /** @name CumulusPalletDmpQueueCall (228) */ interface CumulusPalletDmpQueueCall extends Enum { readonly isServiceOverweight: boolean; readonly asServiceOverweight: { readonly index: u64; - readonly weightLimit: Weight; + readonly weightLimit: u64; } & Struct; readonly type: 'ServiceOverweight'; } - /** @name PalletInflationCall (228) */ + /** @name PalletInflationCall (229) */ interface PalletInflationCall extends Enum { readonly isStartInflation: boolean; readonly asStartInflation: { @@ -2215,7 +2345,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'StartInflation'; } - /** @name PalletUniqueCall (229) */ + /** @name PalletUniqueCall (230) */ interface PalletUniqueCall extends Enum { readonly isCreateCollection: boolean; readonly asCreateCollection: { @@ -2370,15 +2500,25 @@ declare module '@polkadot/types/lookup' { readonly tokenId: u32; readonly amount: u128; } & Struct; - readonly isRepairItem: boolean; - readonly asRepairItem: { + readonly isSetAllowanceForAll: boolean; + readonly asSetAllowanceForAll: { + readonly collectionId: u32; + readonly operator: PalletEvmAccountBasicCrossAccountIdRepr; + readonly approve: bool; + } & Struct; + readonly isForceRepairCollection: boolean; + readonly asForceRepairCollection: { + readonly collectionId: u32; + } & Struct; + readonly isForceRepairItem: boolean; + readonly asForceRepairItem: { readonly collectionId: u32; readonly itemId: u32; } & Struct; - readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'RepairItem'; + readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'SetAllowanceForAll' | 'ForceRepairCollection' | 'ForceRepairItem'; } - /** @name UpDataStructsCollectionMode (234) */ + /** @name UpDataStructsCollectionMode (235) */ interface UpDataStructsCollectionMode extends Enum { readonly isNft: boolean; readonly isFungible: boolean; @@ -2387,7 +2527,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Nft' | 'Fungible' | 'ReFungible'; } - /** @name UpDataStructsCreateCollectionData (235) */ + /** @name UpDataStructsCreateCollectionData (236) */ interface UpDataStructsCreateCollectionData extends Struct { readonly mode: UpDataStructsCollectionMode; readonly access: Option; @@ -2401,14 +2541,14 @@ declare module '@polkadot/types/lookup' { readonly properties: Vec; } - /** @name UpDataStructsAccessMode (237) */ + /** @name UpDataStructsAccessMode (238) */ interface UpDataStructsAccessMode extends Enum { readonly isNormal: boolean; readonly isAllowList: boolean; readonly type: 'Normal' | 'AllowList'; } - /** @name UpDataStructsCollectionLimits (239) */ + /** @name UpDataStructsCollectionLimits (240) */ interface UpDataStructsCollectionLimits extends Struct { readonly accountTokenOwnershipLimit: Option; readonly sponsoredDataSize: Option; @@ -2421,7 +2561,7 @@ declare module '@polkadot/types/lookup' { readonly transfersEnabled: Option; } - /** @name UpDataStructsSponsoringRateLimit (241) */ + /** @name UpDataStructsSponsoringRateLimit (242) */ interface UpDataStructsSponsoringRateLimit extends Enum { readonly isSponsoringDisabled: boolean; readonly isBlocks: boolean; @@ -2429,43 +2569,43 @@ declare module '@polkadot/types/lookup' { readonly type: 'SponsoringDisabled' | 'Blocks'; } - /** @name UpDataStructsCollectionPermissions (244) */ + /** @name UpDataStructsCollectionPermissions (245) */ interface UpDataStructsCollectionPermissions extends Struct { readonly access: Option; readonly mintMode: Option; readonly nesting: Option; } - /** @name UpDataStructsNestingPermissions (246) */ + /** @name UpDataStructsNestingPermissions (247) */ interface UpDataStructsNestingPermissions extends Struct { readonly tokenOwner: bool; readonly collectionAdmin: bool; readonly restricted: Option; } - /** @name UpDataStructsOwnerRestrictedSet (248) */ + /** @name UpDataStructsOwnerRestrictedSet (249) */ interface UpDataStructsOwnerRestrictedSet extends BTreeSet {} - /** @name UpDataStructsPropertyKeyPermission (253) */ + /** @name UpDataStructsPropertyKeyPermission (254) */ interface UpDataStructsPropertyKeyPermission extends Struct { readonly key: Bytes; readonly permission: UpDataStructsPropertyPermission; } - /** @name UpDataStructsPropertyPermission (254) */ + /** @name UpDataStructsPropertyPermission (255) */ interface UpDataStructsPropertyPermission extends Struct { readonly mutable: bool; readonly collectionAdmin: bool; readonly tokenOwner: bool; } - /** @name UpDataStructsProperty (257) */ + /** @name UpDataStructsProperty (258) */ interface UpDataStructsProperty extends Struct { readonly key: Bytes; readonly value: Bytes; } - /** @name UpDataStructsCreateItemData (260) */ + /** @name UpDataStructsCreateItemData (261) */ interface UpDataStructsCreateItemData extends Enum { readonly isNft: boolean; readonly asNft: UpDataStructsCreateNftData; @@ -2476,23 +2616,23 @@ declare module '@polkadot/types/lookup' { readonly type: 'Nft' | 'Fungible' | 'ReFungible'; } - /** @name UpDataStructsCreateNftData (261) */ + /** @name UpDataStructsCreateNftData (262) */ interface UpDataStructsCreateNftData extends Struct { readonly properties: Vec; } - /** @name UpDataStructsCreateFungibleData (262) */ + /** @name UpDataStructsCreateFungibleData (263) */ interface UpDataStructsCreateFungibleData extends Struct { readonly value: u128; } - /** @name UpDataStructsCreateReFungibleData (263) */ + /** @name UpDataStructsCreateReFungibleData (264) */ interface UpDataStructsCreateReFungibleData extends Struct { readonly pieces: u128; readonly properties: Vec; } - /** @name UpDataStructsCreateItemExData (266) */ + /** @name UpDataStructsCreateItemExData (267) */ interface UpDataStructsCreateItemExData extends Enum { readonly isNft: boolean; readonly asNft: Vec; @@ -2505,30 +2645,30 @@ declare module '@polkadot/types/lookup' { readonly type: 'Nft' | 'Fungible' | 'RefungibleMultipleItems' | 'RefungibleMultipleOwners'; } - /** @name UpDataStructsCreateNftExData (268) */ + /** @name UpDataStructsCreateNftExData (269) */ interface UpDataStructsCreateNftExData extends Struct { readonly properties: Vec; readonly owner: PalletEvmAccountBasicCrossAccountIdRepr; } - /** @name UpDataStructsCreateRefungibleExSingleOwner (275) */ + /** @name UpDataStructsCreateRefungibleExSingleOwner (276) */ interface UpDataStructsCreateRefungibleExSingleOwner extends Struct { readonly user: PalletEvmAccountBasicCrossAccountIdRepr; readonly pieces: u128; readonly properties: Vec; } - /** @name UpDataStructsCreateRefungibleExMultipleOwners (277) */ + /** @name UpDataStructsCreateRefungibleExMultipleOwners (278) */ interface UpDataStructsCreateRefungibleExMultipleOwners extends Struct { readonly users: BTreeMap; readonly properties: Vec; } - /** @name PalletConfigurationCall (278) */ + /** @name PalletConfigurationCall (279) */ interface PalletConfigurationCall extends Enum { readonly isSetWeightToFeeCoefficientOverride: boolean; readonly asSetWeightToFeeCoefficientOverride: { - readonly coeff: Option; + readonly coeff: Option; } & Struct; readonly isSetMinGasPriceOverride: boolean; readonly asSetMinGasPriceOverride: { @@ -2545,7 +2685,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'SetWeightToFeeCoefficientOverride' | 'SetMinGasPriceOverride' | 'SetXcmAllowedLocations' | 'SetAppPromotionConfigurationOverride'; } - /** @name PalletConfigurationAppPromotionConfiguration (283) */ + /** @name PalletConfigurationAppPromotionConfiguration (284) */ interface PalletConfigurationAppPromotionConfiguration extends Struct { readonly recalculationInterval: Option; readonly pendingInterval: Option; @@ -2553,13 +2693,226 @@ declare module '@polkadot/types/lookup' { readonly maxStakersPerCalculation: Option; } - /** @name PalletTemplateTransactionPaymentCall (286) */ + /** @name PalletTemplateTransactionPaymentCall (288) */ type PalletTemplateTransactionPaymentCall = Null; - /** @name PalletStructureCall (287) */ + /** @name PalletStructureCall (289) */ type PalletStructureCall = Null; - /** @name PalletAppPromotionCall (288) */ + /** @name PalletRmrkCoreCall (290) */ + interface PalletRmrkCoreCall extends Enum { + readonly isCreateCollection: boolean; + readonly asCreateCollection: { + readonly metadata: Bytes; + readonly max: Option; + readonly symbol: Bytes; + } & Struct; + readonly isDestroyCollection: boolean; + readonly asDestroyCollection: { + readonly collectionId: u32; + } & Struct; + readonly isChangeCollectionIssuer: boolean; + readonly asChangeCollectionIssuer: { + readonly collectionId: u32; + readonly newIssuer: MultiAddress; + } & Struct; + readonly isLockCollection: boolean; + readonly asLockCollection: { + readonly collectionId: u32; + } & Struct; + readonly isMintNft: boolean; + readonly asMintNft: { + readonly owner: Option; + readonly collectionId: u32; + readonly recipient: Option; + readonly royaltyAmount: Option; + readonly metadata: Bytes; + readonly transferable: bool; + readonly resources: Option>; + } & Struct; + readonly isBurnNft: boolean; + readonly asBurnNft: { + readonly collectionId: u32; + readonly nftId: u32; + readonly maxBurns: u32; + } & Struct; + readonly isSend: boolean; + readonly asSend: { + readonly rmrkCollectionId: u32; + readonly rmrkNftId: u32; + readonly newOwner: RmrkTraitsNftAccountIdOrCollectionNftTuple; + } & Struct; + readonly isAcceptNft: boolean; + readonly asAcceptNft: { + readonly rmrkCollectionId: u32; + readonly rmrkNftId: u32; + readonly newOwner: RmrkTraitsNftAccountIdOrCollectionNftTuple; + } & Struct; + readonly isRejectNft: boolean; + readonly asRejectNft: { + readonly rmrkCollectionId: u32; + readonly rmrkNftId: u32; + } & Struct; + readonly isAcceptResource: boolean; + readonly asAcceptResource: { + readonly rmrkCollectionId: u32; + readonly rmrkNftId: u32; + readonly resourceId: u32; + } & Struct; + readonly isAcceptResourceRemoval: boolean; + readonly asAcceptResourceRemoval: { + readonly rmrkCollectionId: u32; + readonly rmrkNftId: u32; + readonly resourceId: u32; + } & Struct; + readonly isSetProperty: boolean; + readonly asSetProperty: { + readonly rmrkCollectionId: Compact; + readonly maybeNftId: Option; + readonly key: Bytes; + readonly value: Bytes; + } & Struct; + readonly isSetPriority: boolean; + readonly asSetPriority: { + readonly rmrkCollectionId: u32; + readonly rmrkNftId: u32; + readonly priorities: Vec; + } & Struct; + readonly isAddBasicResource: boolean; + readonly asAddBasicResource: { + readonly rmrkCollectionId: u32; + readonly nftId: u32; + readonly resource: RmrkTraitsResourceBasicResource; + } & Struct; + readonly isAddComposableResource: boolean; + readonly asAddComposableResource: { + readonly rmrkCollectionId: u32; + readonly nftId: u32; + readonly resource: RmrkTraitsResourceComposableResource; + } & Struct; + readonly isAddSlotResource: boolean; + readonly asAddSlotResource: { + readonly rmrkCollectionId: u32; + readonly nftId: u32; + readonly resource: RmrkTraitsResourceSlotResource; + } & Struct; + readonly isRemoveResource: boolean; + readonly asRemoveResource: { + readonly rmrkCollectionId: u32; + readonly nftId: u32; + readonly resourceId: u32; + } & Struct; + readonly type: 'CreateCollection' | 'DestroyCollection' | 'ChangeCollectionIssuer' | 'LockCollection' | 'MintNft' | 'BurnNft' | 'Send' | 'AcceptNft' | 'RejectNft' | 'AcceptResource' | 'AcceptResourceRemoval' | 'SetProperty' | 'SetPriority' | 'AddBasicResource' | 'AddComposableResource' | 'AddSlotResource' | 'RemoveResource'; + } + + /** @name RmrkTraitsResourceResourceTypes (296) */ + interface RmrkTraitsResourceResourceTypes extends Enum { + readonly isBasic: boolean; + readonly asBasic: RmrkTraitsResourceBasicResource; + readonly isComposable: boolean; + readonly asComposable: RmrkTraitsResourceComposableResource; + readonly isSlot: boolean; + readonly asSlot: RmrkTraitsResourceSlotResource; + readonly type: 'Basic' | 'Composable' | 'Slot'; + } + + /** @name RmrkTraitsResourceBasicResource (298) */ + interface RmrkTraitsResourceBasicResource extends Struct { + readonly src: Option; + readonly metadata: Option; + readonly license: Option; + readonly thumb: Option; + } + + /** @name RmrkTraitsResourceComposableResource (300) */ + interface RmrkTraitsResourceComposableResource extends Struct { + readonly parts: Vec; + readonly base: u32; + readonly src: Option; + readonly metadata: Option; + readonly license: Option; + readonly thumb: Option; + } + + /** @name RmrkTraitsResourceSlotResource (301) */ + interface RmrkTraitsResourceSlotResource extends Struct { + readonly base: u32; + readonly src: Option; + readonly metadata: Option; + readonly slot: u32; + readonly license: Option; + readonly thumb: Option; + } + + /** @name PalletRmrkEquipCall (304) */ + interface PalletRmrkEquipCall extends Enum { + readonly isCreateBase: boolean; + readonly asCreateBase: { + readonly baseType: Bytes; + readonly symbol: Bytes; + readonly parts: Vec; + } & Struct; + readonly isThemeAdd: boolean; + readonly asThemeAdd: { + readonly baseId: u32; + readonly theme: RmrkTraitsTheme; + } & Struct; + readonly isEquippable: boolean; + readonly asEquippable: { + readonly baseId: u32; + readonly slotId: u32; + readonly equippables: RmrkTraitsPartEquippableList; + } & Struct; + readonly type: 'CreateBase' | 'ThemeAdd' | 'Equippable'; + } + + /** @name RmrkTraitsPartPartType (307) */ + interface RmrkTraitsPartPartType extends Enum { + readonly isFixedPart: boolean; + readonly asFixedPart: RmrkTraitsPartFixedPart; + readonly isSlotPart: boolean; + readonly asSlotPart: RmrkTraitsPartSlotPart; + readonly type: 'FixedPart' | 'SlotPart'; + } + + /** @name RmrkTraitsPartFixedPart (309) */ + interface RmrkTraitsPartFixedPart extends Struct { + readonly id: u32; + readonly z: u32; + readonly src: Bytes; + } + + /** @name RmrkTraitsPartSlotPart (310) */ + interface RmrkTraitsPartSlotPart extends Struct { + readonly id: u32; + readonly equippable: RmrkTraitsPartEquippableList; + readonly src: Bytes; + readonly z: u32; + } + + /** @name RmrkTraitsPartEquippableList (311) */ + interface RmrkTraitsPartEquippableList extends Enum { + readonly isAll: boolean; + readonly isEmpty: boolean; + readonly isCustom: boolean; + readonly asCustom: Vec; + readonly type: 'All' | 'Empty' | 'Custom'; + } + + /** @name RmrkTraitsTheme (313) */ + interface RmrkTraitsTheme extends Struct { + readonly name: Bytes; + readonly properties: Vec; + readonly inherit: bool; + } + + /** @name RmrkTraitsThemeThemeProperty (315) */ + interface RmrkTraitsThemeThemeProperty extends Struct { + readonly key: Bytes; + readonly value: Bytes; + } + + /** @name PalletAppPromotionCall (317) */ interface PalletAppPromotionCall extends Enum { readonly isSetAdminAddress: boolean; readonly asSetAdminAddress: { @@ -2593,7 +2946,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'SetAdminAddress' | 'Stake' | 'Unstake' | 'SponsorCollection' | 'StopSponsoringCollection' | 'SponsorContract' | 'StopSponsoringContract' | 'PayoutStakers'; } - /** @name PalletForeignAssetsModuleCall (289) */ + /** @name PalletForeignAssetsModuleCall (318) */ interface PalletForeignAssetsModuleCall extends Enum { readonly isRegisterForeignAsset: boolean; readonly asRegisterForeignAsset: { @@ -2610,7 +2963,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'RegisterForeignAsset' | 'UpdateForeignAsset'; } - /** @name PalletEvmCall (290) */ + /** @name PalletEvmCall (319) */ interface PalletEvmCall extends Enum { readonly isWithdraw: boolean; readonly asWithdraw: { @@ -2655,7 +3008,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Withdraw' | 'Call' | 'Create' | 'Create2'; } - /** @name PalletEthereumCall (294) */ + /** @name PalletEthereumCall (325) */ interface PalletEthereumCall extends Enum { readonly isTransact: boolean; readonly asTransact: { @@ -2664,7 +3017,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Transact'; } - /** @name EthereumTransactionTransactionV2 (295) */ + /** @name EthereumTransactionTransactionV2 (326) */ interface EthereumTransactionTransactionV2 extends Enum { readonly isLegacy: boolean; readonly asLegacy: EthereumTransactionLegacyTransaction; @@ -2675,7 +3028,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Legacy' | 'Eip2930' | 'Eip1559'; } - /** @name EthereumTransactionLegacyTransaction (296) */ + /** @name EthereumTransactionLegacyTransaction (327) */ interface EthereumTransactionLegacyTransaction extends Struct { readonly nonce: U256; readonly gasPrice: U256; @@ -2686,7 +3039,7 @@ declare module '@polkadot/types/lookup' { readonly signature: EthereumTransactionTransactionSignature; } - /** @name EthereumTransactionTransactionAction (297) */ + /** @name EthereumTransactionTransactionAction (328) */ interface EthereumTransactionTransactionAction extends Enum { readonly isCall: boolean; readonly asCall: H160; @@ -2694,14 +3047,14 @@ declare module '@polkadot/types/lookup' { readonly type: 'Call' | 'Create'; } - /** @name EthereumTransactionTransactionSignature (298) */ + /** @name EthereumTransactionTransactionSignature (329) */ interface EthereumTransactionTransactionSignature extends Struct { readonly v: u64; readonly r: H256; readonly s: H256; } - /** @name EthereumTransactionEip2930Transaction (300) */ + /** @name EthereumTransactionEip2930Transaction (331) */ interface EthereumTransactionEip2930Transaction extends Struct { readonly chainId: u64; readonly nonce: U256; @@ -2716,13 +3069,13 @@ declare module '@polkadot/types/lookup' { readonly s: H256; } - /** @name EthereumTransactionAccessListItem (302) */ + /** @name EthereumTransactionAccessListItem (333) */ interface EthereumTransactionAccessListItem extends Struct { readonly address: H160; readonly storageKeys: Vec; } - /** @name EthereumTransactionEip1559Transaction (303) */ + /** @name EthereumTransactionEip1559Transaction (334) */ interface EthereumTransactionEip1559Transaction extends Struct { readonly chainId: u64; readonly nonce: U256; @@ -2738,7 +3091,7 @@ declare module '@polkadot/types/lookup' { readonly s: H256; } - /** @name PalletEvmMigrationCall (304) */ + /** @name PalletEvmMigrationCall (335) */ interface PalletEvmMigrationCall extends Enum { readonly isBegin: boolean; readonly asBegin: { @@ -2765,20 +3118,40 @@ declare module '@polkadot/types/lookup' { readonly type: 'Begin' | 'SetData' | 'Finish' | 'InsertEthLogs' | 'InsertEvents'; } - /** @name PalletMaintenanceCall (308) */ + /** @name PalletMaintenanceCall (339) */ interface PalletMaintenanceCall extends Enum { readonly isEnable: boolean; readonly isDisable: boolean; readonly type: 'Enable' | 'Disable'; } - /** @name PalletSudoError (309) */ + /** @name PalletTestUtilsCall (340) */ + interface PalletTestUtilsCall extends Enum { + readonly isEnable: boolean; + readonly isSetTestValue: boolean; + readonly asSetTestValue: { + readonly value: u32; + } & Struct; + readonly isSetTestValueAndRollback: boolean; + readonly asSetTestValueAndRollback: { + readonly value: u32; + } & Struct; + readonly isIncTestValue: boolean; + readonly isJustTakeFee: boolean; + readonly isBatchAll: boolean; + readonly asBatchAll: { + readonly calls: Vec; + } & Struct; + readonly type: 'Enable' | 'SetTestValue' | 'SetTestValueAndRollback' | 'IncTestValue' | 'JustTakeFee' | 'BatchAll'; + } + + /** @name PalletSudoError (342) */ interface PalletSudoError extends Enum { readonly isRequireSudo: boolean; readonly type: 'RequireSudo'; } - /** @name OrmlVestingModuleError (311) */ + /** @name OrmlVestingModuleError (344) */ interface OrmlVestingModuleError extends Enum { readonly isZeroVestingPeriod: boolean; readonly isZeroVestingPeriodCount: boolean; @@ -2789,7 +3162,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'ZeroVestingPeriod' | 'ZeroVestingPeriodCount' | 'InsufficientBalanceToLock' | 'TooManyVestingSchedules' | 'AmountLow' | 'MaxVestingSchedulesExceeded'; } - /** @name OrmlXtokensModuleError (312) */ + /** @name OrmlXtokensModuleError (345) */ interface OrmlXtokensModuleError extends Enum { readonly isAssetHasNoReserve: boolean; readonly isNotCrossChainTransfer: boolean; @@ -2813,26 +3186,26 @@ declare module '@polkadot/types/lookup' { readonly type: 'AssetHasNoReserve' | 'NotCrossChainTransfer' | 'InvalidDest' | 'NotCrossChainTransferableCurrency' | 'UnweighableMessage' | 'XcmExecutionFailed' | 'CannotReanchor' | 'InvalidAncestry' | 'InvalidAsset' | 'DestinationNotInvertible' | 'BadVersion' | 'DistinctReserveForAssetAndFee' | 'ZeroFee' | 'ZeroAmount' | 'TooManyAssetsBeingSent' | 'AssetIndexNonExistent' | 'FeeNotEnough' | 'NotSupportedMultiLocation' | 'MinXcmFeeNotDefined'; } - /** @name OrmlTokensBalanceLock (315) */ + /** @name OrmlTokensBalanceLock (348) */ interface OrmlTokensBalanceLock extends Struct { readonly id: U8aFixed; readonly amount: u128; } - /** @name OrmlTokensAccountData (317) */ + /** @name OrmlTokensAccountData (350) */ interface OrmlTokensAccountData extends Struct { readonly free: u128; readonly reserved: u128; readonly frozen: u128; } - /** @name OrmlTokensReserveData (319) */ + /** @name OrmlTokensReserveData (352) */ interface OrmlTokensReserveData extends Struct { readonly id: Null; readonly amount: u128; } - /** @name OrmlTokensModuleError (321) */ + /** @name OrmlTokensModuleError (354) */ interface OrmlTokensModuleError extends Enum { readonly isBalanceTooLow: boolean; readonly isAmountIntoBalanceFailed: boolean; @@ -2845,21 +3218,21 @@ declare module '@polkadot/types/lookup' { readonly type: 'BalanceTooLow' | 'AmountIntoBalanceFailed' | 'LiquidityRestrictions' | 'MaxLocksExceeded' | 'KeepAlive' | 'ExistentialDeposit' | 'DeadAccount' | 'TooManyReserves'; } - /** @name CumulusPalletXcmpQueueInboundChannelDetails (323) */ + /** @name CumulusPalletXcmpQueueInboundChannelDetails (356) */ interface CumulusPalletXcmpQueueInboundChannelDetails extends Struct { readonly sender: u32; readonly state: CumulusPalletXcmpQueueInboundState; readonly messageMetadata: Vec>; } - /** @name CumulusPalletXcmpQueueInboundState (324) */ + /** @name CumulusPalletXcmpQueueInboundState (357) */ interface CumulusPalletXcmpQueueInboundState extends Enum { readonly isOk: boolean; readonly isSuspended: boolean; readonly type: 'Ok' | 'Suspended'; } - /** @name PolkadotParachainPrimitivesXcmpMessageFormat (327) */ + /** @name PolkadotParachainPrimitivesXcmpMessageFormat (360) */ interface PolkadotParachainPrimitivesXcmpMessageFormat extends Enum { readonly isConcatenatedVersionedXcm: boolean; readonly isConcatenatedEncodedBlob: boolean; @@ -2867,7 +3240,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'ConcatenatedVersionedXcm' | 'ConcatenatedEncodedBlob' | 'Signals'; } - /** @name CumulusPalletXcmpQueueOutboundChannelDetails (330) */ + /** @name CumulusPalletXcmpQueueOutboundChannelDetails (363) */ interface CumulusPalletXcmpQueueOutboundChannelDetails extends Struct { readonly recipient: u32; readonly state: CumulusPalletXcmpQueueOutboundState; @@ -2876,24 +3249,24 @@ declare module '@polkadot/types/lookup' { readonly lastIndex: u16; } - /** @name CumulusPalletXcmpQueueOutboundState (331) */ + /** @name CumulusPalletXcmpQueueOutboundState (364) */ interface CumulusPalletXcmpQueueOutboundState extends Enum { readonly isOk: boolean; readonly isSuspended: boolean; readonly type: 'Ok' | 'Suspended'; } - /** @name CumulusPalletXcmpQueueQueueConfigData (333) */ + /** @name CumulusPalletXcmpQueueQueueConfigData (366) */ interface CumulusPalletXcmpQueueQueueConfigData extends Struct { readonly suspendThreshold: u32; readonly dropThreshold: u32; readonly resumeThreshold: u32; - readonly thresholdWeight: Weight; - readonly weightRestrictDecay: Weight; - readonly xcmpMaxIndividualWeight: Weight; + readonly thresholdWeight: SpWeightsWeightV2Weight; + readonly weightRestrictDecay: SpWeightsWeightV2Weight; + readonly xcmpMaxIndividualWeight: SpWeightsWeightV2Weight; } - /** @name CumulusPalletXcmpQueueError (335) */ + /** @name CumulusPalletXcmpQueueError (368) */ interface CumulusPalletXcmpQueueError extends Enum { readonly isFailedToSend: boolean; readonly isBadXcmOrigin: boolean; @@ -2903,7 +3276,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'FailedToSend' | 'BadXcmOrigin' | 'BadXcm' | 'BadOverweightIndex' | 'WeightOverLimit'; } - /** @name PalletXcmError (336) */ + /** @name PalletXcmError (369) */ interface PalletXcmError extends Enum { readonly isUnreachable: boolean; readonly isSendFailure: boolean; @@ -2921,44 +3294,43 @@ declare module '@polkadot/types/lookup' { readonly type: 'Unreachable' | 'SendFailure' | 'Filtered' | 'UnweighableMessage' | 'DestinationNotInvertible' | 'Empty' | 'CannotReanchor' | 'TooManyAssets' | 'InvalidOrigin' | 'BadVersion' | 'BadLocation' | 'NoSubscription' | 'AlreadySubscribed'; } - /** @name CumulusPalletXcmError (337) */ + /** @name CumulusPalletXcmError (370) */ type CumulusPalletXcmError = Null; - /** @name CumulusPalletDmpQueueConfigData (338) */ + /** @name CumulusPalletDmpQueueConfigData (371) */ interface CumulusPalletDmpQueueConfigData extends Struct { - readonly maxIndividual: Weight; + readonly maxIndividual: SpWeightsWeightV2Weight; } - /** @name CumulusPalletDmpQueuePageIndexData (339) */ + /** @name CumulusPalletDmpQueuePageIndexData (372) */ interface CumulusPalletDmpQueuePageIndexData extends Struct { readonly beginUsed: u32; readonly endUsed: u32; readonly overweightCount: u64; } - /** @name CumulusPalletDmpQueueError (342) */ + /** @name CumulusPalletDmpQueueError (375) */ interface CumulusPalletDmpQueueError extends Enum { readonly isUnknown: boolean; readonly isOverLimit: boolean; readonly type: 'Unknown' | 'OverLimit'; } - /** @name PalletUniqueError (346) */ + /** @name PalletUniqueError (379) */ interface PalletUniqueError extends Enum { readonly isCollectionDecimalPointLimitExceeded: boolean; - readonly isConfirmUnsetSponsorFail: boolean; readonly isEmptyArgument: boolean; readonly isRepartitionCalledOnNonRefungibleCollection: boolean; - readonly type: 'CollectionDecimalPointLimitExceeded' | 'ConfirmUnsetSponsorFail' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection'; + readonly type: 'CollectionDecimalPointLimitExceeded' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection'; } - /** @name PalletConfigurationError (347) */ + /** @name PalletConfigurationError (380) */ interface PalletConfigurationError extends Enum { readonly isInconsistentConfiguration: boolean; readonly type: 'InconsistentConfiguration'; } - /** @name UpDataStructsCollection (348) */ + /** @name UpDataStructsCollection (381) */ interface UpDataStructsCollection extends Struct { readonly owner: AccountId32; readonly mode: UpDataStructsCollectionMode; @@ -2971,7 +3343,7 @@ declare module '@polkadot/types/lookup' { readonly flags: U8aFixed; } - /** @name UpDataStructsSponsorshipStateAccountId32 (349) */ + /** @name UpDataStructsSponsorshipStateAccountId32 (382) */ interface UpDataStructsSponsorshipStateAccountId32 extends Enum { readonly isDisabled: boolean; readonly isUnconfirmed: boolean; @@ -2981,43 +3353,43 @@ declare module '@polkadot/types/lookup' { readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed'; } - /** @name UpDataStructsProperties (351) */ + /** @name UpDataStructsProperties (384) */ interface UpDataStructsProperties extends Struct { readonly map: UpDataStructsPropertiesMapBoundedVec; readonly consumedSpace: u32; readonly spaceLimit: u32; } - /** @name UpDataStructsPropertiesMapBoundedVec (352) */ + /** @name UpDataStructsPropertiesMapBoundedVec (385) */ interface UpDataStructsPropertiesMapBoundedVec extends BTreeMap {} - /** @name UpDataStructsPropertiesMapPropertyPermission (357) */ + /** @name UpDataStructsPropertiesMapPropertyPermission (390) */ interface UpDataStructsPropertiesMapPropertyPermission extends BTreeMap {} - /** @name UpDataStructsCollectionStats (364) */ + /** @name UpDataStructsCollectionStats (397) */ interface UpDataStructsCollectionStats extends Struct { readonly created: u32; readonly destroyed: u32; readonly alive: u32; } - /** @name UpDataStructsTokenChild (365) */ + /** @name UpDataStructsTokenChild (398) */ interface UpDataStructsTokenChild extends Struct { readonly token: u32; readonly collection: u32; } - /** @name PhantomTypeUpDataStructs (366) */ - interface PhantomTypeUpDataStructs extends Vec> {} + /** @name PhantomTypeUpDataStructs (399) */ + interface PhantomTypeUpDataStructs extends Vec> {} - /** @name UpDataStructsTokenData (368) */ + /** @name UpDataStructsTokenData (401) */ interface UpDataStructsTokenData extends Struct { readonly properties: Vec; readonly owner: Option; readonly pieces: u128; } - /** @name UpDataStructsRpcCollection (370) */ + /** @name UpDataStructsRpcCollection (403) */ interface UpDataStructsRpcCollection extends Struct { readonly owner: AccountId32; readonly mode: UpDataStructsCollectionMode; @@ -3033,13 +3405,13 @@ declare module '@polkadot/types/lookup' { readonly flags: UpDataStructsRpcCollectionFlags; } - /** @name UpDataStructsRpcCollectionFlags (371) */ + /** @name UpDataStructsRpcCollectionFlags (404) */ interface UpDataStructsRpcCollectionFlags extends Struct { readonly foreign: bool; readonly erc721metadata: bool; } - /** @name RmrkTraitsCollectionCollectionInfo (372) */ + /** @name RmrkTraitsCollectionCollectionInfo (405) */ interface RmrkTraitsCollectionCollectionInfo extends Struct { readonly issuer: AccountId32; readonly metadata: Bytes; @@ -3048,7 +3420,7 @@ declare module '@polkadot/types/lookup' { readonly nftsCount: u32; } - /** @name RmrkTraitsNftNftInfo (375) */ + /** @name RmrkTraitsNftNftInfo (406) */ interface RmrkTraitsNftNftInfo extends Struct { readonly owner: RmrkTraitsNftAccountIdOrCollectionNftTuple; readonly royalty: Option; @@ -3057,22 +3429,13 @@ declare module '@polkadot/types/lookup' { readonly pending: bool; } - /** @name RmrkTraitsNftAccountIdOrCollectionNftTuple (376) */ - interface RmrkTraitsNftAccountIdOrCollectionNftTuple extends Enum { - readonly isAccountId: boolean; - readonly asAccountId: AccountId32; - readonly isCollectionAndNftTuple: boolean; - readonly asCollectionAndNftTuple: ITuple<[u32, u32]>; - readonly type: 'AccountId' | 'CollectionAndNftTuple'; - } - - /** @name RmrkTraitsNftRoyaltyInfo (378) */ + /** @name RmrkTraitsNftRoyaltyInfo (408) */ interface RmrkTraitsNftRoyaltyInfo extends Struct { readonly recipient: AccountId32; readonly amount: Permill; } - /** @name RmrkTraitsResourceResourceInfo (379) */ + /** @name RmrkTraitsResourceResourceInfo (409) */ interface RmrkTraitsResourceResourceInfo extends Struct { readonly id: u32; readonly resource: RmrkTraitsResourceResourceTypes; @@ -3080,111 +3443,76 @@ declare module '@polkadot/types/lookup' { readonly pendingRemoval: bool; } - /** @name RmrkTraitsResourceResourceTypes (381) */ - interface RmrkTraitsResourceResourceTypes extends Enum { - readonly isBasic: boolean; - readonly asBasic: RmrkTraitsResourceBasicResource; - readonly isComposable: boolean; - readonly asComposable: RmrkTraitsResourceComposableResource; - readonly isSlot: boolean; - readonly asSlot: RmrkTraitsResourceSlotResource; - readonly type: 'Basic' | 'Composable' | 'Slot'; - } - - /** @name RmrkTraitsResourceBasicResource (382) */ - interface RmrkTraitsResourceBasicResource extends Struct { - readonly src: Option; - readonly metadata: Option; - readonly license: Option; - readonly thumb: Option; - } - - /** @name RmrkTraitsResourceComposableResource (384) */ - interface RmrkTraitsResourceComposableResource extends Struct { - readonly parts: Vec; - readonly base: u32; - readonly src: Option; - readonly metadata: Option; - readonly license: Option; - readonly thumb: Option; - } - - /** @name RmrkTraitsResourceSlotResource (385) */ - interface RmrkTraitsResourceSlotResource extends Struct { - readonly base: u32; - readonly src: Option; - readonly metadata: Option; - readonly slot: u32; - readonly license: Option; - readonly thumb: Option; - } - - /** @name RmrkTraitsPropertyPropertyInfo (386) */ + /** @name RmrkTraitsPropertyPropertyInfo (410) */ interface RmrkTraitsPropertyPropertyInfo extends Struct { readonly key: Bytes; readonly value: Bytes; } - /** @name RmrkTraitsBaseBaseInfo (389) */ + /** @name RmrkTraitsBaseBaseInfo (411) */ interface RmrkTraitsBaseBaseInfo extends Struct { readonly issuer: AccountId32; readonly baseType: Bytes; readonly symbol: Bytes; } - /** @name RmrkTraitsPartPartType (390) */ - interface RmrkTraitsPartPartType extends Enum { - readonly isFixedPart: boolean; - readonly asFixedPart: RmrkTraitsPartFixedPart; - readonly isSlotPart: boolean; - readonly asSlotPart: RmrkTraitsPartSlotPart; - readonly type: 'FixedPart' | 'SlotPart'; + /** @name RmrkTraitsNftNftChild (412) */ + interface RmrkTraitsNftNftChild extends Struct { + readonly collectionId: u32; + readonly nftId: u32; } - /** @name RmrkTraitsPartFixedPart (392) */ - interface RmrkTraitsPartFixedPart extends Struct { - readonly id: u32; - readonly z: u32; - readonly src: Bytes; + /** @name UpPovEstimateRpcPovInfo (413) */ + interface UpPovEstimateRpcPovInfo extends Struct { + readonly proofSize: u64; + readonly compactProofSize: u64; + readonly compressedProofSize: u64; + readonly results: Vec, SpRuntimeTransactionValidityTransactionValidityError>>; + readonly keyValues: Vec; } - /** @name RmrkTraitsPartSlotPart (393) */ - interface RmrkTraitsPartSlotPart extends Struct { - readonly id: u32; - readonly equippable: RmrkTraitsPartEquippableList; - readonly src: Bytes; - readonly z: u32; + /** @name SpRuntimeTransactionValidityTransactionValidityError (416) */ + interface SpRuntimeTransactionValidityTransactionValidityError extends Enum { + readonly isInvalid: boolean; + readonly asInvalid: SpRuntimeTransactionValidityInvalidTransaction; + readonly isUnknown: boolean; + readonly asUnknown: SpRuntimeTransactionValidityUnknownTransaction; + readonly type: 'Invalid' | 'Unknown'; } - /** @name RmrkTraitsPartEquippableList (394) */ - interface RmrkTraitsPartEquippableList extends Enum { - readonly isAll: boolean; - readonly isEmpty: boolean; + /** @name SpRuntimeTransactionValidityInvalidTransaction (417) */ + interface SpRuntimeTransactionValidityInvalidTransaction extends Enum { + readonly isCall: boolean; + readonly isPayment: boolean; + readonly isFuture: boolean; + readonly isStale: boolean; + readonly isBadProof: boolean; + readonly isAncientBirthBlock: boolean; + readonly isExhaustsResources: boolean; readonly isCustom: boolean; - readonly asCustom: Vec; - readonly type: 'All' | 'Empty' | 'Custom'; + readonly asCustom: u8; + readonly isBadMandatory: boolean; + readonly isMandatoryValidation: boolean; + readonly isBadSigner: boolean; + readonly type: 'Call' | 'Payment' | 'Future' | 'Stale' | 'BadProof' | 'AncientBirthBlock' | 'ExhaustsResources' | 'Custom' | 'BadMandatory' | 'MandatoryValidation' | 'BadSigner'; } - /** @name RmrkTraitsTheme (395) */ - interface RmrkTraitsTheme extends Struct { - readonly name: Bytes; - readonly properties: Vec; - readonly inherit: bool; + /** @name SpRuntimeTransactionValidityUnknownTransaction (418) */ + interface SpRuntimeTransactionValidityUnknownTransaction extends Enum { + readonly isCannotLookup: boolean; + readonly isNoUnsignedValidator: boolean; + readonly isCustom: boolean; + readonly asCustom: u8; + readonly type: 'CannotLookup' | 'NoUnsignedValidator' | 'Custom'; } - /** @name RmrkTraitsThemeThemeProperty (397) */ - interface RmrkTraitsThemeThemeProperty extends Struct { + /** @name UpPovEstimateRpcTrieKeyValue (420) */ + interface UpPovEstimateRpcTrieKeyValue extends Struct { readonly key: Bytes; readonly value: Bytes; } - /** @name RmrkTraitsNftNftChild (399) */ - interface RmrkTraitsNftNftChild extends Struct { - readonly collectionId: u32; - readonly nftId: u32; - } - - /** @name PalletCommonError (401) */ + /** @name PalletCommonError (422) */ interface PalletCommonError extends Enum { readonly isCollectionNotFound: boolean; readonly isMustBeTokenOwner: boolean; @@ -3220,26 +3548,24 @@ declare module '@polkadot/types/lookup' { readonly isEmptyPropertyKey: boolean; readonly isCollectionIsExternal: boolean; readonly isCollectionIsInternal: boolean; - readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal'; + readonly isConfirmSponsorshipFail: boolean; + readonly isUserIsNotCollectionAdmin: boolean; + readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal' | 'ConfirmSponsorshipFail' | 'UserIsNotCollectionAdmin'; } - /** @name PalletFungibleError (403) */ + /** @name PalletFungibleError (424) */ interface PalletFungibleError extends Enum { readonly isNotFungibleDataUsedToMintFungibleCollectionToken: boolean; readonly isFungibleItemsHaveNoId: boolean; readonly isFungibleItemsDontHaveData: boolean; readonly isFungibleDisallowsNesting: boolean; readonly isSettingPropertiesNotAllowed: boolean; + readonly isSettingAllowanceForAllNotAllowed: boolean; readonly isFungibleTokensAreAlwaysValid: boolean; - readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'FungibleTokensAreAlwaysValid'; - } - - /** @name PalletRefungibleItemData (404) */ - interface PalletRefungibleItemData extends Struct { - readonly constData: Bytes; + readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'SettingAllowanceForAllNotAllowed' | 'FungibleTokensAreAlwaysValid'; } - /** @name PalletRefungibleError (409) */ + /** @name PalletRefungibleError (428) */ interface PalletRefungibleError extends Enum { readonly isNotRefungibleDataUsedToMintFungibleCollectionToken: boolean; readonly isWrongRefungiblePieces: boolean; @@ -3249,19 +3575,19 @@ declare module '@polkadot/types/lookup' { readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RepartitionWhileNotOwningAllPieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed'; } - /** @name PalletNonfungibleItemData (410) */ + /** @name PalletNonfungibleItemData (429) */ interface PalletNonfungibleItemData extends Struct { readonly owner: PalletEvmAccountBasicCrossAccountIdRepr; } - /** @name UpDataStructsPropertyScope (412) */ + /** @name UpDataStructsPropertyScope (431) */ interface UpDataStructsPropertyScope extends Enum { readonly isNone: boolean; readonly isRmrk: boolean; readonly type: 'None' | 'Rmrk'; } - /** @name PalletNonfungibleError (414) */ + /** @name PalletNonfungibleError (434) */ interface PalletNonfungibleError extends Enum { readonly isNotNonfungibleDataUsedToMintFungibleCollectionToken: boolean; readonly isNonfungibleItemsHaveNoAmount: boolean; @@ -3269,7 +3595,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'NotNonfungibleDataUsedToMintFungibleCollectionToken' | 'NonfungibleItemsHaveNoAmount' | 'CantBurnNftWithChildren'; } - /** @name PalletStructureError (415) */ + /** @name PalletStructureError (435) */ interface PalletStructureError extends Enum { readonly isOuroborosDetected: boolean; readonly isDepthLimit: boolean; @@ -3278,7 +3604,43 @@ declare module '@polkadot/types/lookup' { readonly type: 'OuroborosDetected' | 'DepthLimit' | 'BreadthLimit' | 'TokenNotFound'; } - /** @name PalletAppPromotionError (421) */ + /** @name PalletRmrkCoreError (436) */ + interface PalletRmrkCoreError extends Enum { + readonly isCorruptedCollectionType: boolean; + readonly isRmrkPropertyKeyIsTooLong: boolean; + readonly isRmrkPropertyValueIsTooLong: boolean; + readonly isRmrkPropertyIsNotFound: boolean; + readonly isUnableToDecodeRmrkData: boolean; + readonly isCollectionNotEmpty: boolean; + readonly isNoAvailableCollectionId: boolean; + readonly isNoAvailableNftId: boolean; + readonly isCollectionUnknown: boolean; + readonly isNoPermission: boolean; + readonly isNonTransferable: boolean; + readonly isCollectionFullOrLocked: boolean; + readonly isResourceDoesntExist: boolean; + readonly isCannotSendToDescendentOrSelf: boolean; + readonly isCannotAcceptNonOwnedNft: boolean; + readonly isCannotRejectNonOwnedNft: boolean; + readonly isCannotRejectNonPendingNft: boolean; + readonly isResourceNotPending: boolean; + readonly isNoAvailableResourceId: boolean; + readonly type: 'CorruptedCollectionType' | 'RmrkPropertyKeyIsTooLong' | 'RmrkPropertyValueIsTooLong' | 'RmrkPropertyIsNotFound' | 'UnableToDecodeRmrkData' | 'CollectionNotEmpty' | 'NoAvailableCollectionId' | 'NoAvailableNftId' | 'CollectionUnknown' | 'NoPermission' | 'NonTransferable' | 'CollectionFullOrLocked' | 'ResourceDoesntExist' | 'CannotSendToDescendentOrSelf' | 'CannotAcceptNonOwnedNft' | 'CannotRejectNonOwnedNft' | 'CannotRejectNonPendingNft' | 'ResourceNotPending' | 'NoAvailableResourceId'; + } + + /** @name PalletRmrkEquipError (438) */ + interface PalletRmrkEquipError extends Enum { + readonly isPermissionError: boolean; + readonly isNoAvailableBaseId: boolean; + readonly isNoAvailablePartId: boolean; + readonly isBaseDoesntExist: boolean; + readonly isNeedsDefaultThemeFirst: boolean; + readonly isPartDoesntExist: boolean; + readonly isNoEquippableOnFixedPart: boolean; + readonly type: 'PermissionError' | 'NoAvailableBaseId' | 'NoAvailablePartId' | 'BaseDoesntExist' | 'NeedsDefaultThemeFirst' | 'PartDoesntExist' | 'NoEquippableOnFixedPart'; + } + + /** @name PalletAppPromotionError (444) */ interface PalletAppPromotionError extends Enum { readonly isAdminNotSet: boolean; readonly isNoPermission: boolean; @@ -3289,7 +3651,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'AdminNotSet' | 'NoPermission' | 'NotSufficientFunds' | 'PendingForBlockOverflow' | 'SponsorNotSet' | 'IncorrectLockedBalanceOperation'; } - /** @name PalletForeignAssetsModuleError (422) */ + /** @name PalletForeignAssetsModuleError (445) */ interface PalletForeignAssetsModuleError extends Enum { readonly isBadLocation: boolean; readonly isMultiLocationExisted: boolean; @@ -3298,7 +3660,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'BadLocation' | 'MultiLocationExisted' | 'AssetIdNotExists' | 'AssetIdExisted'; } - /** @name PalletEvmError (424) */ + /** @name PalletEvmError (447) */ interface PalletEvmError extends Enum { readonly isBalanceLow: boolean; readonly isFeeOverflow: boolean; @@ -3306,10 +3668,15 @@ declare module '@polkadot/types/lookup' { readonly isWithdrawFailed: boolean; readonly isGasPriceTooLow: boolean; readonly isInvalidNonce: boolean; - readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce'; + readonly isGasLimitTooLow: boolean; + readonly isGasLimitTooHigh: boolean; + readonly isUndefined: boolean; + readonly isReentrancy: boolean; + readonly isTransactionMustComeFromEOA: boolean; + readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce' | 'GasLimitTooLow' | 'GasLimitTooHigh' | 'Undefined' | 'Reentrancy' | 'TransactionMustComeFromEOA'; } - /** @name FpRpcTransactionStatus (427) */ + /** @name FpRpcTransactionStatus (450) */ interface FpRpcTransactionStatus extends Struct { readonly transactionHash: H256; readonly transactionIndex: u32; @@ -3320,10 +3687,10 @@ declare module '@polkadot/types/lookup' { readonly logsBloom: EthbloomBloom; } - /** @name EthbloomBloom (429) */ + /** @name EthbloomBloom (452) */ interface EthbloomBloom extends U8aFixed {} - /** @name EthereumReceiptReceiptV3 (431) */ + /** @name EthereumReceiptReceiptV3 (454) */ interface EthereumReceiptReceiptV3 extends Enum { readonly isLegacy: boolean; readonly asLegacy: EthereumReceiptEip658ReceiptData; @@ -3334,7 +3701,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Legacy' | 'Eip2930' | 'Eip1559'; } - /** @name EthereumReceiptEip658ReceiptData (432) */ + /** @name EthereumReceiptEip658ReceiptData (455) */ interface EthereumReceiptEip658ReceiptData extends Struct { readonly statusCode: u8; readonly usedGas: U256; @@ -3342,14 +3709,14 @@ declare module '@polkadot/types/lookup' { readonly logs: Vec; } - /** @name EthereumBlock (433) */ + /** @name EthereumBlock (456) */ interface EthereumBlock extends Struct { readonly header: EthereumHeader; readonly transactions: Vec; readonly ommers: Vec; } - /** @name EthereumHeader (434) */ + /** @name EthereumHeader (457) */ interface EthereumHeader extends Struct { readonly parentHash: H256; readonly ommersHash: H256; @@ -3368,24 +3735,24 @@ declare module '@polkadot/types/lookup' { readonly nonce: EthereumTypesHashH64; } - /** @name EthereumTypesHashH64 (435) */ + /** @name EthereumTypesHashH64 (458) */ interface EthereumTypesHashH64 extends U8aFixed {} - /** @name PalletEthereumError (440) */ + /** @name PalletEthereumError (463) */ interface PalletEthereumError extends Enum { readonly isInvalidSignature: boolean; readonly isPreLogExists: boolean; readonly type: 'InvalidSignature' | 'PreLogExists'; } - /** @name PalletEvmCoderSubstrateError (441) */ + /** @name PalletEvmCoderSubstrateError (464) */ interface PalletEvmCoderSubstrateError extends Enum { readonly isOutOfGas: boolean; readonly isOutOfFund: boolean; readonly type: 'OutOfGas' | 'OutOfFund'; } - /** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr (442) */ + /** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr (465) */ interface UpDataStructsSponsorshipStateBasicCrossAccountIdRepr extends Enum { readonly isDisabled: boolean; readonly isUnconfirmed: boolean; @@ -3395,7 +3762,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed'; } - /** @name PalletEvmContractHelpersSponsoringModeT (443) */ + /** @name PalletEvmContractHelpersSponsoringModeT (466) */ interface PalletEvmContractHelpersSponsoringModeT extends Enum { readonly isDisabled: boolean; readonly isAllowlisted: boolean; @@ -3403,7 +3770,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'Disabled' | 'Allowlisted' | 'Generous'; } - /** @name PalletEvmContractHelpersError (449) */ + /** @name PalletEvmContractHelpersError (472) */ interface PalletEvmContractHelpersError extends Enum { readonly isNoPermission: boolean; readonly isNoPendingSponsor: boolean; @@ -3411,7 +3778,7 @@ declare module '@polkadot/types/lookup' { readonly type: 'NoPermission' | 'NoPendingSponsor' | 'TooManyMethodsHaveSponsoredLimit'; } - /** @name PalletEvmMigrationError (450) */ + /** @name PalletEvmMigrationError (473) */ interface PalletEvmMigrationError extends Enum { readonly isAccountNotEmpty: boolean; readonly isAccountIsNotMigrating: boolean; @@ -3419,10 +3786,17 @@ declare module '@polkadot/types/lookup' { readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating' | 'BadEvent'; } - /** @name PalletMaintenanceError (451) */ + /** @name PalletMaintenanceError (474) */ type PalletMaintenanceError = Null; - /** @name SpRuntimeMultiSignature (453) */ + /** @name PalletTestUtilsError (475) */ + interface PalletTestUtilsError extends Enum { + readonly isTestPalletDisabled: boolean; + readonly isTriggerRollback: boolean; + readonly type: 'TestPalletDisabled' | 'TriggerRollback'; + } + + /** @name SpRuntimeMultiSignature (477) */ interface SpRuntimeMultiSignature extends Enum { readonly isEd25519: boolean; readonly asEd25519: SpCoreEd25519Signature; @@ -3433,40 +3807,40 @@ declare module '@polkadot/types/lookup' { readonly type: 'Ed25519' | 'Sr25519' | 'Ecdsa'; } - /** @name SpCoreEd25519Signature (454) */ + /** @name SpCoreEd25519Signature (478) */ interface SpCoreEd25519Signature extends U8aFixed {} - /** @name SpCoreSr25519Signature (456) */ + /** @name SpCoreSr25519Signature (480) */ interface SpCoreSr25519Signature extends U8aFixed {} - /** @name SpCoreEcdsaSignature (457) */ + /** @name SpCoreEcdsaSignature (481) */ interface SpCoreEcdsaSignature extends U8aFixed {} - /** @name FrameSystemExtensionsCheckSpecVersion (460) */ + /** @name FrameSystemExtensionsCheckSpecVersion (484) */ type FrameSystemExtensionsCheckSpecVersion = Null; - /** @name FrameSystemExtensionsCheckTxVersion (461) */ + /** @name FrameSystemExtensionsCheckTxVersion (485) */ type FrameSystemExtensionsCheckTxVersion = Null; - /** @name FrameSystemExtensionsCheckGenesis (462) */ + /** @name FrameSystemExtensionsCheckGenesis (486) */ type FrameSystemExtensionsCheckGenesis = Null; - /** @name FrameSystemExtensionsCheckNonce (465) */ + /** @name FrameSystemExtensionsCheckNonce (489) */ interface FrameSystemExtensionsCheckNonce extends Compact {} - /** @name FrameSystemExtensionsCheckWeight (466) */ + /** @name FrameSystemExtensionsCheckWeight (490) */ type FrameSystemExtensionsCheckWeight = Null; - /** @name OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance (467) */ + /** @name OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance (491) */ type OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance = Null; - /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (468) */ + /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (492) */ interface PalletTemplateTransactionPaymentChargeTransactionPayment extends Compact {} - /** @name OpalRuntimeRuntime (469) */ + /** @name OpalRuntimeRuntime (493) */ type OpalRuntimeRuntime = Null; - /** @name PalletEthereumFakeTransactionFinalizer (470) */ + /** @name PalletEthereumFakeTransactionFinalizer (494) */ type PalletEthereumFakeTransactionFinalizer = Null; } // declare module diff --git a/tests/src/interfaces/types.ts b/tests/src/interfaces/types.ts index 17cdd49c05..919c645bf4 100644 --- a/tests/src/interfaces/types.ts +++ b/tests/src/interfaces/types.ts @@ -4,4 +4,5 @@ export * from './unique/types'; export * from './appPromotion/types'; export * from './rmrk/types'; +export * from './povinfo/types'; export * from './default/types'; diff --git a/tests/src/interfaces/unique/definitions.ts b/tests/src/interfaces/unique/definitions.ts index 303e5d2813..f3a098ca22 100644 --- a/tests/src/interfaces/unique/definitions.ts +++ b/tests/src/interfaces/unique/definitions.ts @@ -38,39 +38,39 @@ export default { types: {}, rpc: { accountTokens: fun( - 'Get tokens owned by an account in a collection', - [collectionParam, crossAccountParam()], + 'Get tokens owned by an account in a collection', + [collectionParam, crossAccountParam()], 'Vec', ), collectionTokens: fun( - 'Get tokens contained within a collection', - [collectionParam], + 'Get tokens contained within a collection', + [collectionParam], 'Vec', ), tokenExists: fun( - 'Check if the token exists', - [collectionParam, tokenParam], + 'Check if the token exists', + [collectionParam, tokenParam], 'bool', ), tokenOwner: fun( - 'Get the token owner', - [collectionParam, tokenParam], + 'Get the token owner', + [collectionParam, tokenParam], `Option<${CROSS_ACCOUNT_ID_TYPE}>`, ), topmostTokenOwner: fun( - 'Get the topmost token owner in the hierarchy of a possibly nested token', - [collectionParam, tokenParam], + 'Get the topmost token owner in the hierarchy of a possibly nested token', + [collectionParam, tokenParam], `Option<${CROSS_ACCOUNT_ID_TYPE}>`, ), tokenOwners: fun( - 'Returns 10 tokens owners in no particular order', - [collectionParam, tokenParam], + 'Returns 10 tokens owners in no particular order', + [collectionParam, tokenParam], `Vec<${CROSS_ACCOUNT_ID_TYPE}>`, ), tokenChildren: fun( - 'Get tokens nested directly into the token', - [collectionParam, tokenParam], + 'Get tokens nested directly into the token', + [collectionParam, tokenParam], 'Vec', ), @@ -91,13 +91,13 @@ export default { ), constMetadata: fun( - 'Get token constant metadata', - [collectionParam, tokenParam], + 'Get token constant metadata', + [collectionParam, tokenParam], 'Vec', ), variableMetadata: fun( - 'Get token variable metadata', - [collectionParam, tokenParam], + 'Get token variable metadata', + [collectionParam, tokenParam], 'Vec', ), @@ -107,73 +107,78 @@ export default { 'UpDataStructsTokenData', ), totalSupply: fun( - 'Get the amount of distinctive tokens present in a collection', - [collectionParam], + 'Get the amount of distinctive tokens present in a collection', + [collectionParam], 'u32', ), accountBalance: fun( - 'Get the amount of any user tokens owned by an account', - [collectionParam, crossAccountParam()], + 'Get the amount of any user tokens owned by an account', + [collectionParam, crossAccountParam()], 'u32', ), balance: fun( - 'Get the amount of a specific token owned by an account', - [collectionParam, crossAccountParam(), tokenParam], + 'Get the amount of a specific token owned by an account', + [collectionParam, crossAccountParam(), tokenParam], 'u128', ), allowance: fun( - 'Get the amount of currently possible sponsored transactions on a token for the fee to be taken off a sponsor', - [collectionParam, crossAccountParam('sender'), crossAccountParam('spender'), tokenParam], + 'Get the amount of currently possible sponsored transactions on a token for the fee to be taken off a sponsor', + [collectionParam, crossAccountParam('sender'), crossAccountParam('spender'), tokenParam], 'u128', ), adminlist: fun( - 'Get the list of admin accounts of a collection', - [collectionParam], + 'Get the list of admin accounts of a collection', + [collectionParam], 'Vec', ), allowlist: fun( - 'Get the list of accounts allowed to operate within a collection', - [collectionParam], + 'Get the list of accounts allowed to operate within a collection', + [collectionParam], 'Vec', ), allowed: fun( - 'Check if a user is allowed to operate within a collection', - [collectionParam, crossAccountParam()], + 'Check if a user is allowed to operate within a collection', + [collectionParam, crossAccountParam()], 'bool', ), lastTokenId: fun( - 'Get the last token ID created in a collection', - [collectionParam], + 'Get the last token ID created in a collection', + [collectionParam], 'u32', ), collectionById: fun( - 'Get a collection by the specified ID', - [collectionParam], + 'Get a collection by the specified ID', + [collectionParam], 'Option', ), collectionStats: fun( - 'Get chain stats about collections', - [], + 'Get chain stats about collections', + [], 'UpDataStructsCollectionStats', ), nextSponsored: fun( - 'Get the number of blocks until sponsoring a transaction is available', - [collectionParam, crossAccountParam(), tokenParam], + 'Get the number of blocks until sponsoring a transaction is available', + [collectionParam, crossAccountParam(), tokenParam], 'Option', ), effectiveCollectionLimits: fun( - 'Get effective collection limits', - [collectionParam], + 'Get effective collection limits', + [collectionParam], 'Option', ), totalPieces: fun( - 'Get the total amount of pieces of an RFT', - [collectionParam, tokenParam], + 'Get the total amount of pieces of an RFT', + [collectionParam, tokenParam], 'Option', ), + allowanceForAll: fun( + 'Tells whether the given `owner` approves the `operator`.', + [collectionParam, crossAccountParam('owner'), crossAccountParam('operator')], + 'Option', + ), }, }; diff --git a/tests/src/limits.test.ts b/tests/src/limits.test.ts index a7a756443f..bcd5995465 100644 --- a/tests/src/limits.test.ts +++ b/tests/src/limits.test.ts @@ -30,7 +30,7 @@ describe('Number of tokens per address (NFT)', () => { itSub.skip('Collection limits allow greater number than chain limits, chain limits are enforced', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {}); await collection.setLimits(alice, {accountTokenOwnershipLimit: 20}); - + for(let i = 0; i < 10; i++){ await expect(collection.mintToken(alice)).to.be.not.rejected; } @@ -40,14 +40,14 @@ describe('Number of tokens per address (NFT)', () => { } await collection.burn(alice); }); - + itSub('Collection limits allow lower number than chain limits, collection limits are enforced', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {}); await collection.setLimits(alice, {accountTokenOwnershipLimit: 1}); await collection.mintToken(alice); await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/); - + await collection.burnToken(alice, 1); await expect(collection.burn(alice)).to.be.not.rejected; }); @@ -68,7 +68,7 @@ describe('Number of tokens per address (ReFungible)', () => { itSub.skip('Collection limits allow greater number than chain limits, chain limits are enforced', async ({helper}) => { const collection = await helper.rft.mintCollection(alice, {}); await collection.setLimits(alice, {accountTokenOwnershipLimit: 20}); - + for(let i = 0; i < 10; i++){ await expect(collection.mintToken(alice, 10n)).to.be.not.rejected; } @@ -85,7 +85,7 @@ describe('Number of tokens per address (ReFungible)', () => { await collection.mintToken(alice); await expect(collection.mintToken(alice)).to.be.rejectedWith(/common\.AccountTokenLimitExceeded/); - + await collection.burnToken(alice, 1); await expect(collection.burn(alice)).to.be.not.rejected; }); @@ -314,7 +314,7 @@ describe('Collection zero limits (NFT)', () => { await collection.setSponsor(alice, alice.address); await collection.confirmSponsorship(alice); - + await token.transfer(alice, {Substrate: bob.address}); const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address); @@ -345,7 +345,7 @@ describe('Collection zero limits (Fungible)', () => { await collection.setSponsor(alice, alice.address); await collection.confirmSponsorship(alice); - + await collection.transfer(alice, {Substrate: bob.address}, 2n); const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address); @@ -387,7 +387,7 @@ describe('Collection zero limits (ReFungible)', () => { await collection.setSponsor(alice, alice.address); await collection.confirmSponsorship(alice); - + await token.transfer(alice, {Substrate: bob.address}, 2n); const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address); @@ -408,17 +408,17 @@ describe('Effective collection limits (NFT)', () => { [alice] = await helper.arrange.createAccounts([10n], donor); }); }); - + itSub('Effective collection limits', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {}); - await collection.setLimits(alice, {ownerCanTransfer: true}); - - { + await collection.setLimits(alice, {ownerCanTransfer: true}); + + { // Check that limits are undefined const collectionInfo = await collection.getData(); const limits = collectionInfo?.raw.limits; expect(limits).to.be.any; - + expect(limits.accountTokenOwnershipLimit).to.be.null; expect(limits.sponsoredDataSize).to.be.null; expect(limits.sponsoredDataRateLimit).to.be.null; @@ -449,7 +449,7 @@ describe('Effective collection limits (NFT)', () => { expect(limits.transfersEnabled).to.be.true; } - { + { // Check the values for collection limits await collection.setLimits(alice, { accountTokenOwnershipLimit: 99_999, diff --git a/tests/src/maintenanceMode.seqtest.ts b/tests/src/maintenanceMode.seqtest.ts index bd0a3175d7..a9dc641714 100644 --- a/tests/src/maintenanceMode.seqtest.ts +++ b/tests/src/maintenanceMode.seqtest.ts @@ -16,7 +16,7 @@ import {IKeyringPair} from '@polkadot/types/types'; import {ApiPromise} from '@polkadot/api'; -import {expect, itSub, Pallets, usingPlaygrounds} from './util'; +import {expect, itSched, itSub, Pallets, usingPlaygrounds} from './util'; import {itEth} from './eth/util'; async function maintenanceEnabled(api: ApiPromise): Promise { @@ -128,7 +128,7 @@ describe('Integration Test: Maintenance Mode', () => { // Unable to mint an RFT when the MM is enabled await expect(rftCollection.mintToken(superuser)) .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/); - + await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.disable', []); expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false; @@ -162,34 +162,38 @@ describe('Integration Test: Maintenance Mode', () => { await expect(helper.balance.transferToSubstrate(bob, superuser.address, 1n)).to.be.fulfilled; }); - itSub.ifWithPallets('MM blocks scheduled calls and the scheduler itself', [Pallets.Scheduler], async ({helper}) => { + itSched.ifWithPallets('MM blocks scheduled calls and the scheduler itself', [Pallets.Scheduler], async (scheduleKind, {helper}) => { const collection = await helper.nft.mintCollection(bob); const nftBeforeMM = await collection.mintToken(bob); const nftDuringMM = await collection.mintToken(bob); const nftAfterMM = await collection.mintToken(bob); - const scheduledIdBeforeMM = '0x' + '0'.repeat(31) + '0'; - const scheduledIdDuringMM = '0x' + '0'.repeat(31) + '1'; - const scheduledIdBunkerThroughMM = '0x' + '0'.repeat(31) + '2'; - const scheduledIdAttemptDuringMM = '0x' + '0'.repeat(31) + '3'; - const scheduledIdAfterMM = '0x' + '0'.repeat(31) + '4'; + const [ + scheduledIdBeforeMM, + scheduledIdDuringMM, + scheduledIdBunkerThroughMM, + scheduledIdAttemptDuringMM, + scheduledIdAfterMM, + ] = scheduleKind == 'named' + ? helper.arrange.makeScheduledIds(5) + : new Array(5); const blocksToWait = 6; // Scheduling works before the maintenance - await nftBeforeMM.scheduleAfter(scheduledIdBeforeMM, blocksToWait) + await nftBeforeMM.scheduleAfter(blocksToWait, {scheduledId: scheduledIdBeforeMM}) .transfer(bob, {Substrate: superuser.address}); await helper.wait.newBlocks(blocksToWait + 1); expect(await nftBeforeMM.getOwner()).to.be.deep.equal({Substrate: superuser.address}); // Schedule a transaction that should occur *during* the maintenance - await nftDuringMM.scheduleAfter(scheduledIdDuringMM, blocksToWait) + await nftDuringMM.scheduleAfter(blocksToWait, {scheduledId: scheduledIdDuringMM}) .transfer(bob, {Substrate: superuser.address}); - + // Schedule a transaction that should occur *after* the maintenance - await nftDuringMM.scheduleAfter(scheduledIdBunkerThroughMM, blocksToWait * 2) + await nftDuringMM.scheduleAfter(blocksToWait * 2, {scheduledId: scheduledIdBunkerThroughMM}) .transfer(bob, {Substrate: superuser.address}); await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []); @@ -200,7 +204,7 @@ describe('Integration Test: Maintenance Mode', () => { expect(await nftDuringMM.getOwner()).to.be.deep.equal({Substrate: bob.address}); // Any attempts to schedule a tx during the MM should be rejected - await expect(nftDuringMM.scheduleAfter(scheduledIdAttemptDuringMM, blocksToWait) + await expect(nftDuringMM.scheduleAfter(blocksToWait, {scheduledId: scheduledIdAttemptDuringMM}) .transfer(bob, {Substrate: superuser.address})) .to.be.rejectedWith(/Invalid Transaction: Transaction call is not expected/); @@ -208,9 +212,9 @@ describe('Integration Test: Maintenance Mode', () => { expect(await maintenanceEnabled(helper.getApi()), 'MM is ON when it should be OFF').to.be.false; // Scheduling works after the maintenance - await nftAfterMM.scheduleAfter(scheduledIdAfterMM, blocksToWait) + await nftAfterMM.scheduleAfter(blocksToWait, {scheduledId: scheduledIdAfterMM}) .transfer(bob, {Substrate: superuser.address}); - + await helper.wait.newBlocks(blocksToWait + 1); expect(await nftAfterMM.getOwner()).to.be.deep.equal({Substrate: superuser.address}); @@ -221,19 +225,19 @@ describe('Integration Test: Maintenance Mode', () => { itEth('Disallows Ethereum transactions to execute while in maintenance', async ({helper}) => { const owner = await helper.eth.createAccountWithBalance(donor); const receiver = helper.eth.createAccount(); - + const {collectionAddress} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'A', 'B', 'C', ''); // Set maintenance mode await helper.getSudo().executeExtrinsic(superuser, 'api.tx.maintenance.enable', []); expect(await maintenanceEnabled(helper.getApi()), 'MM is OFF when it should be ON').to.be.true; - const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner); + const contract = await helper.ethNativeContract.collection(collectionAddress, 'nft', owner); const tokenId = await contract.methods.nextTokenId().call(); expect(tokenId).to.be.equal('1'); await expect(contract.methods.mintWithTokenURI(receiver, 'Test URI').send()) - .to.be.rejectedWith(/submit transaction to pool failed: Pool\(InvalidTransaction\(InvalidTransaction::Call\)\)/); + .to.be.rejectedWith(/Returned error: unknown error/); await expect(contract.methods.ownerOf(tokenId).call()).rejectedWith(/token not found/); diff --git a/tests/src/maintenanceMode.test.ts b/tests/src/maintenanceMode.test.ts deleted file mode 100644 index f97129e755..0000000000 --- a/tests/src/maintenanceMode.test.ts +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. -// This file is part of Unique Network. - -// Unique Network is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Unique Network is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Unique Network. If not, see . - -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import {default as usingApi, executeTransaction, submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api'; -import {createCollection, createItemExpectSuccess, createItemExpectFailure, createCollectionWithPropsExpectSuccess, waitNewBlocks, getTokenOwner, scheduleTransferExpectSuccess} from './util/helpers'; -import {createEthAccount, createEthAccountWithBalance, evmCollection, evmCollectionHelpers, getCollectionAddressFromResult, itWeb3} from './eth/util/helpers'; -import {IKeyringPair} from '@polkadot/types/types'; -import {ApiPromise} from '@polkadot/api'; - -chai.use(chaiAsPromised); -const expect = chai.expect; - -// TODO:maintenance make it into seqtest - -async function maintenanceEnabled(api: ApiPromise): Promise { - return (await api.query.maintenance.enabled()).toJSON(); -} - -describe('Integration Test: Maintenance Mode', () => { - let superuser: IKeyringPair; - let bob: IKeyringPair; - - before(async () => { - await usingApi(async (api, privateKey) => { - superuser = privateKey('//Alice'); - bob = privateKey('//Bob'); - - if (await maintenanceEnabled(api)) { - console.warn('\tMaintenance mode was left enabled BEFORE the test suite! Disabling it now.'); - const sudoTx = api.tx.sudo.sudo(api.tx.maintenance.disable() as any); - await submitTransactionAsync(superuser, sudoTx); - } - }); - }); - - it('Allows superuser to enable and disable maintenance mode - and disallows anyone else', async () => { - await usingApi(async api => { - // Make sure non-sudo can't enable maintenance mode - const txEnable = api.tx.maintenance.enable(); - await expect(submitTransactionExpectFailAsync(bob, txEnable), 'on commoner enabling MM').to.be.rejected; //With(/NoPermission/); - - // Set maintenance mode - await submitTransactionAsync(superuser, api.tx.sudo.sudo(txEnable as any)); - expect(await maintenanceEnabled(api), 'MM is OFF when it should be ON').to.be.true; - - // Make sure non-sudo can't disable maintenance mode - const txDisable = api.tx.maintenance.disable(); - await expect(submitTransactionExpectFailAsync(bob, txDisable), 'on commoner disabling MM').to.be.rejected; //With(/NoPermission/); - - // Disable maintenance mode - await submitTransactionAsync(superuser, api.tx.sudo.sudo(txDisable as any)); - expect(await maintenanceEnabled(api), 'MM is ON when it should be OFF').to.be.false; - }); - }); - - it('MM blocks unique pallet calls', async () => { - await usingApi(async api => { - // Can create an NFT collection before enabling the MM - const nftCollectionId = await expect(createCollectionWithPropsExpectSuccess({ - mode: {type: 'NFT'}, - propPerm: [ - { - key: 'test', - permission: { - collectionAdmin: true, - tokenOwner: true, - mutable: true, - }, - }, - ], - })).to.be.fulfilled; - - // Can mint an NFT before enabling the MM - const nftId = await createItemExpectSuccess(superuser, nftCollectionId, 'NFT'); - - // Can create an FT collection before enabling the MM - const ftCollectionResult = await expect(createCollection(api, superuser, {mode: {type: 'Fungible', decimalPoints: 18}})).to.be.fulfilled; - const ftCollectionId = ftCollectionResult.collectionId; - - // Can mint an FT before enabling the MM - await createItemExpectSuccess(superuser, ftCollectionId, 'Fungible'); - - // Can create an RFT collection before enabling the MM - const rftCollectionResult = await expect(createCollection(api, superuser, {mode: {type: 'ReFungible'}})).to.be.fulfilled; - const rftCollectionId = rftCollectionResult.collectionId; - - // Can mint an RFT before enabling the MM - await createItemExpectSuccess(superuser, rftCollectionId, 'ReFungible'); - - const txEnable = api.tx.maintenance.enable(); - await submitTransactionAsync(superuser, api.tx.sudo.sudo(txEnable as any)); - expect(await maintenanceEnabled(api), 'MM is OFF when it should be ON').to.be.true; - - // Unable to create a collection when the MM is enabled - await expect(createCollection(api, superuser), 'cudo forbidden stuff').to.be.rejected; - - // Unable to set token properties when the MM is enabled - await expect(submitTransactionExpectFailAsync( - superuser, - api.tx.unique.setTokenProperties(nftCollectionId, nftId, [{key: 'test', value: 'test-val'}]), - )).to.be.rejected; - - // Unable to mint an NFT when the MM is enabled - await expect(createItemExpectFailure(superuser, nftCollectionId, 'NFT')).to.be.rejected; - - // Unable to mint an FT when the MM is enabled - await expect(createItemExpectFailure(superuser, ftCollectionId, 'Fungible')).to.be.rejected; - - // Unable to mint an RFT when the MM is enabled - await expect(createItemExpectFailure(superuser, rftCollectionId, 'ReFungible')).to.be.rejected; - - const txDisable = api.tx.maintenance.disable(); - await submitTransactionAsync(superuser, api.tx.sudo.sudo(txDisable as any)); - expect(await maintenanceEnabled(api), 'MM is ON when it should be OFF').to.be.false; - - // Can create a collection after disabling the MM - await expect(createCollection(api, superuser), 'MM is disabled, the collection should be created').to.be.fulfilled; - - // Can set token properties after disabling the MM - await submitTransactionAsync( - superuser, - api.tx.unique.setTokenProperties(nftCollectionId, nftId, [{key: 'test', value: 'test-val'}]), - ); - - // Can mint an NFT after disabling the MM - await createItemExpectSuccess(superuser, nftCollectionId, 'NFT'); - - // Can mint an FT after disabling the MM - await createItemExpectSuccess(superuser, ftCollectionId, 'Fungible'); - - // Can mint an RFT after disabling the MM - await createItemExpectSuccess(superuser, rftCollectionId, 'ReFungible'); - }); - }); - - it('MM allows native token transfers and RPC calls', async () => { - await usingApi(async api => { - // We can use RPC before the MM is enabled - const stats = (await api.rpc.unique.collectionStats()).toJSON(); - - // We can transfer funds before the MM is enabled - await expect(submitTransactionAsync( - superuser, - api.tx.balances.transfer(bob.address, 1n), - )).to.be.fulfilled; - - const txEnable = api.tx.maintenance.enable(); - await submitTransactionAsync(superuser, api.tx.sudo.sudo(txEnable as any)); - expect(await maintenanceEnabled(api), 'MM is OFF when it should be ON').to.be.true; - - // RPCs work while in maintenance - expect((await api.rpc.unique.collectionStats()).toJSON()).to.be.deep.equal(stats); - - // We still able to transfer funds - await expect(submitTransactionAsync( - superuser, - api.tx.balances.transfer(bob.address, 1n), - )).to.be.fulfilled; - - const txDisable = api.tx.maintenance.disable(); - await submitTransactionAsync(superuser, api.tx.sudo.sudo(txDisable as any)); - expect(await maintenanceEnabled(api), 'MM is ON when it should be OFF').to.be.false; - - // RPCs work after maintenance - expect((await api.rpc.unique.collectionStats()).toJSON()).to.be.deep.equal(stats); - - // Transfers work after maintenance - await expect(submitTransactionAsync( - superuser, - api.tx.balances.transfer(bob.address, 1n), - )).to.be.fulfilled; - }); - }); - - it('MM blocks scheduled calls and the scheduler itself', async () => { - await usingApi(async api => { - const collectionResult = await expect(createCollection(api, bob)).to.be.fulfilled; - const collectionId = collectionResult.collectionId; - - const nftBeforeMM = await createItemExpectSuccess(bob, collectionId, 'NFT'); - const nftDuringMM = await createItemExpectSuccess(bob, collectionId, 'NFT'); - const nftAfterMM = await createItemExpectSuccess(bob, collectionId, 'NFT'); - - const scheduledIdBeforeMM = '0x' + '0'.repeat(31) + '0'; - const scheduledIdDuringMM = '0x' + '0'.repeat(31) + '1'; - const scheduledIdAttemptDuringMM = '0x' + '0'.repeat(31) + '2'; - const scheduledIdAfterMM = '0x' + '0'.repeat(31) + '3'; - - const blocksToWait = 6; - - // Scheduling works before the maintenance - await scheduleTransferExpectSuccess( - collectionId, - nftBeforeMM, - bob, - superuser, - 1, - blocksToWait, - scheduledIdBeforeMM, - ); - - await waitNewBlocks(blocksToWait + 1); - - expect(await getTokenOwner(api, collectionId, nftBeforeMM)).to.be.deep.equal({Substrate: superuser.address}); - - // Schedule a transaction that should occur *during* the maintenance - await scheduleTransferExpectSuccess( - collectionId, - nftDuringMM, - bob, - superuser, - 1, - blocksToWait, - scheduledIdDuringMM, - ); - - const txEnable = api.tx.maintenance.enable(); - await executeTransaction(api, superuser, api.tx.sudo.sudo(txEnable as any)); - expect(await maintenanceEnabled(api), 'MM is OFF when it should be ON').to.be.true; - - await waitNewBlocks(blocksToWait + 1); - - // The owner should NOT change since the scheduled transaction should be rejected - expect(await getTokenOwner(api, collectionId, nftDuringMM)).to.be.deep.equal({Substrate: bob.address}); - - // Any attempts to schedule a tx during the MM should be rejected - await expect(scheduleTransferExpectSuccess( - collectionId, - nftDuringMM, - bob, - superuser, - 1, - blocksToWait, - scheduledIdAttemptDuringMM, - )).to.be.rejected; - - const txDisable = api.tx.maintenance.disable(); - await executeTransaction(api, superuser, api.tx.sudo.sudo(txDisable as any)); - expect(await maintenanceEnabled(api), 'MM is ON when it should be OFF').to.be.false; - - // Scheduling works after the maintenance - await scheduleTransferExpectSuccess( - collectionId, - nftAfterMM, - bob, - superuser, - 1, - blocksToWait, - scheduledIdAfterMM, - ); - - await waitNewBlocks(blocksToWait + 1); - - expect(await getTokenOwner(api, collectionId, nftAfterMM)).to.be.deep.equal({Substrate: superuser.address}); - }); - }); - - itWeb3('Disallows Ethereum transactions to execute while in maintenance', async ({api, web3, privateKeyWrapper}) => { - const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); - const receiver = createEthAccount(web3); - const collectionHelper = evmCollectionHelpers(web3, owner); - - const {collectionIdAddress} = await getCollectionAddressFromResult(api, await collectionHelper.methods - .createNonfungibleCollection('A', 'B', 'C') - .send()); - - // Set maintenance mode - await submitTransactionAsync(superuser, api.tx.sudo.sudo(api.tx.maintenance.enable())); - expect(await maintenanceEnabled(api), 'MM is OFF when it should be ON').to.be.true; - - const contract = evmCollection(web3, owner, collectionIdAddress); - const tokenId = await contract.methods.nextTokenId().call(); - expect(tokenId).to.be.equal('1'); - - await expect(contract.methods.mintWithTokenURI( - receiver, - tokenId, - 'Test URI', - ).call({from: owner})); - - await expect(contract.methods.ownerOf(tokenId).call()).rejectedWith(/token not found/); - - // Disable maintenance mode - await submitTransactionAsync(superuser, api.tx.sudo.sudo(api.tx.maintenance.disable())); - expect(await maintenanceEnabled(api), 'MM is ON when it should be OFF').to.be.false; - }); - - it('Allows to enable and disable MM repeatedly', async () => { - await usingApi(async api => { - // Set maintenance mode - const sudoEnalbeTx = api.tx.sudo.sudo(api.tx.maintenance.enable()); - - await submitTransactionAsync(superuser, sudoEnalbeTx); - await submitTransactionAsync(superuser, sudoEnalbeTx); - - expect(await maintenanceEnabled(api), 'MM is OFF when it should be ON').to.be.true; - - // Disable maintenance mode - const sudoDisableTx = api.tx.sudo.sudo(api.tx.maintenance.disable()); - await submitTransactionAsync(superuser, sudoDisableTx); - await submitTransactionAsync(superuser, sudoDisableTx); - expect(await maintenanceEnabled(api), 'MM is ON when it should be OFF').to.be.false; - }); - }); - - afterEach(async () => { - await usingApi(async api => { - if (await maintenanceEnabled(api)) { - console.warn('\tMaintenance mode was left enabled AFTER a test has finished! Be careful. Disabling it now.'); - await submitTransactionAsync(superuser, api.tx.sudo.sudo(api.tx.maintenance.disable())); - } - expect(await maintenanceEnabled(api), 'Disastrous! Exited the test suite with maintenance mode on.').to.be.false; - }); - }); -}); diff --git a/tests/src/nesting/collectionProperties.seqtest.ts b/tests/src/nesting/collectionProperties.seqtest.ts new file mode 100644 index 0000000000..a36944adbd --- /dev/null +++ b/tests/src/nesting/collectionProperties.seqtest.ts @@ -0,0 +1,61 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {IKeyringPair} from '@polkadot/types/types'; +import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip} from '../util'; + +describe('Integration Test: Collection Properties with sudo', () => { + let superuser: IKeyringPair; + let alice: IKeyringPair; + + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + superuser = await privateKey('//Alice'); + const donor = await privateKey({filename: __filename}); + [alice] = await helper.arrange.createAccounts([100n], donor); + }); + }); + + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'ft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => { + before(async function() { + // eslint-disable-next-line require-await + await usingPlaygrounds(async helper => { + requirePalletsOrSkip(this, helper, testSuite.requiredPallets); + }); + }); + + itSub('Repairing an unbroken collection\'s properties preserves the consumed space', async({helper}) => { + const properties = [ + {key: 'sea-creatures', value: 'mermaids'}, + {key: 'goldenratio', value: '1.6180339887498948482045868343656381177203091798057628621354486227052604628189'}, + ]; + const collection = await helper[testSuite.mode].mintCollection(alice, {properties}); + + const newProperty = ' '.repeat(4096); + await collection.setProperties(alice, [{key: 'space', value: newProperty}]); + const originalSpace = await collection.getPropertiesConsumedSpace(); + expect(originalSpace).to.be.equal(properties[0].value.length + properties[1].value.length + newProperty.length); + + await helper.getSudo().executeExtrinsic(superuser, 'api.tx.unique.forceRepairCollection', [collection.collectionId], true); + const recomputedSpace = await collection.getPropertiesConsumedSpace(); + expect(recomputedSpace).to.be.equal(originalSpace); + }); + })); +}); \ No newline at end of file diff --git a/tests/src/nesting/collectionProperties.test.ts b/tests/src/nesting/collectionProperties.test.ts index 2c3222fcf3..2a072cce66 100644 --- a/tests/src/nesting/collectionProperties.test.ts +++ b/tests/src/nesting/collectionProperties.test.ts @@ -15,133 +15,114 @@ // along with Unique Network. If not, see . import {IKeyringPair} from '@polkadot/types/types'; -import {itSub, Pallets, usingPlaygrounds, expect} from '../util'; -import {UniqueBaseCollection} from '../util/playgrounds/unique'; +import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip} from '../util'; describe('Integration Test: Collection Properties', () => { let alice: IKeyringPair; let bob: IKeyringPair; - + before(async () => { await usingPlaygrounds(async (helper, privateKey) => { const donor = await privateKey({filename: __filename}); [alice, bob] = await helper.arrange.createAccounts([200n, 10n], donor); }); }); - + itSub('Properties are initially empty', async ({helper}) => { const collection = await helper.nft.mintCollection(alice); expect(await collection.getProperties()).to.be.empty; }); - - async function testSetsPropertiesForCollection(collection: UniqueBaseCollection) { - // As owner - await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}])).to.be.fulfilled; - - await collection.addAdmin(alice, {Substrate: bob.address}); - - // As administrator - await expect(collection.setProperties(bob, [{key: 'black_hole'}])).to.be.fulfilled; - - const properties = await collection.getProperties(); - expect(properties).to.include.deep.members([ - {key: 'electron', value: 'come bond'}, - {key: 'black_hole', value: ''}, - ]); - } - - itSub('Sets properties for a NFT collection', async ({helper}) => { - await testSetsPropertiesForCollection(await helper.nft.mintCollection(alice)); - }); - - itSub.ifWithPallets('Sets properties for a ReFungible collection', [Pallets.ReFungible], async ({helper}) => { - await testSetsPropertiesForCollection(await helper.rft.mintCollection(alice)); - }); - - async function testCheckValidNames(collection: UniqueBaseCollection) { - // alpha symbols - await expect(collection.setProperties(alice, [{key: 'answer'}])).to.be.fulfilled; - - // numeric symbols - await expect(collection.setProperties(alice, [{key: '451'}])).to.be.fulfilled; - - // underscore symbol - await expect(collection.setProperties(alice, [{key: 'black_hole'}])).to.be.fulfilled; - - // dash symbol - await expect(collection.setProperties(alice, [{key: '-'}])).to.be.fulfilled; - - // dot symbol - await expect(collection.setProperties(alice, [{key: 'once.in.a.long.long.while...', value: 'you get a little lost'}])).to.be.fulfilled; - - const properties = await collection.getProperties(); - expect(properties).to.include.deep.members([ - {key: 'answer', value: ''}, - {key: '451', value: ''}, - {key: 'black_hole', value: ''}, - {key: '-', value: ''}, - {key: 'once.in.a.long.long.while...', value: 'you get a little lost'}, - ]); - } - - itSub('Check valid names for NFT collection properties keys', async ({helper}) => { - await testCheckValidNames(await helper.nft.mintCollection(alice)); - }); - - itSub.ifWithPallets('Check valid names for ReFungible collection properties keys', [Pallets.ReFungible], async ({helper}) => { - await testCheckValidNames(await helper.rft.mintCollection(alice)); - }); - - async function testChangesProperties(collection: UniqueBaseCollection) { - await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: ''}])).to.be.fulfilled; - - // Mutate the properties - await expect(collection.setProperties(alice, [{key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled; - - const properties = await collection.getProperties(); - expect(properties).to.include.deep.members([ - {key: 'electron', value: 'come bond'}, - {key: 'black_hole', value: 'LIGO'}, - ]); - } - - itSub('Changes properties of a NFT collection', async ({helper}) => { - await testChangesProperties(await helper.nft.mintCollection(alice)); - }); - - itSub.ifWithPallets('Changes properties of a ReFungible collection', [Pallets.ReFungible], async ({helper}) => { - await testChangesProperties(await helper.rft.mintCollection(alice)); - }); - - async function testDeleteProperties(collection: UniqueBaseCollection) { - await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled; - - await expect(collection.deleteProperties(alice, ['electron'])).to.be.fulfilled; - - const properties = await collection.getProperties(['black_hole', 'electron']); - expect(properties).to.be.deep.equal([ - {key: 'black_hole', value: 'LIGO'}, - ]); - } - - itSub('Deletes properties of a NFT collection', async ({helper}) => { - await testDeleteProperties(await helper.nft.mintCollection(alice)); - }); - - itSub.ifWithPallets('Deletes properties of a ReFungible collection', [Pallets.ReFungible], async ({helper}) => { - await testDeleteProperties(await helper.rft.mintCollection(alice)); - }); [ - // TODO enable properties for FT collection in Substrate (release 040) - // {mode: 'ft' as const, requiredPallets: []}, {mode: 'nft' as const, requiredPallets: []}, - {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, - ].map(testCase => - itSub.ifWithPallets(`Allows modifying a collection property multiple times with the same size (${testCase.mode})`, testCase.requiredPallets, async({helper}) => { + {mode: 'ft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => { + before(async function() { + // eslint-disable-next-line require-await + await usingPlaygrounds(async helper => { + requirePalletsOrSkip(this, helper, testSuite.requiredPallets); + }); + }); + + itSub('Sets properties for a collection', async ({helper}) => { + const collection = await helper[testSuite.mode].mintCollection(alice); + + // As owner + await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}])).to.be.fulfilled; + + await collection.addAdmin(alice, {Substrate: bob.address}); + + // As administrator + await expect(collection.setProperties(bob, [{key: 'black_hole'}])).to.be.fulfilled; + + const properties = await collection.getProperties(); + expect(properties).to.include.deep.members([ + {key: 'electron', value: 'come bond'}, + {key: 'black_hole', value: ''}, + ]); + }); + + itSub('Check valid names for collection properties keys', async ({helper}) => { + const collection = await helper[testSuite.mode].mintCollection(alice); + + // alpha symbols + await expect(collection.setProperties(alice, [{key: 'answer'}])).to.be.fulfilled; + + // numeric symbols + await expect(collection.setProperties(alice, [{key: '451'}])).to.be.fulfilled; + + // underscore symbol + await expect(collection.setProperties(alice, [{key: 'black_hole'}])).to.be.fulfilled; + + // dash symbol + await expect(collection.setProperties(alice, [{key: '-'}])).to.be.fulfilled; + + // dot symbol + await expect(collection.setProperties(alice, [{key: 'once.in.a.long.long.while...', value: 'you get a little lost'}])).to.be.fulfilled; + + const properties = await collection.getProperties(); + expect(properties).to.include.deep.members([ + {key: 'answer', value: ''}, + {key: '451', value: ''}, + {key: 'black_hole', value: ''}, + {key: '-', value: ''}, + {key: 'once.in.a.long.long.while...', value: 'you get a little lost'}, + ]); + }); + + itSub('Changes properties of a collection', async ({helper}) => { + const collection = await helper[testSuite.mode].mintCollection(alice); + + await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: ''}])).to.be.fulfilled; + + // Mutate the properties + await expect(collection.setProperties(alice, [{key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled; + + const properties = await collection.getProperties(); + expect(properties).to.include.deep.members([ + {key: 'electron', value: 'come bond'}, + {key: 'black_hole', value: 'LIGO'}, + ]); + }); + + itSub('Deletes properties of a collection', async ({helper}) => { + const collection = await helper[testSuite.mode].mintCollection(alice); + + await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled; + + await expect(collection.deleteProperties(alice, ['electron'])).to.be.fulfilled; + + const properties = await collection.getProperties(['black_hole', 'electron']); + expect(properties).to.be.deep.equal([ + {key: 'black_hole', value: 'LIGO'}, + ]); + }); + + itSub('Allows modifying a collection property multiple times with the same size', async({helper}) => { const propKey = 'tok-prop'; - const collection = await helper[testCase.mode].mintCollection(alice); + const collection = await helper[testSuite.mode].mintCollection(alice); const maxCollectionPropertiesSize = 40960; @@ -166,18 +147,12 @@ describe('Integration Test: Collection Properties', () => { const consumedSpace = await collection.getPropertiesConsumedSpace(); expect(consumedSpace).to.be.equal(originalSpace); } - })); + }); - [ - // TODO enable properties for FT collection in Substrate (release 040) - // {mode: 'ft' as const, requiredPallets: []}, - {mode: 'nft' as const, requiredPallets: []}, - {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, - ].map(testCase => - itSub.ifWithPallets(`Adding then removing a collection property doesn't change the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => { + itSub('Adding then removing a collection property doesn\'t change the consumed space', async({helper}) => { const propKey = 'tok-prop'; - const collection = await helper[testCase.mode].mintCollection(alice); + const collection = await helper[testSuite.mode].mintCollection(alice); const originalSpace = await collection.getPropertiesConsumedSpace(); const propDataSize = 4096; @@ -190,18 +165,12 @@ describe('Integration Test: Collection Properties', () => { await collection.deleteProperties(alice, [propKey]); consumedSpace = await collection.getPropertiesConsumedSpace(); expect(consumedSpace).to.be.equal(originalSpace); - })); + }); - [ - // TODO enable properties for FT collection in Substrate (release 040) - // {mode: 'ft' as const, requiredPallets: []}, - {mode: 'nft' as const, requiredPallets: []}, - {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, - ].map(testCase => - itSub.ifWithPallets(`Modifying a collection property with different sizes correctly changes the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => { + itSub('Modifying a collection property with different sizes correctly changes the consumed space', async({helper}) => { const propKey = 'tok-prop'; - const collection = await helper[testCase.mode].mintCollection(alice); + const collection = await helper[testSuite.mode].mintCollection(alice); const originalSpace = await collection.getPropertiesConsumedSpace(); const initPropDataSize = 4096; @@ -229,132 +198,131 @@ describe('Integration Test: Collection Properties', () => { consumedSpace = await collection.getPropertiesConsumedSpace(); expectedConsumedSpaceDiff = biggerPropDataSize - smallerPropDataSize; expect(consumedSpace).to.be.equal(biggerPropDataSize - expectedConsumedSpaceDiff); - })); + }); + })); }); - + describe('Negative Integration Test: Collection Properties', () => { let alice: IKeyringPair; let bob: IKeyringPair; - + before(async () => { await usingPlaygrounds(async (helper, privateKey) => { const donor = await privateKey({filename: __filename}); - [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor); + [alice, bob] = await helper.arrange.createAccounts([1000n, 100n], donor); }); }); - - async function testFailsSetPropertiesIfNotOwnerOrAdmin(collection: UniqueBaseCollection) { - await expect(collection.setProperties(bob, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}])) - .to.be.rejectedWith(/common\.NoPermission/); - - expect(await collection.getProperties()).to.be.empty; - } - - itSub('Fails to set properties in a NFT collection if not its onwer/administrator', async ({helper}) => { - await testFailsSetPropertiesIfNotOwnerOrAdmin(await helper.nft.mintCollection(alice)); - }); - - itSub.ifWithPallets('Fails to set properties in a ReFungible collection if not its onwer/administrator', [Pallets.ReFungible], async ({helper}) => { - await testFailsSetPropertiesIfNotOwnerOrAdmin(await helper.rft.mintCollection(alice)); - }); - - async function testFailsSetPropertiesThatExeedLimits(collection: UniqueBaseCollection) { - const spaceLimit = (await (collection.helper!.api! as any).query.common.collectionProperties(collection.collectionId)).spaceLimit.toNumber(); - - // Mute the general tx parsing error, too many bytes to process - { - console.error = () => {}; - await expect(collection.setProperties(alice, [ - {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}, - ])).to.be.rejected; - } - - expect(await collection.getProperties(['electron'])).to.be.empty; - - await expect(collection.setProperties(alice, [ - {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 18))}, - {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))}, - ])).to.be.rejectedWith(/common\.NoSpaceForProperty/); - - expect(await collection.getProperties(['electron', 'black_hole'])).to.be.empty; - } - - itSub('Fails to set properties that exceed the limits (NFT)', async ({helper}) => { - await testFailsSetPropertiesThatExeedLimits(await helper.nft.mintCollection(alice)); - }); - - itSub.ifWithPallets('Fails to set properties that exceed the limits (ReFungible)', [Pallets.ReFungible], async ({helper}) => { - await testFailsSetPropertiesThatExeedLimits(await helper.rft.mintCollection(alice)); - }); - - async function testFailsSetMorePropertiesThanAllowed(collection: UniqueBaseCollection) { - const propertiesToBeSet = []; - for (let i = 0; i < 65; i++) { - propertiesToBeSet.push({ - key: 'electron_' + i, - value: Math.random() > 0.5 ? 'high' : 'low', + + [ + {mode: 'nft' as const, requiredPallets: []}, + {mode: 'ft' as const, requiredPallets: []}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => { + before(async function() { + // eslint-disable-next-line require-await + await usingPlaygrounds(async helper => { + requirePalletsOrSkip(this, helper, testSuite.requiredPallets); }); - } - - await expect(collection.setProperties(alice, propertiesToBeSet)). - to.be.rejectedWith(/common\.PropertyLimitReached/); - - expect(await collection.getProperties()).to.be.empty; - } - - itSub('Fails to set more properties than it is allowed (NFT)', async ({helper}) => { - await testFailsSetMorePropertiesThanAllowed(await helper.nft.mintCollection(alice)); - }); - - itSub.ifWithPallets('Fails to set more properties than it is allowed (ReFungible)', [Pallets.ReFungible], async ({helper}) => { - await testFailsSetMorePropertiesThanAllowed(await helper.rft.mintCollection(alice)); - }); - - async function testFailsSetPropertiesWithInvalidNames(collection: UniqueBaseCollection) { - const invalidProperties = [ - [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}], - [{key: 'Mr/Sandman', value: 'Bring me a gene'}], - [{key: 'déjà vu', value: 'hmm...'}], - ]; - - for (let i = 0; i < invalidProperties.length; i++) { + }); + + itSub('Fails to set properties in a collection if not its onwer/administrator', async ({helper}) => { + const collection = await helper[testSuite.mode].mintCollection(alice); + + await expect(collection.setProperties(bob, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}])) + .to.be.rejectedWith(/common\.NoPermission/); + + expect(await collection.getProperties()).to.be.empty; + }); + + itSub('Fails to set properties that exceed the limits', async ({helper}) => { + const collection = await helper[testSuite.mode].mintCollection(alice); + + const spaceLimit = (await (collection.helper!.api! as any).query.common.collectionProperties(collection.collectionId)).spaceLimit.toNumber(); + + // Mute the general tx parsing error, too many bytes to process + { + console.error = () => {}; + await expect(collection.setProperties(alice, [ + {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}, + ])).to.be.rejected; + } + + expect(await collection.getProperties(['electron'])).to.be.empty; + + await expect(collection.setProperties(alice, [ + {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 18))}, + {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))}, + ])).to.be.rejectedWith(/common\.NoSpaceForProperty/); + + expect(await collection.getProperties(['electron', 'black_hole'])).to.be.empty; + }); + + itSub('Fails to set more properties than it is allowed', async ({helper}) => { + const collection = await helper[testSuite.mode].mintCollection(alice); + + const propertiesToBeSet = []; + for (let i = 0; i < 65; i++) { + propertiesToBeSet.push({ + key: 'electron_' + i, + value: Math.random() > 0.5 ? 'high' : 'low', + }); + } + + await expect(collection.setProperties(alice, propertiesToBeSet)). + to.be.rejectedWith(/common\.PropertyLimitReached/); + + expect(await collection.getProperties()).to.be.empty; + }); + + itSub('Fails to set properties with invalid names', async ({helper}) => { + const collection = await helper[testSuite.mode].mintCollection(alice); + + const invalidProperties = [ + [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}], + [{key: 'Mr/Sandman', value: 'Bring me a gene'}], + [{key: 'déjà vu', value: 'hmm...'}], + ]; + + for (let i = 0; i < invalidProperties.length; i++) { + await expect( + collection.setProperties(alice, invalidProperties[i]), + `on rejecting the new badly-named property #${i}`, + ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/); + } + await expect( - collection.setProperties(alice, invalidProperties[i]), - `on rejecting the new badly-named property #${i}`, - ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/); - } - - await expect( - collection.setProperties(alice, [{key: '', value: 'nothing must not exist'}]), - 'on rejecting an unnamed property', - ).to.be.rejectedWith(/common\.EmptyPropertyKey/); - - await expect( - collection.setProperties(alice, [{key: 'CRISPR-Cas9', value: 'rewriting nature!'}]), - 'on setting the correctly-but-still-badly-named property', - ).to.be.fulfilled; - - const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat(''); - - const properties = await collection.getProperties(keys); - expect(properties).to.be.deep.equal([ - {key: 'CRISPR-Cas9', value: 'rewriting nature!'}, - ]); - - for (let i = 0; i < invalidProperties.length; i++) { + collection.setProperties(alice, [{key: '', value: 'nothing must not exist'}]), + 'on rejecting an unnamed property', + ).to.be.rejectedWith(/common\.EmptyPropertyKey/); + await expect( - collection.deleteProperties(alice, invalidProperties[i].map(propertySet => propertySet.key)), - `on trying to delete the non-existent badly-named property #${i}`, - ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/); - } - } - - itSub('Fails to set properties with invalid names (NFT)', async ({helper}) => { - await testFailsSetPropertiesWithInvalidNames(await helper.nft.mintCollection(alice)); - }); - - itSub.ifWithPallets('Fails to set properties with invalid names (ReFungible)', [Pallets.ReFungible], async ({helper}) => { - await testFailsSetPropertiesWithInvalidNames(await helper.rft.mintCollection(alice)); - }); + collection.setProperties(alice, [{key: 'CRISPR-Cas9', value: 'rewriting nature!'}]), + 'on setting the correctly-but-still-badly-named property', + ).to.be.fulfilled; + + const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat(''); + + const properties = await collection.getProperties(keys); + expect(properties).to.be.deep.equal([ + {key: 'CRISPR-Cas9', value: 'rewriting nature!'}, + ]); + + for (let i = 0; i < invalidProperties.length; i++) { + await expect( + collection.deleteProperties(alice, invalidProperties[i].map(propertySet => propertySet.key)), + `on trying to delete the non-existent badly-named property #${i}`, + ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/); + } + }); + + itSub('Forbids to repair a collection if called with non-sudo', async({helper}) => { + const collection = await helper[testSuite.mode].mintCollection(alice, {properties: [ + {key: 'sea-creatures', value: 'mermaids'}, + {key: 'goldenratio', value: '1.6180339887498948482045868343656381177203091798057628621354486227052604628189'}, + ]}); + + await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairCollection', [collection.collectionId], true)) + .to.be.rejectedWith(/BadOrigin/); + }); + })); }); - \ No newline at end of file diff --git a/tests/src/nesting/graphs.test.ts b/tests/src/nesting/graphs.test.ts index b6c3ad7538..a0c5fc996f 100644 --- a/tests/src/nesting/graphs.test.ts +++ b/tests/src/nesting/graphs.test.ts @@ -56,7 +56,7 @@ describe('Graphs', () => { // to self await expect( tokens[0].nest(alice, tokens[0]), - 'first transaction', + 'first transaction', ).to.be.rejectedWith(/structure\.OuroborosDetected/); // to nested part of graph await expect( diff --git a/tests/src/nesting/nest.test.ts b/tests/src/nesting/nest.test.ts index be20a96c4e..bb813e2bcf 100644 --- a/tests/src/nesting/nest.test.ts +++ b/tests/src/nesting/nest.test.ts @@ -36,7 +36,7 @@ describe('Integration Test: Composite nesting tests', () => { const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount()); expect(await nestedToken.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address}); expect(await nestedToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase()); - + // Create a token to be nested const newToken = await collection.mintToken(alice); @@ -66,7 +66,7 @@ describe('Integration Test: Composite nesting tests', () => { // Create a nested token const tokenC = await collection.mintToken(alice, tokenA.nestingAccount()); expect(await tokenC.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase()); - + // Transfer the nested token to another token await expect(tokenC.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount())).to.be.fulfilled; expect(await tokenC.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address}); @@ -76,7 +76,7 @@ describe('Integration Test: Composite nesting tests', () => { itSub('Checks token children', async ({helper}) => { const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}}); const collectionB = await helper.ft.mintCollection(alice); - + const targetToken = await collectionA.mintToken(alice); expect((await targetToken.getChildren()).length).to.be.equal(0, 'Children length check at creation'); @@ -108,7 +108,7 @@ describe('Integration Test: Composite nesting tests', () => { {tokenId: 0, collectionId: collectionB.collectionId}, ], 'Children contents check at nesting #4 (from another collection)') .and.be.length(2, 'Children length check at nesting #4 (from another collection)'); - + // Move part of the fungible token inside token A deeper in the nesting tree await collectionB.transferFrom(alice, targetToken.nestingAccount(), tokenA.nestingAccount(), 1n); expect(await targetToken.getChildren()).to.be.have.deep.members([ diff --git a/tests/src/nesting/propertyPermissions.test.ts b/tests/src/nesting/propertyPermissions.test.ts index b8bd0cd818..4ad305a82f 100644 --- a/tests/src/nesting/propertyPermissions.test.ts +++ b/tests/src/nesting/propertyPermissions.test.ts @@ -21,94 +21,94 @@ import {UniqueNFTCollection, UniqueRFTCollection} from '../util/playgrounds/uniq describe('Integration Test: Access Rights to Token Properties', () => { let alice: IKeyringPair; let bob: IKeyringPair; - + before(async () => { await usingPlaygrounds(async (helper, privateKey) => { const donor = await privateKey({filename: __filename}); [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor); }); }); - + itSub('Reads access rights to properties of a collection', async ({helper}) => { const collection = await helper.nft.mintCollection(alice); const propertyRights = (await helper.callRpc('api.query.common.collectionPropertyPermissions', [collection.collectionId])).toJSON(); expect(propertyRights).to.be.empty; }); - - async function testSetsAccessRightsToProperties(collection: UniqueNFTCollection | UniqueRFTCollection) { + + async function testSetsAccessRightsToProperties(collection: UniqueNFTCollection | UniqueRFTCollection) { await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true}}])) .to.be.fulfilled; - + await collection.addAdmin(alice, {Substrate: bob.address}); - + await expect(collection.setTokenPropertyPermissions(bob, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}])) .to.be.fulfilled; - + const propertyRights = await collection.getPropertyPermissions(['skullduggery', 'mindgame']); expect(propertyRights).to.include.deep.members([ {key: 'skullduggery', permission: {mutable: true, collectionAdmin: false, tokenOwner: false}}, {key: 'mindgame', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}}, ]); } - + itSub('Sets access rights to properties of a collection (NFT)', async ({helper}) => { await testSetsAccessRightsToProperties(await helper.nft.mintCollection(alice)); }); - + itSub.ifWithPallets('Sets access rights to properties of a collection (ReFungible)', [Pallets.ReFungible], async ({helper}) => { await testSetsAccessRightsToProperties(await helper.rft.mintCollection(alice)); }); - + async function testChangesAccessRightsToProperty(collection: UniqueNFTCollection | UniqueRFTCollection) { await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}])) .to.be.fulfilled; - + await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}])) .to.be.fulfilled; - + const propertyRights = await collection.getPropertyPermissions(); expect(propertyRights).to.be.deep.equal([ {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}}, ]); } - + itSub('Changes access rights to properties of a NFT collection', async ({helper}) => { await testChangesAccessRightsToProperty(await helper.nft.mintCollection(alice)); }); - + itSub.ifWithPallets('Changes access rights to properties of a ReFungible collection', [Pallets.ReFungible], async ({helper}) => { await testChangesAccessRightsToProperty(await helper.rft.mintCollection(alice)); }); }); - + describe('Negative Integration Test: Access Rights to Token Properties', () => { let alice: IKeyringPair; let bob: IKeyringPair; - + before(async () => { await usingPlaygrounds(async (helper, privateKey) => { const donor = await privateKey({filename: __filename}); [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor); }); }); - + async function testPreventsFromSettingAccessRightsNotAdminOrOwner(collection: UniqueNFTCollection | UniqueRFTCollection) { await expect(collection.setTokenPropertyPermissions(bob, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}])) .to.be.rejectedWith(/common\.NoPermission/); - + const propertyRights = await collection.getPropertyPermissions(['skullduggery']); expect(propertyRights).to.be.empty; } - + itSub('Prevents from setting access rights to properties of a NFT collection if not an onwer/admin', async ({helper}) => { await testPreventsFromSettingAccessRightsNotAdminOrOwner(await helper.nft.mintCollection(alice)); }); - + itSub.ifWithPallets('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', [Pallets.ReFungible], async ({helper}) => { await testPreventsFromSettingAccessRightsNotAdminOrOwner(await helper.rft.mintCollection(alice)); }); - - async function testPreventFromAddingTooManyPossibleProperties(collection: UniqueNFTCollection | UniqueRFTCollection) { + + async function testPreventFromAddingTooManyPossibleProperties(collection: UniqueNFTCollection | UniqueRFTCollection) { const constitution = []; for (let i = 0; i < 65; i++) { constitution.push({ @@ -116,82 +116,82 @@ describe('Negative Integration Test: Access Rights to Token Properties', () => { permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {}, }); } - + await expect(collection.setTokenPropertyPermissions(alice, constitution)) .to.be.rejectedWith(/common\.PropertyLimitReached/); - + const propertyRights = await collection.getPropertyPermissions(); expect(propertyRights).to.be.empty; } - + itSub('Prevents from adding too many possible properties (NFT)', async ({helper}) => { await testPreventFromAddingTooManyPossibleProperties(await helper.nft.mintCollection(alice)); }); - + itSub.ifWithPallets('Prevents from adding too many possible properties (ReFungible)', [Pallets.ReFungible], async ({helper}) => { await testPreventFromAddingTooManyPossibleProperties(await helper.rft.mintCollection(alice)); }); - + async function testPreventAccessRightsModifiedIfConstant(collection: UniqueNFTCollection | UniqueRFTCollection) { await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}])) .to.be.fulfilled; - + await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {collectionAdmin: true}}])) .to.be.rejectedWith(/common\.NoPermission/); - + const propertyRights = await collection.getPropertyPermissions(['skullduggery']); expect(propertyRights).to.deep.equal([ {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}}, ]); } - + itSub('Prevents access rights to be modified if constant (NFT)', async ({helper}) => { await testPreventAccessRightsModifiedIfConstant(await helper.nft.mintCollection(alice)); }); - + itSub.ifWithPallets('Prevents access rights to be modified if constant (ReFungible)', [Pallets.ReFungible], async ({helper}) => { await testPreventAccessRightsModifiedIfConstant(await helper.rft.mintCollection(alice)); }); - + async function testPreventsAddingPropertiesWithInvalidNames(collection: UniqueNFTCollection | UniqueRFTCollection) { const invalidProperties = [ [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}], [{key: 'G#4', permission: {tokenOwner: true}}], [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}], ]; - + for (let i = 0; i < invalidProperties.length; i++) { await expect( - collection.setTokenPropertyPermissions(alice, invalidProperties[i]), + collection.setTokenPropertyPermissions(alice, invalidProperties[i]), `on setting the new badly-named property #${i}`, ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/); } - + await expect( - collection.setTokenPropertyPermissions(alice, [{key: '', permission: {}}]), + collection.setTokenPropertyPermissions(alice, [{key: '', permission: {}}]), 'on rejecting an unnamed property', ).to.be.rejectedWith(/common\.EmptyPropertyKey/); - + const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string await expect( collection.setTokenPropertyPermissions(alice, [ {key: correctKey, permission: {collectionAdmin: true}}, - ]), + ]), 'on setting the correctly-but-still-badly-named property', ).to.be.fulfilled; - + const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat(''); - + const propertyRights = await collection.getPropertyPermissions(keys); expect(propertyRights).to.be.deep.equal([ {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}}, ]); } - + itSub('Prevents adding properties with invalid names (NFT)', async ({helper}) => { await testPreventsAddingPropertiesWithInvalidNames(await helper.nft.mintCollection(alice)); }); - + itSub.ifWithPallets('Prevents adding properties with invalid names (ReFungible)', [Pallets.ReFungible], async ({helper}) => { await testPreventsAddingPropertiesWithInvalidNames(await helper.rft.mintCollection(alice)); }); diff --git a/tests/src/nesting/tokenProperties.seqtest.ts b/tests/src/nesting/tokenProperties.seqtest.ts new file mode 100644 index 0000000000..df23e9b9f5 --- /dev/null +++ b/tests/src/nesting/tokenProperties.seqtest.ts @@ -0,0 +1,72 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {IKeyringPair} from '@polkadot/types/types'; +import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip} from '../util'; + +describe('Integration Test: Token Properties with sudo', () => { + let superuser: IKeyringPair; + let alice: IKeyringPair; // collection owner + + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + superuser = await privateKey('//Alice'); + const donor = await privateKey({filename: __filename}); + [alice] = await helper.arrange.createAccounts([100n], donor); + }); + }); + + [ + {mode: 'nft' as const, pieces: undefined, requiredPallets: []}, + {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]}, + ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => { + before(async function() { + // eslint-disable-next-line require-await + await usingPlaygrounds(async helper => { + requirePalletsOrSkip(this, helper, testSuite.requiredPallets); + }); + }); + + itSub('force_repair_item preserves valid consumed space', async({helper}) => { + const propKey = 'tok-prop'; + + const collection = await helper[testSuite.mode].mintCollection(alice, { + tokenPropertyPermissions: [ + { + key: propKey, + permission: {mutable: true, tokenOwner: true}, + }, + ], + }); + const token = await ( + testSuite.pieces + ? collection.mintToken(alice, testSuite.pieces) + : collection.mintToken(alice) + ); + + const propDataSize = 4096; + const propData = 'a'.repeat(propDataSize); + + await token.setProperties(alice, [{key: propKey, value: propData}]); + const originalSpace = await token.getTokenPropertiesConsumedSpace(); + expect(originalSpace).to.be.equal(propDataSize); + + await helper.getSudo().executeExtrinsic(superuser, 'api.tx.unique.forceRepairItem', [token.collectionId, token.tokenId], true); + const recomputedSpace = await token.getTokenPropertiesConsumedSpace(); + expect(recomputedSpace).to.be.equal(originalSpace); + }); + })); +}); \ No newline at end of file diff --git a/tests/src/nesting/tokenProperties.test.ts b/tests/src/nesting/tokenProperties.test.ts index 5bee3bc97a..f2f021c569 100644 --- a/tests/src/nesting/tokenProperties.test.ts +++ b/tests/src/nesting/tokenProperties.test.ts @@ -43,12 +43,12 @@ describe('Integration Test: Token Properties', () => { async function mintCollectionWithAllPermissionsAndToken(helper: UniqueHelper, mode: 'NFT' | 'RFT'): Promise<[UniqueNFToken | UniqueRFToken, bigint]> { const collection = await (mode == 'NFT' ? helper.nft : helper.rft).mintCollection(alice, { - tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) => + tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) => signers.map(signer => {return {key: `${i+1}_${signer.address}`, permission};})), }); return mode == 'NFT' ? [await collection.mintToken(alice), 1n] : [await collection.mintToken(alice, 100n), 100n]; } - + async function testReadsYetEmptyProperties(token: UniqueNFToken | UniqueRFToken) { const properties = await token.getProperties(); expect(properties).to.be.empty; @@ -84,7 +84,7 @@ describe('Integration Test: Token Properties', () => { propertyKeys.push(key); await expect( - token.setProperties(signer, [{key: key, value: 'Serotonin increase'}]), + token.setProperties(signer, [{key: key, value: 'Serotonin increase'}]), `on adding property #${i} by signer #${j}`, ).to.be.fulfilled; } @@ -117,7 +117,7 @@ describe('Integration Test: Token Properties', () => { for (const permission of permissions) { i++; if (!permission.permission.mutable) continue; - + let j = 0; for (const signer of permission.signers) { j++; @@ -125,12 +125,12 @@ describe('Integration Test: Token Properties', () => { propertyKeys.push(key); await expect( - token.setProperties(signer, [{key, value: 'Serotonin increase'}]), + token.setProperties(signer, [{key, value: 'Serotonin increase'}]), `on adding property #${i} by signer #${j}`, ).to.be.fulfilled; await expect( - token.setProperties(signer, [{key, value: 'Serotonin stable'}]), + token.setProperties(signer, [{key, value: 'Serotonin stable'}]), `on changing property #${i} by signer #${j}`, ).to.be.fulfilled; } @@ -164,7 +164,7 @@ describe('Integration Test: Token Properties', () => { for (const permission of permissions) { i++; if (!permission.permission.mutable) continue; - + let j = 0; for (const signer of permission.signers) { j++; @@ -172,12 +172,12 @@ describe('Integration Test: Token Properties', () => { propertyKeys.push(key); await expect( - token.setProperties(signer, [{key, value: 'Serotonin increase'}]), + token.setProperties(signer, [{key, value: 'Serotonin increase'}]), `on adding property #${i} by signer #${j}`, ).to.be.fulfilled; await expect( - token.deleteProperties(signer, [key]), + token.deleteProperties(signer, [key]), `on deleting property #${i} by signer #${j}`, ).to.be.fulfilled; } @@ -186,7 +186,7 @@ describe('Integration Test: Token Properties', () => { expect(await token.getProperties(propertyKeys)).to.be.empty; expect((await token.getData())!.properties).to.be.empty; } - + itSub('Deletes properties of a token according to permissions (NFT)', async ({helper}) => { const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT'); await testDeletePropertiesAccordingPermission(token, amount); @@ -200,7 +200,7 @@ describe('Integration Test: Token Properties', () => { itSub('Assigns properties to a nested token according to permissions', async ({helper}) => { const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}}); const collectionB = await helper.nft.mintCollection(alice, { - tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) => + tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) => signers.map(signer => {return {key: `${i+1}_${signer.address}`, permission};})), }); const targetToken = await collectionA.mintToken(alice); @@ -220,7 +220,7 @@ describe('Integration Test: Token Properties', () => { propertyKeys.push(key); await expect( - nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]), + nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]), `on adding property #${i} by signer #${j}`, ).to.be.fulfilled; } @@ -238,7 +238,7 @@ describe('Integration Test: Token Properties', () => { itSub('Changes properties of a nested token according to permissions', async ({helper}) => { const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}}); const collectionB = await helper.nft.mintCollection(alice, { - tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) => + tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) => signers.map(signer => {return {key: `${i+1}_${signer.address}`, permission};})), }); const targetToken = await collectionA.mintToken(alice); @@ -252,7 +252,7 @@ describe('Integration Test: Token Properties', () => { for (const permission of permissions) { i++; if (!permission.permission.mutable) continue; - + let j = 0; for (const signer of permission.signers) { j++; @@ -260,12 +260,12 @@ describe('Integration Test: Token Properties', () => { propertyKeys.push(key); await expect( - nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]), + nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]), `on adding property #${i} by signer #${j}`, ).to.be.fulfilled; await expect( - nestedToken.setProperties(signer, [{key, value: 'Serotonin stable'}]), + nestedToken.setProperties(signer, [{key, value: 'Serotonin stable'}]), `on changing property #${i} by signer #${j}`, ).to.be.fulfilled; } @@ -283,7 +283,7 @@ describe('Integration Test: Token Properties', () => { itSub('Deletes properties of a nested token according to permissions', async ({helper}) => { const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}}); const collectionB = await helper.nft.mintCollection(alice, { - tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) => + tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) => signers.map(signer => {return {key: `${i+1}_${signer.address}`, permission};})), }); const targetToken = await collectionA.mintToken(alice); @@ -297,7 +297,7 @@ describe('Integration Test: Token Properties', () => { for (const permission of permissions) { i++; if (!permission.permission.mutable) continue; - + let j = 0; for (const signer of permission.signers) { j++; @@ -305,12 +305,12 @@ describe('Integration Test: Token Properties', () => { propertyKeys.push(key); await expect( - nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]), + nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]), `on adding property #${i} by signer #${j}`, ).to.be.fulfilled; await expect( - nestedToken.deleteProperties(signer, [key]), + nestedToken.deleteProperties(signer, [key]), `on deleting property #${i} by signer #${j}`, ).to.be.fulfilled; } @@ -323,7 +323,7 @@ describe('Integration Test: Token Properties', () => { [ {mode: 'nft' as const, storage: 'nonfungible' as const, pieces: undefined, requiredPallets: []}, - {mode: 'rft' as const, storage: 'refungible' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]}, + {mode: 'rft' as const, storage: 'refungible' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]}, ].map(testCase => itSub.ifWithPallets(`Allows modifying a token property multiple times with the same size (${testCase.mode})`, testCase.requiredPallets, async({helper}) => { const propKey = 'tok-prop'; @@ -370,7 +370,7 @@ describe('Integration Test: Token Properties', () => { [ {mode: 'nft' as const, pieces: undefined, requiredPallets: []}, - {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]}, + {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]}, ].map(testCase => itSub.ifWithPallets(`Adding then removing a token property doesn't change the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => { const propKey = 'tok-prop'; @@ -404,40 +404,7 @@ describe('Integration Test: Token Properties', () => { [ {mode: 'nft' as const, pieces: undefined, requiredPallets: []}, - {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]}, - ].map(testCase => - itSub.ifWithPallets(`repair_item preserves valid consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => { - const propKey = 'tok-prop'; - - const collection = await helper[testCase.mode].mintCollection(alice, { - tokenPropertyPermissions: [ - { - key: propKey, - permission: {mutable: true, tokenOwner: true}, - }, - ], - }); - const token = await ( - testCase.pieces - ? collection.mintToken(alice, testCase.pieces) - : collection.mintToken(alice) - ); - - const propDataSize = 4096; - const propData = 'a'.repeat(propDataSize); - - await token.setProperties(alice, [{key: propKey, value: propData}]); - const originalSpace = await token.getTokenPropertiesConsumedSpace(); - expect(originalSpace).to.be.equal(propDataSize); - - await helper.executeExtrinsic(alice, 'api.tx.unique.repairItem', [token.collectionId, token.tokenId], true); - const recomputedSpace = await token.getTokenPropertiesConsumedSpace(); - expect(recomputedSpace).to.be.equal(originalSpace); - })); - - [ - {mode: 'nft' as const, pieces: undefined, requiredPallets: []}, - {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]}, + {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]}, ].map(testCase => itSub.ifWithPallets(`Modifying a token property with different sizes correctly changes the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => { const propKey = 'tok-prop'; @@ -530,12 +497,12 @@ describe('Negative Integration Test: Token Properties', () => { i++; const signer = passage.signers[0]; await expect( - token.setProperties(signer, [{key: `${i}`, value: 'Serotonin increase'}]), + token.setProperties(signer, [{key: `${i}`, value: 'Serotonin increase'}]), `on adding property ${i} by ${signer.address}`, ).to.be.fulfilled; } - const originalSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); + const originalSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); return originalSpace; } @@ -548,17 +515,17 @@ describe('Negative Integration Test: Token Properties', () => { if (!forbiddance.permission.mutable) continue; await expect( - token.setProperties(forbiddance.sinner, [{key: `${i}`, value: 'Serotonin down'}]), + token.setProperties(forbiddance.sinner, [{key: `${i}`, value: 'Serotonin down'}]), `on failing to change property ${i} by the malefactor`, ).to.be.rejectedWith(/common\.NoPermission/); await expect( - token.deleteProperties(forbiddance.sinner, [`${i}`]), + token.deleteProperties(forbiddance.sinner, [`${i}`]), `on failing to delete property ${i} by the malefactor`, ).to.be.rejectedWith(/common\.NoPermission/); } - const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); + const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); expect(consumedSpace).to.be.equal(originalSpace); } @@ -581,17 +548,17 @@ describe('Negative Integration Test: Token Properties', () => { if (permission.permission.mutable) continue; await expect( - token.setProperties(permission.signers[0], [{key: `${i}`, value: 'Serotonin down'}]), + token.setProperties(permission.signers[0], [{key: `${i}`, value: 'Serotonin down'}]), `on failing to change property ${i} by signer #0`, ).to.be.rejectedWith(/common\.NoPermission/); await expect( - token.deleteProperties(permission.signers[0], [i.toString()]), + token.deleteProperties(permission.signers[0], [i.toString()]), `on failing to delete property ${i} by signer #0`, ).to.be.rejectedWith(/common\.NoPermission/); } - - const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); + + const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); expect(consumedSpace).to.be.equal(originalSpace); } @@ -609,23 +576,23 @@ describe('Negative Integration Test: Token Properties', () => { const originalSpace = await prepare(token, pieces); await expect( - token.setProperties(alice, [{key: 'non-existent', value: 'I exist!'}]), + token.setProperties(alice, [{key: 'non-existent', value: 'I exist!'}]), 'on failing to add a previously non-existent property', ).to.be.rejectedWith(/common\.NoPermission/); - + await expect( - token.collection.setTokenPropertyPermissions(alice, [{key: 'now-existent', permission: {}}]), + token.collection.setTokenPropertyPermissions(alice, [{key: 'now-existent', permission: {}}]), 'on setting a new non-permitted property', ).to.be.fulfilled; await expect( - token.setProperties(alice, [{key: 'now-existent', value: 'I exist!'}]), + token.setProperties(alice, [{key: 'now-existent', value: 'I exist!'}]), 'on failing to add a property forbidden by the \'None\' permission', ).to.be.rejectedWith(/common\.NoPermission/); expect(await token.getProperties(['non-existent', 'now-existent'])).to.be.empty; - - const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); + + const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); expect(consumedSpace).to.be.equal(originalSpace); } @@ -644,9 +611,9 @@ describe('Negative Integration Test: Token Properties', () => { await expect( token.collection.setTokenPropertyPermissions(alice, [ - {key: 'a_holy_book', permission: {collectionAdmin: true, tokenOwner: true}}, + {key: 'a_holy_book', permission: {collectionAdmin: true, tokenOwner: true}}, {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}}, - ]), + ]), 'on setting new permissions for properties', ).to.be.fulfilled; @@ -658,12 +625,12 @@ describe('Negative Integration Test: Token Properties', () => { } await expect(token.setProperties(alice, [ - {key: 'a_holy_book', value: 'word '.repeat(3277)}, + {key: 'a_holy_book', value: 'word '.repeat(3277)}, {key: 'young_years', value: 'neverending'.repeat(1490)}, ])).to.be.rejectedWith(/common\.NoSpaceForProperty/); - + expect(await token.getProperties(['a_holy_book', 'young_years'])).to.be.empty; - const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); + const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT'); expect(consumedSpace).to.be.equal(originalSpace); } @@ -679,7 +646,7 @@ describe('Negative Integration Test: Token Properties', () => { [ {mode: 'nft' as const, requiredPallets: []}, - {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, + {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]}, ].map(testCase => itSub.ifWithPallets(`Forbids adding too many propeties to a token (${testCase.mode})`, testCase.requiredPallets, async({helper}) => { const collection = await helper[testCase.mode].mintCollection(alice); @@ -697,6 +664,35 @@ describe('Negative Integration Test: Token Properties', () => { permission: {mutable: true, tokenOwner: true, collectionAdmin: true}, }])).to.be.rejectedWith(/common\.PropertyLimitReached/); })); + + [ + {mode: 'nft' as const, pieces: undefined, requiredPallets: []}, + {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]}, + ].map(testCase => + itSub.ifWithPallets(`Forbids force_repair_item from non-sudo (${testCase.mode})`, testCase.requiredPallets, async({helper}) => { + const propKey = 'tok-prop'; + + const collection = await helper[testCase.mode].mintCollection(alice, { + tokenPropertyPermissions: [ + { + key: propKey, + permission: {mutable: true, tokenOwner: true}, + }, + ], + }); + const token = await ( + testCase.pieces + ? collection.mintToken(alice, testCase.pieces) + : collection.mintToken(alice) + ); + + const propDataSize = 4096; + const propData = 'a'.repeat(propDataSize); + await token.setProperties(alice, [{key: propKey, value: propData}]); + + await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairItem', [token.collectionId, token.tokenId], true)) + .to.be.rejectedWith(/BadOrigin/); + })); }); describe('ReFungible token properties permissions tests', () => { @@ -716,10 +712,10 @@ describe('ReFungible token properties permissions tests', () => { async function prepare(helper: UniqueHelper): Promise { const collection = await helper.rft.mintCollection(alice); const token = await collection.mintToken(alice, 100n); - + await collection.addAdmin(alice, {Substrate: bob.address}); await collection.setTokenPropertyPermissions(alice, [{key: 'fractals', permission: {mutable: true, tokenOwner: true}}]); - + return token; } @@ -729,7 +725,7 @@ describe('ReFungible token properties permissions tests', () => { await token.transfer(alice, {Substrate: charlie.address}, 33n); await expect(token.setProperties(alice, [ - {key: 'fractals', value: 'multiverse'}, + {key: 'fractals', value: 'multiverse'}, ])).to.be.rejectedWith(/common\.NoPermission/); }); @@ -740,13 +736,13 @@ describe('ReFungible token properties permissions tests', () => { .to.be.fulfilled; await expect(token.setProperties(alice, [ - {key: 'fractals', value: 'multiverse'}, + {key: 'fractals', value: 'multiverse'}, ])).to.be.fulfilled; await token.transfer(alice, {Substrate: charlie.address}, 33n); await expect(token.setProperties(alice, [ - {key: 'fractals', value: 'want to rule the world'}, + {key: 'fractals', value: 'want to rule the world'}, ])).to.be.rejectedWith(/common\.NoPermission/); }); @@ -754,7 +750,7 @@ describe('ReFungible token properties permissions tests', () => { const token = await prepare(helper); await expect(token.setProperties(alice, [ - {key: 'fractals', value: 'one headline - why believe it'}, + {key: 'fractals', value: 'one headline - why believe it'}, ])).to.be.fulfilled; await token.transfer(alice, {Substrate: charlie.address}, 33n); @@ -772,7 +768,7 @@ describe('ReFungible token properties permissions tests', () => { .to.be.fulfilled; await expect(token.setProperties(alice, [ - {key: 'fractals', value: 'multiverse'}, + {key: 'fractals', value: 'multiverse'}, ])).to.be.fulfilled; }); }); diff --git a/tests/src/nesting/unnest.test.ts b/tests/src/nesting/unnest.test.ts index 0da84556bb..e55c14acea 100644 --- a/tests/src/nesting/unnest.test.ts +++ b/tests/src/nesting/unnest.test.ts @@ -30,7 +30,7 @@ describe('Integration Test: Unnesting', () => { itSub('NFT: allows the owner to successfully unnest a token', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}}); const targetToken = await collection.mintToken(alice); - + // Create a nested token const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount()); @@ -49,7 +49,7 @@ describe('Integration Test: Unnesting', () => { const targetToken = await collection.mintToken(alice); const collectionFT = await helper.ft.mintCollection(alice); - + // Nest and unnest await collectionFT.mint(alice, 10n, targetToken.nestingAccount()); await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled; @@ -69,7 +69,7 @@ describe('Integration Test: Unnesting', () => { const targetToken = await collection.mintToken(alice); const collectionRFT = await helper.rft.mintCollection(alice); - + // Nest and unnest const token = await collectionRFT.mintToken(alice, 10n, targetToken.nestingAccount()); await expect(token.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled; diff --git a/tests/src/nextSponsoring.test.ts b/tests/src/nextSponsoring.test.ts index 33ceca0d4c..2621c92389 100644 --- a/tests/src/nextSponsoring.test.ts +++ b/tests/src/nextSponsoring.test.ts @@ -39,7 +39,7 @@ describe('Integration Test getNextSponsored(collection_id, owner, item_id):', () // Check with Disabled sponsoring state expect(await token.getNextSponsored({Substrate: alice.address})).to.be.null; - + // Check with Unconfirmed sponsoring state await collection.setSponsor(alice, bob.address); expect(await token.getNextSponsored({Substrate: alice.address})).to.be.null; @@ -52,7 +52,7 @@ describe('Integration Test getNextSponsored(collection_id, owner, item_id):', () await token.transfer(alice, {Substrate: bob.address}); expect(await token.getNextSponsored({Substrate: alice.address})).to.be.lessThanOrEqual(SPONSORING_TIMEOUT); - // Non-existing token + // Non-existing token expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.null; }); @@ -65,7 +65,7 @@ describe('Integration Test getNextSponsored(collection_id, owner, item_id):', () await collection.setSponsor(alice, bob.address); await collection.confirmSponsorship(bob); - + // Check with Confirmed sponsoring state expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.equal(0); @@ -91,7 +91,7 @@ describe('Integration Test getNextSponsored(collection_id, owner, item_id):', () await token.transfer(alice, {Substrate: bob.address}); expect(await token.getNextSponsored({Substrate: alice.address})).to.be.lessThanOrEqual(SPONSORING_TIMEOUT); - // Non-existing token + // Non-existing token expect(await collection.getTokenNextSponsored(0, {Substrate: alice.address})).to.be.null; }); }); diff --git a/tests/src/pallet-presence.test.ts b/tests/src/pallet-presence.test.ts index 27982b834a..e3dce5d0a6 100644 --- a/tests/src/pallet-presence.test.ts +++ b/tests/src/pallet-presence.test.ts @@ -63,16 +63,18 @@ describe('Pallet presence', () => { const chain = await helper.callRpc('api.rpc.system.chain', []); const refungible = 'refungible'; - // const scheduler = 'scheduler'; const foreignAssets = 'foreignassets'; + const rmrkPallets = ['rmrkcore', 'rmrkequip']; const appPromotion = 'apppromotion'; + const testUtils = 'testutils'; if (chain.eq('OPAL by UNIQUE')) { requiredPallets.push( refungible, - // scheduler, foreignAssets, appPromotion, + testUtils, + ...rmrkPallets, ); } else if (chain.eq('QUARTZ by UNIQUE')) { requiredPallets.push( diff --git a/tests/src/refungible.test.ts b/tests/src/refungible.test.ts index c02ed35ad5..62d2341d16 100644 --- a/tests/src/refungible.test.ts +++ b/tests/src/refungible.test.ts @@ -32,36 +32,36 @@ describe('integration test: Refungible functionality:', () => { [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor); }); }); - + itSub('Create refungible collection and token', async ({helper}) => { const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}); const itemCountBefore = await collection.getLastTokenId(); const token = await collection.mintToken(alice, 100n); - + const itemCountAfter = await collection.getLastTokenId(); - + // What to expect expect(token?.tokenId).to.be.gte(itemCountBefore); expect(itemCountAfter).to.be.equal(itemCountBefore + 1); expect(itemCountAfter.toString()).to.be.equal(token?.tokenId.toString()); }); - + itSub('Checking RPC methods when interacting with maximum allowed values (MAX_REFUNGIBLE_PIECES)', async ({helper}) => { const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}); - + const token = await collection.mintToken(alice, MAX_REFUNGIBLE_PIECES); - + expect(await collection.getTokenBalance(token.tokenId, {Substrate: alice.address})).to.be.equal(MAX_REFUNGIBLE_PIECES); - + await collection.transferToken(alice, token.tokenId, {Substrate: bob.address}, MAX_REFUNGIBLE_PIECES); expect(await collection.getTokenBalance(token.tokenId, {Substrate: bob.address})).to.be.equal(MAX_REFUNGIBLE_PIECES); expect(await token.getTotalPieces()).to.be.equal(MAX_REFUNGIBLE_PIECES); - + await expect(collection.mintToken(alice, MAX_REFUNGIBLE_PIECES + 1n)) .to.eventually.be.rejectedWith(/refungible\.WrongRefungiblePieces/); }); - + itSub('RPC method tokenOwners for refungible collection and token', async ({helper}) => { const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'}; const facelessCrowd = (await helper.arrange.createAccounts(Array(7).fill(0n), donor)).map(keyring => {return {Substrate: keyring.address};}); @@ -72,32 +72,32 @@ describe('integration test: Refungible functionality:', () => { await token.transfer(alice, {Substrate: bob.address}, 1000n); await token.transfer(alice, ethAcc, 900n); - + for (let i = 0; i < 7; i++) { await token.transfer(alice, facelessCrowd[i], 50n * BigInt(i + 1)); - } + } const owners = await token.getTop10Owners(); // What to expect expect(owners).to.deep.include.members([{Substrate: alice.address}, ethAcc, {Substrate: bob.address}, ...facelessCrowd]); expect(owners.length).to.be.equal(10); - + const [eleven] = await helper.arrange.createAccounts([0n], donor); expect(await token.transfer(alice, {Substrate: eleven.address}, 10n)).to.be.true; expect((await token.getTop10Owners()).length).to.be.equal(10); }); - + itSub('Transfer token pieces', async ({helper}) => { const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}); const token = await collection.mintToken(alice, 100n); expect(await token.getBalance({Substrate: alice.address})).to.be.equal(100n); expect(await token.transfer(alice, {Substrate: bob.address}, 60n)).to.be.true; - + expect(await token.getBalance({Substrate: alice.address})).to.be.equal(40n); expect(await token.getBalance({Substrate: bob.address})).to.be.equal(60n); - + await expect(token.transfer(alice, {Substrate: bob.address}, 41n)) .to.eventually.be.rejectedWith(/common\.TokenValueTooLow/); }); @@ -111,8 +111,8 @@ describe('integration test: Refungible functionality:', () => { // {owner: {Substrate: alice.address}, pieces: 100n}, // ]); await helper.rft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, [ - {pieces: 1n}, - {pieces: 2n}, + {pieces: 1n}, + {pieces: 2n}, {pieces: 100n}, ]); const lastTokenId = await collection.getLastTokenId(); @@ -133,7 +133,7 @@ describe('integration test: Refungible functionality:', () => { itSub('Burn all pieces', async ({helper}) => { const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}); const token = await collection.mintToken(alice, 100n); - + expect(await collection.doesTokenExist(token.tokenId)).to.be.true; expect(await token.getBalance({Substrate: alice.address})).to.be.equal(100n); @@ -146,7 +146,7 @@ describe('integration test: Refungible functionality:', () => { const token = await collection.mintToken(alice, 100n); expect(await collection.doesTokenExist(token.tokenId)).to.be.true; - + expect(await token.getBalance({Substrate: alice.address})).to.be.equal(100n); expect(await token.transfer(alice, {Substrate: bob.address}, 60n)).to.be.true; @@ -171,7 +171,7 @@ describe('integration test: Refungible functionality:', () => { itSub('Set allowance for token', async ({helper}) => { const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}); const token = await collection.mintToken(alice, 100n); - + expect(await token.getBalance({Substrate: alice.address})).to.be.equal(100n); expect(await token.approve(alice, {Substrate: bob.address}, 60n)).to.be.true; @@ -190,14 +190,14 @@ describe('integration test: Refungible functionality:', () => { expect(await token.repartition(alice, 200n)).to.be.true; expect(await token.getBalance({Substrate: alice.address})).to.be.equal(200n); expect(await token.getTotalPieces()).to.be.equal(200n); - + expect(await token.transfer(alice, {Substrate: bob.address}, 110n)).to.be.true; expect(await token.getBalance({Substrate: alice.address})).to.be.equal(90n); expect(await token.getBalance({Substrate: bob.address})).to.be.equal(110n); - + await expect(token.repartition(alice, 80n)) .to.eventually.be.rejectedWith(/refungible\.RepartitionWhileNotOwningAllPieces/); - + expect(await token.transfer(alice, {Substrate: bob.address}, 90n)).to.be.true; expect(await token.getBalance({Substrate: alice.address})).to.be.equal(0n); expect(await token.getBalance({Substrate: bob.address})).to.be.equal(200n); @@ -220,7 +220,7 @@ describe('integration test: Refungible functionality:', () => { data: [ collection.collectionId, token.tokenId, - {substrate: alice.address}, + {substrate: alice.address}, 100n, ], }); @@ -239,12 +239,12 @@ describe('integration test: Refungible functionality:', () => { data: [ collection.collectionId, token.tokenId, - {substrate: alice.address}, + {substrate: alice.address}, 50n, ], }); }); - + itSub('Create new collection with properties', async ({helper}) => { const properties = [{key: 'key1', value: 'val1'}]; const tokenPropertyPermissions = [{key: 'key1', permission: {tokenOwner: true, mutable: false, collectionAdmin: true}}]; @@ -280,7 +280,7 @@ describe('Refungible negative tests', () => { await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.TokenValueTooLow'); await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 10n)).to.be.rejectedWith('common.TokenValueTooLow'); await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 100n)).to.be.rejectedWith('common.TokenValueTooLow'); - + // 2. Alice cannot transfer non-existing token: await expect(collection.transferToken(alice, 100, {Substrate: charlie.address}, 0n)).to.be.rejectedWith('common.TokenValueTooLow'); await expect(collection.transferToken(alice, 100, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.TokenValueTooLow'); diff --git a/tests/src/removeCollectionAdmin.test.ts b/tests/src/removeCollectionAdmin.test.ts index 8c3e62d285..6755b71c4c 100644 --- a/tests/src/removeCollectionAdmin.test.ts +++ b/tests/src/removeCollectionAdmin.test.ts @@ -51,7 +51,7 @@ describe('Integration Test removeCollectionAdmin(collection_id, account_id):', ( const adminListBeforeAddAdmin = await collection.getAdmins(); expect(adminListBeforeAddAdmin).to.have.lengthOf(0); - await collection.removeAdmin(alice, {Substrate: alice.address}); + await expect(collection.removeAdmin(alice, {Substrate: alice.address})).to.be.rejectedWith('common.UserIsNotCollectionAdmin'); }); }); @@ -94,7 +94,7 @@ describe('Negative Integration Test removeCollectionAdmin(collection_id, account itSub('Admin can\'t remove collection admin.', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionAdmin-Neg-4', tokenPrefix: 'RCA'}); - + await collection.addAdmin(alice, {Substrate: bob.address}); await collection.addAdmin(alice, {Substrate: charlie.address}); diff --git a/tests/src/removeCollectionSponsor.test.ts b/tests/src/removeCollectionSponsor.test.ts index 467d69b110..2ae8533c77 100644 --- a/tests/src/removeCollectionSponsor.test.ts +++ b/tests/src/removeCollectionSponsor.test.ts @@ -21,11 +21,12 @@ describe('integration test: ext. removeCollectionSponsor():', () => { let donor: IKeyringPair; let alice: IKeyringPair; let bob: IKeyringPair; + let charlie: IKeyringPair; before(async () => { await usingPlaygrounds(async (helper, privateKey) => { donor = await privateKey({filename: __filename}); - [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor); + [alice, bob, charlie] = await helper.arrange.createAccounts([20n, 10n, 10n], donor); }); }); @@ -69,6 +70,12 @@ describe('integration test: ext. removeCollectionSponsor():', () => { await expect(collection.removeSponsor(alice)).to.not.be.rejected; }); + itSub('Remove a sponsor from a collection with collection admin permissions', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-1', tokenPrefix: 'RCS'}); + await collection.setSponsor(alice, bob.address); + await collection.addAdmin(alice, {Substrate: charlie.address}); + await expect(collection.removeSponsor(charlie)).not.to.be.rejected; + }); }); describe('(!negative test!) integration test: ext. removeCollectionSponsor():', () => { @@ -88,13 +95,6 @@ describe('(!negative test!) integration test: ext. removeCollectionSponsor():', await expect(helper.collection.removeSponsor(alice, collectionId)).to.be.rejectedWith(/common\.CollectionNotFound/); }); - itSub('(!negative test!) Remove sponsor for a collection with collection admin permissions', async ({helper}) => { - const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-1', tokenPrefix: 'RCS'}); - await collection.setSponsor(alice, bob.address); - await collection.addAdmin(alice, {Substrate: charlie.address}); - await expect(collection.removeSponsor(charlie)).to.be.rejectedWith(/common\.NoPermission/); - }); - itSub('(!negative test!) Remove sponsor for a collection by regular user', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-2', tokenPrefix: 'RCS'}); await collection.setSponsor(alice, bob.address); @@ -112,7 +112,7 @@ describe('(!negative test!) integration test: ext. removeCollectionSponsor():', const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-4', tokenPrefix: 'RCS'}); await collection.setSponsor(alice, bob.address); await collection.removeSponsor(alice); - await expect(collection.confirmSponsorship(bob)).to.be.rejectedWith(/unique\.ConfirmUnsetSponsorFail/); + await expect(collection.confirmSponsorship(bob)).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/); }); itSub('Set - confirm - remove - confirm: Sponsor cannot come back', async ({helper}) => { @@ -120,6 +120,6 @@ describe('(!negative test!) integration test: ext. removeCollectionSponsor():', await collection.setSponsor(alice, bob.address); await collection.confirmSponsorship(bob); await collection.removeSponsor(alice); - await expect(collection.confirmSponsorship(bob)).to.be.rejectedWith(/unique\.ConfirmUnsetSponsorFail/); + await expect(collection.confirmSponsorship(bob)).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/); }); }); diff --git a/tests/src/rmrk/rmrkIsolation.test.ts b/tests/src/rmrk/rmrkIsolation.test.ts deleted file mode 100644 index 7fa7690a2b..0000000000 --- a/tests/src/rmrk/rmrkIsolation.test.ts +++ /dev/null @@ -1,252 +0,0 @@ -import {expect} from 'chai'; -import usingApi, {executeTransaction} from '../substrate/substrate-api'; -import { - createCollectionExpectSuccess, - createItemExpectSuccess, - getCreateCollectionResult, - getDetailedCollectionInfo, - getGenericResult, - normalizeAccountId, -} from '../util/helpers'; -import {IKeyringPair} from '@polkadot/types/types'; -import {ApiPromise} from '@polkadot/api'; -import {it} from 'mocha'; -import {Pallets, requirePallets} from '../util/helpers'; - -let alice: IKeyringPair; -let bob: IKeyringPair; - -async function createRmrkCollection(api: ApiPromise, sender: IKeyringPair): Promise<{uniqueId: number, rmrkId: number}> { - const tx = api.tx.rmrkCore.createCollection('metadata', null, 'symbol'); - const events = await executeTransaction(api, sender, tx); - - const uniqueResult = getCreateCollectionResult(events); - const rmrkResult = getGenericResult(events, 'rmrkCore', 'CollectionCreated', (data) => { - return parseInt(data[1].toString(), 10); - }); - - return { - uniqueId: uniqueResult.collectionId, - rmrkId: rmrkResult.data!, - }; -} - -async function createRmrkNft(api: ApiPromise, sender: IKeyringPair, collectionId: number): Promise { - const tx = api.tx.rmrkCore.mintNft( - sender.address, - collectionId, - sender.address, - null, - 'nft-metadata', - true, - null, - ); - const events = await executeTransaction(api, sender, tx); - const result = getGenericResult(events, 'rmrkCore', 'NftMinted', (data) => { - return parseInt(data[2].toString(), 10); - }); - - return result.data!; -} - -async function isUnique(): Promise { - return usingApi(async api => { - const chain = await api.rpc.system.chain(); - - return chain.eq('UNIQUE'); - }); -} - -describe('RMRK External Integration Test', async () => { - const it_rmrk = (await isUnique() ? it : it.skip); - - before(async function() { - await requirePallets(this, [Pallets.RmrkCore]); - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - - - }); - }); - - it_rmrk('Creates a new RMRK collection that is mapped to a different ID and is tagged as external', async () => { - await usingApi(async api => { - // throwaway collection to bump last Unique collection ID to test ID mapping - await createCollectionExpectSuccess(); - - const collectionIds = await createRmrkCollection(api, alice); - - expect(collectionIds.rmrkId).to.be.lessThan(collectionIds.uniqueId, 'collection ID mapping'); - - const collection = (await getDetailedCollectionInfo(api, collectionIds.uniqueId))!; - expect(collection.readOnly.toHuman(), 'tagged external').to.be.true; - }); - }); -}); - -describe('Negative Integration Test: External Collections, Internal Ops', async () => { - let uniqueCollectionId: number; - let rmrkCollectionId: number; - let rmrkNftId: number; - - const it_rmrk = (await isUnique() ? it : it.skip); - - before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - - const collectionIds = await createRmrkCollection(api, alice); - uniqueCollectionId = collectionIds.uniqueId; - rmrkCollectionId = collectionIds.rmrkId; - - rmrkNftId = await createRmrkNft(api, alice, rmrkCollectionId); - }); - }); - - it_rmrk('[Negative] Forbids Unique operations with an external collection, handled by dispatch_call', async () => { - await usingApi(async api => { - // Collection item creation - - const txCreateItem = api.tx.unique.createItem(uniqueCollectionId, normalizeAccountId(alice), 'NFT'); - await expect(executeTransaction(api, alice, txCreateItem), 'creating item') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txCreateMultipleItems = api.tx.unique.createMultipleItems(uniqueCollectionId, normalizeAccountId(alice), [{NFT: {}}, {NFT: {}}]); - await expect(executeTransaction(api, alice, txCreateMultipleItems), 'creating multiple') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txCreateMultipleItemsEx = api.tx.unique.createMultipleItemsEx(uniqueCollectionId, {NFT: [{}]}); - await expect(executeTransaction(api, alice, txCreateMultipleItemsEx), 'creating multiple ex') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - // Collection properties - - const txSetCollectionProperties = api.tx.unique.setCollectionProperties(uniqueCollectionId, [{key: 'a', value: '1'}, {key: 'b'}]); - await expect(executeTransaction(api, alice, txSetCollectionProperties), 'setting collection properties') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txDeleteCollectionProperties = api.tx.unique.deleteCollectionProperties(uniqueCollectionId, ['a']); - await expect(executeTransaction(api, alice, txDeleteCollectionProperties), 'deleting collection properties') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txsetTokenPropertyPermissions = api.tx.unique.setTokenPropertyPermissions(uniqueCollectionId, [{key: 'a', permission: {mutable: true}}]); - await expect(executeTransaction(api, alice, txsetTokenPropertyPermissions), 'setting property permissions') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - // NFT - - const txBurn = api.tx.unique.burnItem(uniqueCollectionId, rmrkNftId, 1); - await expect(executeTransaction(api, alice, txBurn), 'burning').to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txBurnFrom = api.tx.unique.burnFrom(uniqueCollectionId, normalizeAccountId(alice), rmrkNftId, 1); - await expect(executeTransaction(api, alice, txBurnFrom), 'burning-from').to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txTransfer = api.tx.unique.transfer(normalizeAccountId(bob), uniqueCollectionId, rmrkNftId, 1); - await expect(executeTransaction(api, alice, txTransfer), 'transferring').to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txApprove = api.tx.unique.approve(normalizeAccountId(bob), uniqueCollectionId, rmrkNftId, 1); - await expect(executeTransaction(api, alice, txApprove), 'approving').to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txTransferFrom = api.tx.unique.transferFrom(normalizeAccountId(alice), normalizeAccountId(bob), uniqueCollectionId, rmrkNftId, 1); - await expect(executeTransaction(api, alice, txTransferFrom), 'transferring-from').to.be.rejectedWith(/common\.CollectionIsExternal/); - - // NFT properties - - const txSetTokenProperties = api.tx.unique.setTokenProperties(uniqueCollectionId, rmrkNftId, [{key: 'a', value: '2'}]); - await expect(executeTransaction(api, alice, txSetTokenProperties), 'setting token properties') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txDeleteTokenProperties = api.tx.unique.deleteTokenProperties(uniqueCollectionId, rmrkNftId, ['a']); - await expect(executeTransaction(api, alice, txDeleteTokenProperties), 'deleting token properties') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - }); - }); - - it_rmrk('[Negative] Forbids Unique collection operations with an external collection', async () => { - await usingApi(async api => { - const txDestroyCollection = api.tx.unique.destroyCollection(uniqueCollectionId); - await expect(executeTransaction(api, alice, txDestroyCollection), 'destroying collection') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - // Allow list - - const txAddAllowList = api.tx.unique.addToAllowList(uniqueCollectionId, normalizeAccountId(bob)); - await expect(executeTransaction(api, alice, txAddAllowList), 'adding to allow list') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txRemoveAllowList = api.tx.unique.removeFromAllowList(uniqueCollectionId, normalizeAccountId(bob)); - await expect(executeTransaction(api, alice, txRemoveAllowList), 'removing from allowlist') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - // Owner / Admin / Sponsor - - const txChangeOwner = api.tx.unique.changeCollectionOwner(uniqueCollectionId, bob.address); - await expect(executeTransaction(api, alice, txChangeOwner), 'changing owner') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txAddAdmin = api.tx.unique.addCollectionAdmin(uniqueCollectionId, normalizeAccountId(bob)); - await expect(executeTransaction(api, alice, txAddAdmin), 'adding admin') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txRemoveAdmin = api.tx.unique.removeCollectionAdmin(uniqueCollectionId, normalizeAccountId(bob)); - await expect(executeTransaction(api, alice, txRemoveAdmin), 'removing admin') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txAddCollectionSponsor = api.tx.unique.setCollectionSponsor(uniqueCollectionId, bob.address); - await expect(executeTransaction(api, alice, txAddCollectionSponsor), 'setting sponsor') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txConfirmCollectionSponsor = api.tx.unique.confirmSponsorship(uniqueCollectionId); - await expect(executeTransaction(api, alice, txConfirmCollectionSponsor), 'confirming sponsor') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txRemoveCollectionSponsor = api.tx.unique.removeCollectionSponsor(uniqueCollectionId); - await expect(executeTransaction(api, alice, txRemoveCollectionSponsor), 'removing sponsor') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - // Limits / permissions / transfers - - const txSetTransfers = api.tx.unique.setTransfersEnabledFlag(uniqueCollectionId, true); - await expect(executeTransaction(api, alice, txSetTransfers), 'setting transfers enabled flag') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txSetLimits = api.tx.unique.setCollectionLimits(uniqueCollectionId, {transfersEnabled: false}); - await expect(executeTransaction(api, alice, txSetLimits), 'setting collection limits') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - - const txSetPermissions = api.tx.unique.setCollectionPermissions(uniqueCollectionId, {access: 'AllowList'}); - await expect(executeTransaction(api, alice, txSetPermissions), 'setting collection permissions') - .to.be.rejectedWith(/common\.CollectionIsExternal/); - }); - }); -}); - -describe('Negative Integration Test: Internal Collections, External Ops', async () => { - let collectionId: number; - let nftId: number; - - const it_rmrk = (await isUnique() ? it : it.skip); - - before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - - collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); - nftId = await createItemExpectSuccess(alice, collectionId, 'NFT'); - }); - }); - - it_rmrk('[Negative] Forbids RMRK operations with the internal collection and NFT (due to the lack of mapping)', async () => { - await usingApi(async api => { - const txChangeOwner = api.tx.rmrkCore.changeCollectionIssuer(collectionId, bob.address); - await expect(executeTransaction(api, alice, txChangeOwner), 'changing collection issuer') - .to.be.rejectedWith(/rmrkCore\.CollectionUnknown/); - - const maxBurns = 10; - const txBurnItem = api.tx.rmrkCore.burnNft(collectionId, nftId, maxBurns); - await expect(executeTransaction(api, alice, txBurnItem), 'burning NFT').to.be.rejectedWith(/rmrkCore\.CollectionUnknown/); - }); - }); -}); diff --git a/tests/src/rpc.test.ts b/tests/src/rpc.test.ts index 5fd5a1ff7d..b5e02f4d50 100644 --- a/tests/src/rpc.test.ts +++ b/tests/src/rpc.test.ts @@ -35,20 +35,20 @@ describe('integration test: RPC methods', () => { const owner = (await helper.callRpc('api.rpc.unique.tokenOwner', [collection.collectionId, 0])).toJSON() as any; expect(owner).to.be.null; }); - + itSub('RPC method tokenOwners for fungible collection and token', async ({helper}) => { // Set-up a few token owners of all stripes const ethAcc = {Ethereum: '0x67fb3503a61b284dc83fa96dceec4192db47dc7c'}; const facelessCrowd = (await helper.arrange.createAccounts([0n, 0n, 0n, 0n, 0n, 0n, 0n], donor)) .map(i => {return {Substrate: i.address};}); - + const collection = await helper.ft.mintCollection(alice, {name: 'RPC-2', tokenPrefix: 'RPC'}); // mint some maximum (u128) amounts of tokens possible await collection.mint(alice, (1n << 128n) - 1n); - + await collection.transfer(alice, {Substrate: bob.address}, 1000n); await collection.transfer(alice, ethAcc, 900n); - + for (let i = 0; i < facelessCrowd.length; i++) { await collection.transfer(alice, facelessCrowd[i], 1n); } @@ -59,7 +59,7 @@ describe('integration test: RPC methods', () => { expect(ids).to.deep.include.members([{Substrate: alice.address}, ethAcc, {Substrate: bob.address}, ...facelessCrowd]); expect(owners.length == 10).to.be.true; - + // Make sure only 10 results are returned with this RPC const [eleven] = await helper.arrange.createAccounts([0n], donor); expect(await collection.transfer(alice, {Substrate: eleven.address}, 10n)).to.be.true; diff --git a/tests/src/scheduler.seqtest.ts b/tests/src/scheduler.seqtest.ts new file mode 100644 index 0000000000..ba25536db8 --- /dev/null +++ b/tests/src/scheduler.seqtest.ts @@ -0,0 +1,809 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {expect, itSched, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from './util'; +import {IKeyringPair} from '@polkadot/types/types'; +import {DevUniqueHelper} from './util/playgrounds/unique.dev'; + +describe('Scheduling token and balance transfers', () => { + let superuser: IKeyringPair; + let alice: IKeyringPair; + let bob: IKeyringPair; + let charlie: IKeyringPair; + + before(async function() { + await usingPlaygrounds(async (helper, privateKey) => { + requirePalletsOrSkip(this, helper, [Pallets.Scheduler]); + + superuser = await privateKey('//Alice'); + const donor = await privateKey({filename: __filename}); + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); + + await helper.testUtils.enable(); + }); + }); + + beforeEach(async () => { + await usingPlaygrounds(async (helper) => { + await helper.wait.noScheduledTasks(); + }); + }); + + itSched('Can delay a transfer of an owned token', async (scheduleKind, {helper}) => { + const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'}); + const token = await collection.mintToken(alice); + const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined; + const blocksBeforeExecution = 4; + + await token.scheduleAfter(blocksBeforeExecution, {scheduledId}) + .transfer(alice, {Substrate: bob.address}); + const executionBlock = await helper.chain.getLatestBlockNumber() + blocksBeforeExecution + 1; + + expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address}); + + await helper.wait.forParachainBlockNumber(executionBlock); + + expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address}); + }); + + itSched('Can transfer funds periodically', async (scheduleKind, {helper}) => { + const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined; + const waitForBlocks = 1; + + const amount = 1n * helper.balance.getOneTokenNominal(); + const periodic = { + period: 2, + repetitions: 2, + }; + + const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address); + + await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, periodic}) + .balance.transferToSubstrate(alice, bob.address, amount); + const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1; + + await helper.wait.forParachainBlockNumber(executionBlock); + + const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address); + expect(bobsBalanceAfterFirst) + .to.be.equal( + bobsBalanceBefore + 1n * amount, + '#1 Balance of the recipient should be increased by 1 * amount', + ); + + await helper.wait.forParachainBlockNumber(executionBlock + periodic.period); + + const bobsBalanceAfterSecond = await helper.balance.getSubstrate(bob.address); + expect(bobsBalanceAfterSecond) + .to.be.equal( + bobsBalanceBefore + 2n * amount, + '#2 Balance of the recipient should be increased by 2 * amount', + ); + }); + + itSub('Can cancel a scheduled operation which has not yet taken effect', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'}); + const token = await collection.mintToken(alice); + + const scheduledId = helper.arrange.makeScheduledId(); + const waitForBlocks = 4; + + expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address}); + + await token.scheduleAfter(waitForBlocks, {scheduledId}) + .transfer(alice, {Substrate: bob.address}); + const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1; + + await helper.scheduler.cancelScheduled(alice, scheduledId); + + await helper.wait.forParachainBlockNumber(executionBlock); + + expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address}); + }); + + itSub('Can cancel a periodic operation (transfer of funds)', async ({helper}) => { + const waitForBlocks = 1; + const periodic = { + period: 3, + repetitions: 2, + }; + + const scheduledId = helper.arrange.makeScheduledId(); + + const amount = 1n * helper.balance.getOneTokenNominal(); + + const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address); + + await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, periodic}) + .balance.transferToSubstrate(alice, bob.address, amount); + const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1; + + await helper.wait.forParachainBlockNumber(executionBlock); + + const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address); + + expect(bobsBalanceAfterFirst) + .to.be.equal( + bobsBalanceBefore + 1n * amount, + '#1 Balance of the recipient should be increased by 1 * amount', + ); + + await helper.scheduler.cancelScheduled(alice, scheduledId); + await helper.wait.forParachainBlockNumber(executionBlock + periodic.period); + + const bobsBalanceAfterSecond = await helper.balance.getSubstrate(bob.address); + expect(bobsBalanceAfterSecond) + .to.be.equal( + bobsBalanceAfterFirst, + '#2 Balance of the recipient should not be changed', + ); + }); + + itSched('scheduler will not insert more tasks than allowed', async (scheduleKind, {helper}) => { + const maxScheduledPerBlock = 50; + let fillScheduledIds = new Array(maxScheduledPerBlock); + let extraScheduledId = undefined; + + if (scheduleKind == 'named') { + const scheduledIds = helper.arrange.makeScheduledIds(maxScheduledPerBlock + 1); + fillScheduledIds = scheduledIds.slice(0, maxScheduledPerBlock); + extraScheduledId = scheduledIds[maxScheduledPerBlock]; + } + + // Since the dev node has Instant Seal, + // we need a larger gap between the current block and the target one. + // + // We will schedule `maxScheduledPerBlock` transaction into the target block, + // so we need at least `maxScheduledPerBlock`-wide gap. + // We add some additional blocks to this gap to mitigate possible PolkadotJS delays. + const waitForBlocks = await helper.arrange.isDevNode() ? maxScheduledPerBlock + 5 : 5; + + const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks; + + const amount = 1n * helper.balance.getOneTokenNominal(); + + const balanceBefore = await helper.balance.getSubstrate(bob.address); + + // Fill the target block + for (let i = 0; i < maxScheduledPerBlock; i++) { + await helper.scheduler.scheduleAt(executionBlock, {scheduledId: fillScheduledIds[i]}) + .balance.transferToSubstrate(superuser, bob.address, amount); + } + + // Try to schedule a task into a full block + await expect(helper.scheduler.scheduleAt(executionBlock, {scheduledId: extraScheduledId}) + .balance.transferToSubstrate(superuser, bob.address, amount)) + .to.be.rejectedWith(/scheduler\.AgendaIsExhausted/); + + await helper.wait.forParachainBlockNumber(executionBlock); + + const balanceAfter = await helper.balance.getSubstrate(bob.address); + + expect(balanceAfter > balanceBefore).to.be.true; + + const diff = balanceAfter - balanceBefore; + expect(diff).to.be.equal(amount * BigInt(maxScheduledPerBlock)); + }); + + itSched.ifWithPallets('Scheduled tasks are transactional', [Pallets.TestUtils], async (scheduleKind, {helper}) => { + const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined; + const waitForBlocks = 4; + + const initTestVal = 42; + const changedTestVal = 111; + + await helper.testUtils.setTestValue(alice, initTestVal); + + await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId}) + .testUtils.setTestValueAndRollback(alice, changedTestVal); + const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1; + + await helper.wait.forParachainBlockNumber(executionBlock); + + const testVal = await helper.testUtils.testValue(); + expect(testVal, 'The test value should NOT be commited') + .to.be.equal(initTestVal); + }); + + itSched.ifWithPallets('Scheduled tasks should take correct fees', [Pallets.TestUtils], async function(scheduleKind, {helper}) { + const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined; + const waitForBlocks = 4; + const periodic = { + period: 2, + repetitions: 2, + }; + + const dummyTx = helper.constructApiCall('api.tx.testUtils.justTakeFee', []); + const scheduledLen = dummyTx.callIndex.length; + + const expectedScheduledFee = (await helper.getPaymentInfo(alice, dummyTx, scheduledLen)) + .partialFee.toBigInt(); + + await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, periodic}) + .testUtils.justTakeFee(alice); + const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1; + + const aliceInitBalance = await helper.balance.getSubstrate(alice.address); + let diff; + + await helper.wait.forParachainBlockNumber(executionBlock); + + const aliceBalanceAfterFirst = await helper.balance.getSubstrate(alice.address); + expect( + aliceBalanceAfterFirst < aliceInitBalance, + '[after execution #1] Scheduled task should take a fee', + ).to.be.true; + + diff = aliceInitBalance - aliceBalanceAfterFirst; + expect(diff).to.be.equal( + expectedScheduledFee, + 'Scheduled task should take the right amount of fees', + ); + + await helper.wait.forParachainBlockNumber(executionBlock + periodic.period); + + const aliceBalanceAfterSecond = await helper.balance.getSubstrate(alice.address); + expect( + aliceBalanceAfterSecond < aliceBalanceAfterFirst, + '[after execution #2] Scheduled task should take a fee', + ).to.be.true; + + diff = aliceBalanceAfterFirst - aliceBalanceAfterSecond; + expect(diff).to.be.equal( + expectedScheduledFee, + 'Scheduled task should take the right amount of fees', + ); + }); + + // Check if we can cancel a scheduled periodic operation + // in the same block in which it is running + itSub.ifWithPallets('Can cancel the periodic sheduled tx when the tx is running', [Pallets.TestUtils], async ({helper}) => { + const currentBlockNumber = await helper.chain.getLatestBlockNumber(); + const blocksBeforeExecution = 10; + const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution; + + const [ + scheduledId, + scheduledCancelId, + ] = helper.arrange.makeScheduledIds(2); + + const periodic = { + period: 5, + repetitions: 5, + }; + + const initTestVal = 0; + const incTestVal = initTestVal + 1; + const finalTestVal = initTestVal + 2; + + await helper.testUtils.setTestValue(alice, initTestVal); + + await helper.scheduler.scheduleAt(firstExecutionBlockNumber, {scheduledId, periodic}) + .testUtils.incTestValue(alice); + + // Cancel the inc tx after 2 executions + // *in the same block* in which the second execution is scheduled + await helper.scheduler.scheduleAt( + firstExecutionBlockNumber + periodic.period, + {scheduledId: scheduledCancelId}, + ).scheduler.cancelScheduled(alice, scheduledId); + + await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber); + + // execution #0 + expect(await helper.testUtils.testValue()) + .to.be.equal(incTestVal); + + await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period); + + // execution #1 + expect(await helper.testUtils.testValue()) + .to.be.equal(finalTestVal); + + for (let i = 1; i < periodic.repetitions; i++) { + await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period * (i + 1)); + expect(await helper.testUtils.testValue()) + .to.be.equal(finalTestVal); + } + }); + + itSub.ifWithPallets('A scheduled operation can cancel itself', [Pallets.TestUtils], async ({helper}) => { + const scheduledId = helper.arrange.makeScheduledId(); + const waitForBlocks = 4; + const periodic = { + period: 2, + repetitions: 5, + }; + + const initTestVal = 0; + const maxTestVal = 2; + + await helper.testUtils.setTestValue(alice, initTestVal); + + await helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, periodic}) + .testUtils.selfCancelingInc(alice, scheduledId, maxTestVal); + const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1; + + await helper.wait.forParachainBlockNumber(executionBlock); + + // execution #0 + expect(await helper.testUtils.testValue()) + .to.be.equal(initTestVal + 1); + + await helper.wait.forParachainBlockNumber(executionBlock + periodic.period); + + // execution #1 + expect(await helper.testUtils.testValue()) + .to.be.equal(initTestVal + 2); + + await helper.wait.forParachainBlockNumber(executionBlock + 2 * periodic.period); + + // + expect(await helper.testUtils.testValue()) + .to.be.equal(initTestVal + 2); + }); + + itSub('Root can cancel any scheduled operation', async ({helper}) => { + const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'}); + const token = await collection.mintToken(bob); + + const scheduledId = helper.arrange.makeScheduledId(); + const waitForBlocks = 4; + + await token.scheduleAfter(waitForBlocks, {scheduledId}) + .transfer(bob, {Substrate: alice.address}); + const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1; + + await helper.getSudo().scheduler.cancelScheduled(superuser, scheduledId); + + await helper.wait.forParachainBlockNumber(executionBlock); + + expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address}); + }); + + itSched('Root can set prioritized scheduled operation', async (scheduleKind, {helper}) => { + const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined; + const waitForBlocks = 4; + + const amount = 42n * helper.balance.getOneTokenNominal(); + + const balanceBefore = await helper.balance.getSubstrate(charlie.address); + + await helper.getSudo() + .scheduler.scheduleAfter(waitForBlocks, {scheduledId, priority: 42}) + .balance.forceTransferToSubstrate(superuser, bob.address, charlie.address, amount); + const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1; + + await helper.wait.forParachainBlockNumber(executionBlock); + + const balanceAfter = await helper.balance.getSubstrate(charlie.address); + + expect(balanceAfter > balanceBefore).to.be.true; + + const diff = balanceAfter - balanceBefore; + expect(diff).to.be.equal(amount); + }); + + itSub("Root can change scheduled operation's priority", async ({helper}) => { + const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'}); + const token = await collection.mintToken(bob); + + const scheduledId = helper.arrange.makeScheduledId(); + const waitForBlocks = 6; + + await token.scheduleAfter(waitForBlocks, {scheduledId}) + .transfer(bob, {Substrate: alice.address}); + const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1; + + const priority = 112; + await helper.getSudo().scheduler.changePriority(superuser, scheduledId, priority); + + const priorityChanged = await helper.wait.event( + waitForBlocks, + 'scheduler', + 'PriorityChanged', + ); + + expect(priorityChanged !== null).to.be.true; + + const [blockNumber, index] = priorityChanged!.event.data[0].toJSON() as any[]; + expect(blockNumber).to.be.equal(executionBlock); + expect(index).to.be.equal(0); + + expect(priorityChanged!.event.data[1].toString()).to.be.equal(priority.toString()); + }); + + itSub('Prioritized operations execute in valid order', async ({helper}) => { + const [ + scheduledFirstId, + scheduledSecondId, + ] = helper.arrange.makeScheduledIds(2); + + const currentBlockNumber = await helper.chain.getLatestBlockNumber(); + const blocksBeforeExecution = 6; + const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution; + + const prioHigh = 0; + const prioLow = 255; + + const periodic = { + period: 6, + repetitions: 2, + }; + + const amount = 1n * helper.balance.getOneTokenNominal(); + + // Scheduler a task with a lower priority first, then with a higher priority + await helper.getSudo().scheduler.scheduleAt(firstExecutionBlockNumber, { + scheduledId: scheduledFirstId, + priority: prioLow, + periodic, + }).balance.forceTransferToSubstrate(superuser, alice.address, bob.address, amount); + + await helper.getSudo().scheduler.scheduleAt(firstExecutionBlockNumber, { + scheduledId: scheduledSecondId, + priority: prioHigh, + periodic, + }).balance.forceTransferToSubstrate(superuser, alice.address, bob.address, amount); + + const capture = await helper.arrange.captureEvents('scheduler', 'Dispatched'); + + await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber); + + // Flip priorities + await helper.getSudo().scheduler.changePriority(superuser, scheduledFirstId, prioHigh); + await helper.getSudo().scheduler.changePriority(superuser, scheduledSecondId, prioLow); + + await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period); + + const dispatchEvents = capture.extractCapturedEvents(); + expect(dispatchEvents.length).to.be.equal(4); + + const dispatchedIds = dispatchEvents.map(r => r.event.data[1].toString()); + + const firstExecuctionIds = [dispatchedIds[0], dispatchedIds[1]]; + const secondExecuctionIds = [dispatchedIds[2], dispatchedIds[3]]; + + expect(firstExecuctionIds[0]).to.be.equal(scheduledSecondId); + expect(firstExecuctionIds[1]).to.be.equal(scheduledFirstId); + + expect(secondExecuctionIds[0]).to.be.equal(scheduledFirstId); + expect(secondExecuctionIds[1]).to.be.equal(scheduledSecondId); + }); + + itSched('Periodic operations always can be rescheduled', async (scheduleKind, {helper}) => { + const maxScheduledPerBlock = 50; + const numFilledBlocks = 3; + const ids = helper.arrange.makeScheduledIds(numFilledBlocks * maxScheduledPerBlock + 1); + const periodicId = scheduleKind == 'named' ? ids[0] : undefined; + const fillIds = ids.slice(1); + + const fillScheduleFn = scheduleKind == 'named' ? 'scheduleNamed' : 'schedule'; + + const initTestVal = 0; + const firstExecTestVal = 1; + const secondExecTestVal = 2; + await helper.testUtils.setTestValue(alice, initTestVal); + + const currentBlockNumber = await helper.chain.getLatestBlockNumber(); + const blocksBeforeExecution = 8; + const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution; + + const period = 5; + + const periodic = { + period, + repetitions: 2, + }; + + // Fill `numFilledBlocks` blocks beginning from the block in which the second execution should occur + const txs = []; + for (let offset = 0; offset < numFilledBlocks; offset ++) { + for (let i = 0; i < maxScheduledPerBlock; i++) { + + const scheduledTx = helper.constructApiCall('api.tx.balances.transfer', [bob.address, 1n]); + + const when = firstExecutionBlockNumber + period + offset; + const mandatoryArgs = [when, null, null, scheduledTx]; + const scheduleArgs = scheduleKind == 'named' + ? [fillIds[i + offset * maxScheduledPerBlock], ...mandatoryArgs] + : mandatoryArgs; + + const tx = helper.constructApiCall(`api.tx.scheduler.${fillScheduleFn}`, scheduleArgs); + + txs.push(tx); + } + } + await helper.executeExtrinsic(alice, 'api.tx.testUtils.batchAll', [txs], true); + + await helper.scheduler.scheduleAt(firstExecutionBlockNumber, { + scheduledId: periodicId, + periodic, + }).testUtils.incTestValue(alice); + + await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber); + expect(await helper.testUtils.testValue()).to.be.equal(firstExecTestVal); + + await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + period + numFilledBlocks); + + // The periodic operation should be postponed by `numFilledBlocks` + for (let i = 0; i < numFilledBlocks; i++) { + expect(await helper.testUtils.testValue(firstExecutionBlockNumber + period + i)).to.be.equal(firstExecTestVal); + } + + // After the `numFilledBlocks` the periodic operation will eventually be executed + expect(await helper.testUtils.testValue()).to.be.equal(secondExecTestVal); + }); + + itSched('scheduled operations does not change nonce', async (scheduleKind, {helper}) => { + const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined; + const blocksBeforeExecution = 4; + + await helper.scheduler + .scheduleAfter(blocksBeforeExecution, {scheduledId}) + .balance.transferToSubstrate(alice, bob.address, 1n); + const executionBlock = await helper.chain.getLatestBlockNumber() + blocksBeforeExecution + 1; + + const initNonce = await helper.chain.getNonce(alice.address); + + await helper.wait.forParachainBlockNumber(executionBlock); + + const finalNonce = await helper.chain.getNonce(alice.address); + + expect(initNonce).to.be.equal(finalNonce); + }); +}); + +describe('Negative Test: Scheduling', () => { + let alice: IKeyringPair; + let bob: IKeyringPair; + + before(async function() { + await usingPlaygrounds(async (helper, privateKey) => { + requirePalletsOrSkip(this, helper, [Pallets.Scheduler]); + + const donor = await privateKey({filename: __filename}); + [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor); + + await helper.testUtils.enable(); + }); + }); + + itSub("Can't overwrite a scheduled ID", async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'}); + const token = await collection.mintToken(alice); + + const scheduledId = helper.arrange.makeScheduledId(); + const waitForBlocks = 4; + + await token.scheduleAfter(waitForBlocks, {scheduledId}) + .transfer(alice, {Substrate: bob.address}); + const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1; + + const scheduled = helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId}); + await expect(scheduled.balance.transferToSubstrate(alice, bob.address, 1n * helper.balance.getOneTokenNominal())) + .to.be.rejectedWith(/scheduler\.FailedToSchedule/); + + const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address); + + await helper.wait.forParachainBlockNumber(executionBlock); + + const bobsBalanceAfter = await helper.balance.getSubstrate(bob.address); + + expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address}); + expect(bobsBalanceBefore).to.be.equal(bobsBalanceAfter); + }); + + itSub("Can't cancel an operation which is not scheduled", async ({helper}) => { + const scheduledId = helper.arrange.makeScheduledId(); + await expect(helper.scheduler.cancelScheduled(alice, scheduledId)) + .to.be.rejectedWith(/scheduler\.NotFound/); + }); + + itSub("Can't cancel a non-owned scheduled operation", async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'}); + const token = await collection.mintToken(alice); + + const scheduledId = helper.arrange.makeScheduledId(); + const waitForBlocks = 4; + + await token.scheduleAfter(waitForBlocks, {scheduledId}) + .transfer(alice, {Substrate: bob.address}); + const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1; + + await expect(helper.scheduler.cancelScheduled(bob, scheduledId)) + .to.be.rejectedWith(/BadOrigin/); + + await helper.wait.forParachainBlockNumber(executionBlock); + + expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address}); + }); + + itSched("Regular user can't set prioritized scheduled operation", async (scheduleKind, {helper}) => { + const scheduledId = scheduleKind == 'named' ? helper.arrange.makeScheduledId() : undefined; + const waitForBlocks = 4; + + const amount = 42n * helper.balance.getOneTokenNominal(); + + const balanceBefore = await helper.balance.getSubstrate(bob.address); + + const scheduled = helper.scheduler.scheduleAfter(waitForBlocks, {scheduledId, priority: 42}); + + await expect(scheduled.balance.transferToSubstrate(alice, bob.address, amount)) + .to.be.rejectedWith(/BadOrigin/); + + const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1; + + await helper.wait.forParachainBlockNumber(executionBlock); + + const balanceAfter = await helper.balance.getSubstrate(bob.address); + + expect(balanceAfter).to.be.equal(balanceBefore); + }); + + itSub("Regular user can't change scheduled operation's priority", async ({helper}) => { + const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'}); + const token = await collection.mintToken(bob); + + const scheduledId = helper.arrange.makeScheduledId(); + const waitForBlocks = 4; + + await token.scheduleAfter(waitForBlocks, {scheduledId}) + .transfer(bob, {Substrate: alice.address}); + + const priority = 112; + await expect(helper.scheduler.changePriority(alice, scheduledId, priority)) + .to.be.rejectedWith(/BadOrigin/); + + const priorityChanged = await helper.wait.event( + waitForBlocks, + 'scheduler', + 'PriorityChanged', + ); + + expect(priorityChanged === null).to.be.true; + }); +}); + +// Implementation of the functionality tested here was postponed/shelved +describe.skip('Sponsoring scheduling', () => { + // let alice: IKeyringPair; + // let bob: IKeyringPair; + + // before(async() => { + // await usingApi(async (_, privateKey) => { + // alice = privateKey('//Alice'); + // bob = privateKey('//Bob'); + // }); + // }); + + it('Can sponsor scheduling a transaction', async () => { + // const collectionId = await createCollectionExpectSuccess(); + // await setCollectionSponsorExpectSuccess(collectionId, bob.address); + // await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); + + // await usingApi(async api => { + // const scheduledId = await makeScheduledId(); + // const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); + + // const bobBalanceBefore = await getFreeBalance(bob); + // const waitForBlocks = 4; + // // no need to wait to check, fees must be deducted on scheduling, immediately + // await scheduleTransferExpectSuccess(api, collectionId, tokenId, alice, bob, 0, waitForBlocks, scheduledId); + // const bobBalanceAfter = await getFreeBalance(bob); + // // expect(aliceBalanceAfter == aliceBalanceBefore).to.be.true; + // expect(bobBalanceAfter < bobBalanceBefore).to.be.true; + // // wait for sequentiality matters + // await waitNewBlocks(waitForBlocks - 1); + // }); + }); + + it('Schedules and dispatches a transaction even if the caller has no funds at the time of the dispatch', async () => { + // await usingApi(async (api, privateKey) => { + // // Find an empty, unused account + // const zeroBalance = await findUnusedAddress(api, privateKey); + + // const collectionId = await createCollectionExpectSuccess(); + + // // Add zeroBalance address to allow list + // await enablePublicMintingExpectSuccess(alice, collectionId); + // await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address); + + // // Grace zeroBalance with money, enough to cover future transactions + // const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE); + // await submitTransactionAsync(alice, balanceTx); + + // // Mint a fresh NFT + // const tokenId = await createItemExpectSuccess(zeroBalance, collectionId, 'NFT'); + // const scheduledId = await makeScheduledId(); + + // // Schedule transfer of the NFT a few blocks ahead + // const waitForBlocks = 5; + // await scheduleTransferExpectSuccess(api, collectionId, tokenId, zeroBalance, alice, 1, waitForBlocks, scheduledId); + + // // Get rid of the account's funds before the scheduled transaction takes place + // const balanceTx2 = api.tx.balances.transfer(alice.address, UNIQUE * 68n / 100n); + // const events = await submitTransactionAsync(zeroBalance, balanceTx2); + // expect(getGenericResult(events).success).to.be.true; + // /*const emptyBalanceTx = api.tx.balances.setBalance(zeroBalance.address, 0, 0); // do not null reserved? + // const sudoTx = api.tx.sudo.sudo(emptyBalanceTx as any); + // const events = await submitTransactionAsync(alice, sudoTx); + // expect(getGenericResult(events).success).to.be.true;*/ + + // // Wait for a certain number of blocks, discarding the ones that already happened while accepting the late transactions + // await waitNewBlocks(waitForBlocks - 3); + + // expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(alice.address)); + // }); + }); + + it('Sponsor going bankrupt does not impact a scheduled transaction', async () => { + // const collectionId = await createCollectionExpectSuccess(); + + // await usingApi(async (api, privateKey) => { + // const zeroBalance = await findUnusedAddress(api, privateKey); + // const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE); + // await submitTransactionAsync(alice, balanceTx); + + // await setCollectionSponsorExpectSuccess(collectionId, zeroBalance.address); + // await confirmSponsorshipByKeyExpectSuccess(collectionId, zeroBalance); + + // const scheduledId = await makeScheduledId(); + // const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); + + // const waitForBlocks = 5; + // await scheduleTransferExpectSuccess(api, collectionId, tokenId, alice, zeroBalance, 1, waitForBlocks, scheduledId); + + // const emptyBalanceSponsorTx = api.tx.balances.setBalance(zeroBalance.address, 0, 0); + // const sudoTx = api.tx.sudo.sudo(emptyBalanceSponsorTx as any); + // const events = await submitTransactionAsync(alice, sudoTx); + // expect(getGenericResult(events).success).to.be.true; + + // // Wait for a certain number of blocks, save for the ones that already happened while accepting the late transactions + // await waitNewBlocks(waitForBlocks - 3); + + // expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(zeroBalance.address)); + // }); + }); + + it('Exceeding sponsor rate limit without having enough funds prevents scheduling a periodic transaction', async () => { + // const collectionId = await createCollectionExpectSuccess(); + // await setCollectionSponsorExpectSuccess(collectionId, bob.address); + // await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); + + // await usingApi(async (api, privateKey) => { + // const zeroBalance = await findUnusedAddress(api, privateKey); + + // await enablePublicMintingExpectSuccess(alice, collectionId); + // await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address); + + // const bobBalanceBefore = await getFreeBalance(bob); + + // const createData = {nft: {const_data: [], variable_data: []}}; + // const creationTx = api.tx.unique.createItem(collectionId, normalizeAccountId(zeroBalance), createData as any); + // const scheduledId = await makeScheduledId(); + + // /*const badTransaction = async function () { + // await submitTransactionExpectFailAsync(zeroBalance, zeroToAlice); + // }; + // await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees');*/ + + // await expect(scheduleAfter(api, creationTx, zeroBalance, 3, scheduledId, 1, 3)).to.be.rejectedWith(/Inability to pay some fees/); + + // expect(await getFreeBalance(bob)).to.be.equal(bobBalanceBefore); + // }); + }); +}); diff --git a/tests/src/setCollectionLimits.test.ts b/tests/src/setCollectionLimits.test.ts index 9d4aacb7b2..1ea4c1e7b6 100644 --- a/tests/src/setCollectionLimits.test.ts +++ b/tests/src/setCollectionLimits.test.ts @@ -75,7 +75,7 @@ describe('setCollectionLimits positive', () => { await collection.setLimits(alice, collectionLimits); const collectionInfo1 = await collection.getEffectiveLimits(); - + expect(collectionInfo1.tokenLimit).to.be.equal(tokenLimit); await collection.setLimits(alice, collectionLimits); @@ -108,7 +108,7 @@ describe('setCollectionLimits negative', () => { [alice, bob] = await helper.arrange.createAccounts([20n, 10n], donor); }); }); - + itSub('execute setCollectionLimits for not exists collection', async ({helper}) => { const nonExistentCollectionId = (1 << 32) - 1; await expect(helper.collection.setLimits( @@ -180,7 +180,7 @@ describe('setCollectionLimits negative', () => { itSub('Setting the higher token limit fails', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionLimits-Neg-4', tokenPrefix: 'SCL'}); - + const collectionLimits = { accountTokenOwnershipLimit: accountTokenOwnershipLimit, sponsoredMintSize: sponsoredDataSize, diff --git a/tests/src/setCollectionSponsor.test.ts b/tests/src/setCollectionSponsor.test.ts index 8c7619a8c0..e8f82de4a3 100644 --- a/tests/src/setCollectionSponsor.test.ts +++ b/tests/src/setCollectionSponsor.test.ts @@ -37,7 +37,7 @@ describe('integration test: ext. setCollectionSponsor():', () => { Unconfirmed: bob.address, }); }); - + itSub('Set Fungible collection sponsor', async ({helper}) => { const collection = await helper.ft.mintCollection(alice, {name: 'SetCollectionSponsor-1-FT', tokenPrefix: 'SCS'}); await expect(collection.setSponsor(alice, bob.address)).to.be.not.rejected; @@ -75,7 +75,7 @@ describe('integration test: ext. setCollectionSponsor():', () => { Unconfirmed: charlie.address, }); }); - + itSub('Collection admin add sponsor', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {name: 'SetCollectionSponsor-4', tokenPrefix: 'SCS'}); await collection.addAdmin(alice, {Substrate: bob.address}); diff --git a/tests/src/setPermissions.test.ts b/tests/src/setPermissions.test.ts index 9cc412dee6..27c34474e3 100644 --- a/tests/src/setPermissions.test.ts +++ b/tests/src/setPermissions.test.ts @@ -34,11 +34,11 @@ describe('Integration Test: Set Permissions', () => { await collection.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true, restricted: [1, 2]}}); await collection.setPermissions(alice, {access: 'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true, restricted: [1, 2]}}); - + const permissions = (await collection.getData())?.raw.permissions; expect(permissions).to.be.deep.equal({ - access: 'AllowList', - mintMode: true, + access: 'AllowList', + mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true, restricted: [1, 2]}, }); }); @@ -49,16 +49,16 @@ describe('Integration Test: Set Permissions', () => { await collection.setPermissions(alice, {access: 'AllowList', nesting: {collectionAdmin: false, tokenOwner: true, restricted: [1, 2]}}); expect((await collection.getData())?.raw.permissions).to.be.deep.equal({ - access: 'AllowList', - mintMode: false, + access: 'AllowList', + mintMode: false, nesting: {collectionAdmin: false, tokenOwner: true, restricted: [1, 2]}, }); await collection.setPermissions(alice, {access: 'Normal', mintMode: false, nesting: {}}); await collection.setPermissions(alice, {access: 'Normal', mintMode: false, nesting: {}}); expect((await collection.getData())?.raw.permissions).to.be.deep.equal({ - access: 'Normal', - mintMode: false, + access: 'Normal', + mintMode: false, nesting: {collectionAdmin: false, tokenOwner: false, restricted: null}, }); }); @@ -67,7 +67,7 @@ describe('Integration Test: Set Permissions', () => { const collection = await helper.nft.mintCollection(alice, {name: 'SetPermissions-2', tokenPrefix: 'SP'}); await collection.addAdmin(alice, {Substrate: bob.address}); await collection.setPermissions(bob, {access: 'AllowList', mintMode: true}); - + expect((await collection.getData())?.raw.permissions.access).to.equal('AllowList'); expect((await collection.getData())?.raw.permissions.mintMode).to.equal(true); }); diff --git a/tests/src/transfer.nload.ts b/tests/src/transfer.nload.ts index 1e22f45af0..12c8d09f06 100644 --- a/tests/src/transfer.nload.ts +++ b/tests/src/transfer.nload.ts @@ -14,26 +14,27 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import {ApiPromise} from '@polkadot/api'; -import {IKeyringPair} from '@polkadot/types/types'; -import usingApi, {submitTransactionAsync} from './substrate/substrate-api'; -import waitNewBlocks from './substrate/wait-new-blocks'; -import * as cluster from 'cluster'; +/* eslint-disable @typescript-eslint/no-floating-promises */ import os from 'os'; +import {IKeyringPair} from '@polkadot/types/types'; +import {usingPlaygrounds} from './util'; +import {UniqueHelper} from './util/playgrounds/unique'; +import * as notReallyCluster from 'cluster'; // https://github.com/nodejs/node/issues/42271#issuecomment-1063415346 +const cluster = notReallyCluster as unknown as notReallyCluster.Cluster; -async function findUnusedAddress(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, seedAddition = ''): Promise { +async function findUnusedAddress(helper: UniqueHelper, privateKey: (account: string) => Promise, seedAddition = ''): Promise { let bal = 0n; let unused; do { const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition; - unused = privateKeyWrapper(`//${randomSeed}`); - bal = (await api.query.system.account(unused.address)).data.free.toBigInt(); + unused = await privateKey(`//${randomSeed}`); + bal = await helper.balance.getSubstrate(unused.address); } while (bal !== 0n); return unused; } -function findUnusedAddresses(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, amount: number): Promise { - return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, privateKeyWrapper, '_' + Date.now()))); +function findUnusedAddresses(helper: UniqueHelper, privateKey: (account: string) => Promise, amount: number): Promise { + return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(helper, privateKey, '_' + Date.now()))); } // Innacurate transfer fee @@ -54,13 +55,13 @@ function flushCounterToMaster() { counters = {}; } -async function distributeBalance(source: IKeyringPair, api: ApiPromise, totalAmount: bigint, stages: number) { +async function distributeBalance(source: IKeyringPair, helper: UniqueHelper, privateKey: (account: string) => Promise, totalAmount: bigint, stages: number) { const accounts = [source]; // we don't need source in output array const failedAccounts = [0]; const finalUserAmount = 2 ** stages - 1; - accounts.push(...await findUnusedAddresses(api, finalUserAmount)); + accounts.push(...await findUnusedAddresses(helper, privateKey, finalUserAmount)); // findUnusedAddresses produces at least 1 request per user increaseCounter('requests', finalUserAmount); @@ -68,12 +69,12 @@ async function distributeBalance(source: IKeyringPair, api: ApiPromise, totalAmo const usersWithBalance = 2 ** stage; const amount = totalAmount / (2n ** BigInt(stage)) - FEE * BigInt(stage); // console.log(`Stage ${stage}/${stages}, ${usersWithBalance} => ${usersWithBalance * 2} = ${amount}`); - const txs = []; + const txs: Promise[] = []; for (let i = 0; i < usersWithBalance; i++) { const newUser = accounts[i + usersWithBalance]; // console.log(`${accounts[i].address} => ${newUser.address} = ${amountToSplit}`); - const tx = api.tx.balances.transfer(newUser.address, amount); - txs.push(submitTransactionAsync(accounts[i], tx).catch(() => { + const tx = helper.balance.transferToSubstrate(accounts[i], newUser.address, amount); + txs.push(tx.catch(() => { failedAccounts.push(i + usersWithBalance); increaseCounter('txFailed', 1); })); @@ -90,7 +91,7 @@ async function distributeBalance(source: IKeyringPair, api: ApiPromise, totalAmo if (cluster.isMaster) { let testDone = false; - usingApi(async (api) => { + usingPlaygrounds(async (helper) => { const prevCounters: { [key: string]: number } = {}; while (!testDone) { for (const name in counters) { @@ -103,18 +104,17 @@ if (cluster.isMaster) { console.log(`${name.padEnd(15)} = ${counters[name] - prevCounters[name]}`); prevCounters[name] = counters[name]; } - await waitNewBlocks(api, 1); + await helper.wait.newBlocks(1); } }); const waiting: Promise[] = []; console.log(`Starting ${os.cpus().length} workers`); - usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); + usingPlaygrounds(async (helper, privateKey) => { + const alice = await privateKey('//Alice'); for (const id in os.cpus()) { const WORKER_NAME = `//LoadWorker${id}_${Date.now()}`; - const workerAccount = privateKeyWrapper(WORKER_NAME); - const tx = api.tx.balances.transfer(workerAccount.address, 400n * 10n ** 23n); - await submitTransactionAsync(alice, tx); + const workerAccount = await privateKey(WORKER_NAME); + await helper.balance.transferToSubstrate(alice, workerAccount.address, 400n * 10n ** 23n); const worker = cluster.fork({ WORKER_NAME, @@ -132,8 +132,8 @@ if (cluster.isMaster) { }); } else { increaseCounter('startedWorkers', 1); - usingApi(async (api, privateKeyWrapper) => { - await distributeBalance(privateKeyWrapper(process.env.WORKER_NAME as string), api, 400n * 10n ** 22n, 10); + usingPlaygrounds(async (helper, privateKey) => { + await distributeBalance(await privateKey(process.env.WORKER_NAME as string), helper, privateKey, 400n * 10n ** 22n, 10); }); const interval = setInterval(() => { flushCounterToMaster(); diff --git a/tests/src/transfer.test.ts b/tests/src/transfer.test.ts index 40510624de..a3dd459903 100644 --- a/tests/src/transfer.test.ts +++ b/tests/src/transfer.test.ts @@ -29,7 +29,7 @@ describe('Integration Test Transfer(recipient, collection_id, item_id, value)', [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor); }); }); - + itSub('Balance transfers and check balance', async ({helper}) => { const alicesBalanceBefore = await helper.balance.getSubstrate(alice.address); const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address); @@ -162,7 +162,7 @@ describe('Negative Integration Test Transfer(recipient, collection_id, item_id, await expect(collection.transfer(alice, {Substrate: bob.address})) .to.be.rejectedWith(/common\.CollectionNotFound/); }); - + itSub.ifWithPallets('[refungible] Transfer with deleted collection_id', [Pallets.ReFungible], async ({helper}) => { const collection = await helper.rft.mintCollection(alice, {name: 'Transfer-Neg-1-RFT', description: '', tokenPrefix: 'T'}); const rft = await collection.mintToken(alice, 10n); @@ -279,7 +279,7 @@ describe('Transfers to self (potentially over substrate-evm boundary)', () => { donor = await privateKey({filename: __filename}); }); }); - + itEth('Transfers to self. In case of same frontend', async ({helper}) => { const [owner] = await helper.arrange.createAccounts([10n], donor); const collection = await helper.ft.mintCollection(owner, {}); diff --git a/tests/src/transferFrom.test.ts b/tests/src/transferFrom.test.ts index 76d604dcb0..dbd5faf657 100644 --- a/tests/src/transferFrom.test.ts +++ b/tests/src/transferFrom.test.ts @@ -44,7 +44,7 @@ describe('Integration Test transferFrom(from, recipient, collection_id, item_id, await collection.mint(alice, 10n); await collection.approveTokens(alice, {Substrate: bob.address}, 7n); expect(await collection.getApprovedTokens({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(7n); - + await collection.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 6n); expect(await collection.getBalance({Substrate: charlie.address})).to.be.equal(6n); expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(4n); @@ -56,7 +56,7 @@ describe('Integration Test transferFrom(from, recipient, collection_id, item_id, const rft = await collection.mintToken(alice, 10n); await rft.approve(alice, {Substrate: bob.address}, 7n); expect(await rft.getApprovedPieces({Substrate: alice.address}, {Substrate: bob.address})).to.be.equal(7n); - + await rft.transferFrom(bob, {Substrate: alice.address}, {Substrate: charlie.address}, 6n); expect(await rft.getBalance({Substrate: charlie.address})).to.be.equal(6n); expect(await rft.getBalance({Substrate: alice.address})).to.be.equal(4n); @@ -155,11 +155,11 @@ describe('Negative Integration Test transferFrom(from, recipient, collection_id, expect(await nft.isApproved({Substrate: bob.address})).to.be.true; await expect(helper.collection.transferTokenFrom( - bob, - collection.collectionId, - nft.tokenId, - {Substrate: alice.address}, - {Substrate: charlie.address}, + bob, + collection.collectionId, + nft.tokenId, + {Substrate: alice.address}, + {Substrate: charlie.address}, 2n, )).to.be.rejectedWith(/nonfungible\.NonfungibleItemsHaveNoAmount/); expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address}); @@ -202,7 +202,7 @@ describe('Negative Integration Test transferFrom(from, recipient, collection_id, await expect(nft.transferFrom( charlie, - {Substrate: alice.address}, + {Substrate: alice.address}, {Substrate: charlie.address}, )).to.be.rejectedWith(/common\.ApprovedValueTooLow/); expect(await nft.getOwner()).to.be.deep.equal({Substrate: alice.address}); @@ -218,7 +218,7 @@ describe('Negative Integration Test transferFrom(from, recipient, collection_id, await expect(collection.transferFrom( charlie, - {Substrate: alice.address}, + {Substrate: alice.address}, {Substrate: charlie.address}, )).to.be.rejectedWith(/common\.ApprovedValueTooLow/); expect(await collection.getBalance({Substrate: alice.address})).to.be.deep.equal(10000n); @@ -236,7 +236,7 @@ describe('Negative Integration Test transferFrom(from, recipient, collection_id, await expect(rft.transferFrom( charlie, - {Substrate: alice.address}, + {Substrate: alice.address}, {Substrate: charlie.address}, )).to.be.rejectedWith(/common\.ApprovedValueTooLow/); expect(await rft.getBalance({Substrate: alice.address})).to.be.deep.equal(10000n); @@ -254,7 +254,7 @@ describe('Negative Integration Test transferFrom(from, recipient, collection_id, await expect(nft.transferFrom( bob, - {Substrate: alice.address}, + {Substrate: alice.address}, {Substrate: charlie.address}, )).to.be.rejectedWith(/common\.ApprovedValueTooLow/); }); @@ -269,7 +269,7 @@ describe('Negative Integration Test transferFrom(from, recipient, collection_id, await expect(collection.transferFrom( alice, - {Substrate: alice.address}, + {Substrate: alice.address}, {Substrate: charlie.address}, )).to.be.rejectedWith(/common\.TokenValueTooLow/); }); @@ -284,7 +284,7 @@ describe('Negative Integration Test transferFrom(from, recipient, collection_id, await expect(rft.transferFrom( alice, - {Substrate: alice.address}, + {Substrate: alice.address}, {Substrate: charlie.address}, )).to.be.rejectedWith(/common\.TokenValueTooLow/); }); @@ -300,7 +300,7 @@ describe('Negative Integration Test transferFrom(from, recipient, collection_id, await expect(nft.transferFrom( bob, - {Substrate: alice.address}, + {Substrate: alice.address}, {Substrate: charlie.address}, )).to.be.rejectedWith(/common\.ApprovedValueTooLow/); }); @@ -316,7 +316,7 @@ describe('Negative Integration Test transferFrom(from, recipient, collection_id, await expect(collection.transferFrom( bob, - {Substrate: alice.address}, + {Substrate: alice.address}, {Substrate: charlie.address}, )).to.be.rejectedWith(/common\.TokenValueTooLow/); }); @@ -332,7 +332,7 @@ describe('Negative Integration Test transferFrom(from, recipient, collection_id, await expect(rft.transferFrom( bob, - {Substrate: alice.address}, + {Substrate: alice.address}, {Substrate: charlie.address}, )).to.be.rejectedWith(/common\.ApprovedValueTooLow/); }); @@ -345,7 +345,7 @@ describe('Negative Integration Test transferFrom(from, recipient, collection_id, await expect(nft.transferFrom( alice, - {Substrate: bob.address}, + {Substrate: bob.address}, {Substrate: charlie.address}, )).to.be.rejectedWith(/common\.ApprovedValueTooLow/); }); diff --git a/tests/src/util/globalSetup.ts b/tests/src/util/globalSetup.ts index def6c1b1c5..a42e3ffb18 100644 --- a/tests/src/util/globalSetup.ts +++ b/tests/src/util/globalSetup.ts @@ -17,10 +17,10 @@ const globalSetup = async (): Promise => { // 2. Create donors for test files await fundFilenamesWithRetries(3) .then((result) => { - if (!result) Promise.reject(); + if (!result) throw Error('Some problems with fundFilenamesWithRetries'); }); - // 3. Configure App Promotion + // 3. Configure App Promotion const missingPallets = helper.fetchMissingPalletNames([Pallets.AppPromotion]); if (missingPallets.length === 0) { const superuser = await privateKey('//Alice'); @@ -38,7 +38,7 @@ const globalSetup = async (): Promise => { } } catch (error) { console.error(error); - Promise.reject(); + throw Error('Error during globalSetup'); } }); }; @@ -78,7 +78,7 @@ const fundFilenames = async () => { if (aliceBalance < MINIMUM_DONOR_FUND * oneToken) { tx.push(helper.executeExtrinsic( - alice, + alice, 'api.tx.balances.transfer', [account.address, DONOR_FUNDING * oneToken], true, diff --git a/tests/src/util/helpers.ts b/tests/src/util/helpers.ts deleted file mode 100644 index e6537c5035..0000000000 --- a/tests/src/util/helpers.ts +++ /dev/null @@ -1,1726 +0,0 @@ -// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. -// This file is part of Unique Network. - -// Unique Network is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Unique Network is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Unique Network. If not, see . - -import '../interfaces/augment-api-rpc'; -import '../interfaces/augment-api-query'; -import {ApiPromise} from '@polkadot/api'; -import type {AccountId, EventRecord, Event} from '@polkadot/types/interfaces'; -import type {GenericEventData} from '@polkadot/types'; -import {AnyTuple, IEvent, IKeyringPair} from '@polkadot/types/types'; -import {evmToAddress} from '@polkadot/util-crypto'; -import BN from 'bn.js'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import {default as usingApi, executeTransaction, submitTransactionAsync, submitTransactionExpectFailAsync} from '../substrate/substrate-api'; -import {hexToStr, strToUTF16, utf16ToStr} from './util'; -import {UpDataStructsRpcCollection, UpDataStructsCreateItemData, UpDataStructsProperty} from '@polkadot/types/lookup'; -import {UpDataStructsTokenChild} from '../interfaces'; -import { Context } from 'mocha'; - -chai.use(chaiAsPromised); -const expect = chai.expect; - -export type CrossAccountId = { - Substrate: string, -} | { - Ethereum: string, -}; - -export enum Pallets { - Inflation = 'inflation', - RmrkCore = 'rmrkcore', - RmrkEquip = 'rmrkequip', - ReFungible = 'refungible', - Fungible = 'fungible', - NFT = 'nonfungible', - Scheduler = 'scheduler', - AppPromotion = 'apppromotion', -} - -export async function isUnique(): Promise { - return usingApi(async api => { - const chain = await api.rpc.system.chain(); - - return chain.eq('UNIQUE'); - }); -} - -export async function isQuartz(): Promise { - return usingApi(async api => { - const chain = await api.rpc.system.chain(); - - return chain.eq('QUARTZ'); - }); -} - -let modulesNames: any; -export function getModuleNames(api: ApiPromise): string[] { - if (typeof modulesNames === 'undefined') - modulesNames = api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase()); - return modulesNames; -} - -export async function missingRequiredPallets(requiredPallets: string[]): Promise { - return await usingApi(async api => { - const pallets = getModuleNames(api); - - return requiredPallets.filter(p => !pallets.includes(p)); - }); -} - -export async function checkPalletsPresence(requiredPallets: string[]): Promise { - return (await missingRequiredPallets(requiredPallets)).length == 0; -} - -export async function requirePallets(mocha: Context, requiredPallets: string[]) { - const missingPallets = await missingRequiredPallets(requiredPallets); - - if (missingPallets.length > 0) { - const skippingTestMsg = `\tSkipping test "${mocha.test?.title}".`; - const missingPalletsMsg = `\tThe following pallets are missing:\n\t- ${missingPallets.join('\n\t- ')}`; - const skipMsg = `${skippingTestMsg}\n${missingPalletsMsg}`; - - console.error('\x1b[38:5:208m%s\x1b[0m', skipMsg); - - mocha.skip(); - } -} - -export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId { - if (typeof input === 'string') { - if (input.length >= 47) { - return {Substrate: input}; - } else if (input.length === 42 && input.startsWith('0x')) { - return {Ethereum: input.toLowerCase()}; - } else if (input.length === 40 && !input.startsWith('0x')) { - return {Ethereum: '0x' + input.toLowerCase()}; - } else { - throw new Error(`Unknown address format: "${input}"`); - } - } - if ('address' in input) { - return {Substrate: input.address}; - } - if ('Ethereum' in input) { - return { - Ethereum: input.Ethereum.toLowerCase(), - }; - } else if ('ethereum' in input) { - return { - Ethereum: (input as any).ethereum.toLowerCase(), - }; - } else if ('Substrate' in input) { - return input; - } else if ('substrate' in input) { - return { - Substrate: (input as any).substrate, - }; - } - - // AccountId - return {Substrate: input.toString()}; -} -export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string { - input = normalizeAccountId(input); - if ('Substrate' in input) { - return input.Substrate; - } else { - return evmToAddress(input.Ethereum); - } -} - -export const U128_MAX = (1n << 128n) - 1n; - -const MICROUNIQUE = 1_000_000_000_000n; -const MILLIUNIQUE = 1_000n * MICROUNIQUE; -const CENTIUNIQUE = 10n * MILLIUNIQUE; -export const UNIQUE = 100n * CENTIUNIQUE; - -interface GenericResult { - success: boolean; - data: T | null; -} - -interface CreateCollectionResult { - success: boolean; - collectionId: number; -} - -interface CreateItemResult { - success: boolean; - collectionId: number; - itemId: number; - recipient?: CrossAccountId; -} - -interface TransferResult { - collectionId: number; - itemId: number; - sender?: CrossAccountId; - recipient?: CrossAccountId; - value: bigint; -} - -interface IReFungibleOwner { - fraction: BN; - owner: number[]; -} - -interface IGetMessage { - checkMsgUnqMethod: string; - checkMsgTrsMethod: string; - checkMsgSysMethod: string; -} - -export interface IFungibleTokenDataType { - value: number; -} - -export interface IChainLimits { - collectionNumbersLimit: number; - accountTokenOwnershipLimit: number; - collectionsAdminsLimit: number; - customDataLimit: number; - nftSponsorTransferTimeout: number; - fungibleSponsorTransferTimeout: number; - refungibleSponsorTransferTimeout: number; - //offchainSchemaLimit: number; - //constOnChainSchemaLimit: number; -} - -export interface IReFungibleTokenDataType { - owner: IReFungibleOwner[]; -} - -export function uniqueEventMessage(events: EventRecord[]): IGetMessage { - let checkMsgUnqMethod = ''; - let checkMsgTrsMethod = ''; - let checkMsgSysMethod = ''; - events.forEach(({event: {method, section}}) => { - if (section === 'common') { - checkMsgUnqMethod = method; - } else if (section === 'treasury') { - checkMsgTrsMethod = method; - } else if (section === 'system') { - checkMsgSysMethod = method; - } else { return null; } - }); - const result: IGetMessage = { - checkMsgUnqMethod, - checkMsgTrsMethod, - checkMsgSysMethod, - }; - return result; -} - -export function getEvent(events: EventRecord[], check: (event: IEvent) => event is T): T | undefined { - const event = events.find(r => check(r.event)); - if (!event) return; - return event.event as T; -} - -export function getGenericResult(events: EventRecord[]): GenericResult; -export function getGenericResult( - events: EventRecord[], - expectSection: string, - expectMethod: string, - extractAction: (data: GenericEventData) => T -): GenericResult; - -export function getGenericResult( - events: EventRecord[], - expectSection?: string, - expectMethod?: string, - extractAction?: (data: GenericEventData) => T, -): GenericResult { - let success = false; - let successData = null; - - events.forEach(({event: {data, method, section}}) => { - // console.log(` ${phase}: ${section}.${method}:: ${data}`); - if (method === 'ExtrinsicSuccess') { - success = true; - } else if ((expectSection == section) && (expectMethod == method)) { - successData = extractAction!(data as any); - } - }); - - const result: GenericResult = { - success, - data: successData, - }; - return result; -} - -export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult { - const genericResult = getGenericResult(events, 'common', 'CollectionCreated', (data) => parseInt(data[0].toString(), 10)); - const result: CreateCollectionResult = { - success: genericResult.success, - collectionId: genericResult.data ?? 0, - }; - return result; -} - -export function getCreateItemsResult(events: EventRecord[]): CreateItemResult[] { - const results: CreateItemResult[] = []; - - const genericResult = getGenericResult(events, 'common', 'ItemCreated', (data) => { - const collectionId = parseInt(data[0].toString(), 10); - const itemId = parseInt(data[1].toString(), 10); - const recipient = normalizeAccountId(data[2].toJSON() as any); - - const itemRes: CreateItemResult = { - success: true, - collectionId, - itemId, - recipient, - }; - - results.push(itemRes); - return results; - }); - - if (!genericResult.success) return []; - return results; -} - -export function getCreateItemResult(events: EventRecord[]): CreateItemResult { - const genericResult = getGenericResult<[number, number, CrossAccountId?]>(events, 'common', 'ItemCreated', (data) => [ - parseInt(data[0].toString(), 10), - parseInt(data[1].toString(), 10), - normalizeAccountId(data[2].toJSON() as any), - ]); - - if (genericResult.data == null) genericResult.data = [0, 0]; - - const result: CreateItemResult = { - success: genericResult.success, - collectionId: genericResult.data[0], - itemId: genericResult.data[1], - recipient: genericResult.data![2], - }; - - return result; -} - -export function getTransferResult(api: ApiPromise, events: EventRecord[]): TransferResult { - for (const {event} of events) { - if (api.events.common.Transfer.is(event)) { - const [collection, token, sender, recipient, value] = event.data; - return { - collectionId: collection.toNumber(), - itemId: token.toNumber(), - sender: normalizeAccountId(sender.toJSON() as any), - recipient: normalizeAccountId(recipient.toJSON() as any), - value: value.toBigInt(), - }; - } - } - throw new Error('no transfer event'); -} - -interface Nft { - type: 'NFT'; -} - -interface Fungible { - type: 'Fungible'; - decimalPoints: number; -} - -interface ReFungible { - type: 'ReFungible'; -} - -type CollectionMode = Nft | Fungible | ReFungible; - -export type Property = { - key: any, - value: any, -}; - -type Permission = { - mutable: boolean; - collectionAdmin: boolean; - tokenOwner: boolean; -} - -type PropertyPermission = { - key: any; - permission: Permission; -} - -export type CreateCollectionParams = { - mode: CollectionMode, - name: string, - description: string, - tokenPrefix: string, - properties?: Array, - propPerm?: Array -}; - -const defaultCreateCollectionParams: CreateCollectionParams = { - description: 'description', - mode: {type: 'NFT'}, - name: 'name', - tokenPrefix: 'prefix', -}; - -export async function -createCollection( - api: ApiPromise, - sender: IKeyringPair, - params: Partial = {}, -): Promise { - const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params}; - - let modeprm = {}; - if (mode.type === 'NFT') { - modeprm = {nft: null}; - } else if (mode.type === 'Fungible') { - modeprm = {fungible: mode.decimalPoints}; - } else if (mode.type === 'ReFungible') { - modeprm = {refungible: null}; - } - - const tx = api.tx.unique.createCollectionEx({ - name: strToUTF16(name), - description: strToUTF16(description), - tokenPrefix: strToUTF16(tokenPrefix), - mode: modeprm as any, - }); - const events = await submitTransactionAsync(sender, tx); - return getCreateCollectionResult(events); -} - -export async function createCollectionExpectSuccess(params: Partial = {}): Promise { - const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params}; - - let collectionId = 0; - await usingApi(async (api, privateKeyWrapper) => { - // Get number of collections before the transaction - const collectionCountBefore = await getCreatedCollectionCount(api); - - // Run the CreateCollection transaction - const alicePrivateKey = privateKeyWrapper('//Alice'); - - const result = await createCollection(api, alicePrivateKey, params); - - // Get number of collections after the transaction - const collectionCountAfter = await getCreatedCollectionCount(api); - - // Get the collection - const collection = await queryCollectionExpectSuccess(api, result.collectionId); - - // What to expect - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.true; - expect(result.collectionId).to.be.equal(collectionCountAfter); - // tslint:disable-next-line:no-unused-expression - expect(collection).to.be.not.null; - expect(collectionCountAfter).to.be.equal(collectionCountBefore + 1, 'Error: NFT collection NOT created.'); - expect(collection.owner.toString()).to.be.equal(toSubstrateAddress(alicePrivateKey)); - expect(utf16ToStr(collection.name.toJSON() as any)).to.be.equal(name); - expect(utf16ToStr(collection.description.toJSON() as any)).to.be.equal(description); - expect(hexToStr(collection.tokenPrefix.toJSON())).to.be.equal(tokenPrefix); - - collectionId = result.collectionId; - }); - - return collectionId; -} - -export async function createCollectionWithPropsExpectSuccess(params: Partial = {}): Promise { - const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params}; - - let collectionId = 0; - await usingApi(async (api, privateKeyWrapper) => { - // Get number of collections before the transaction - const collectionCountBefore = await getCreatedCollectionCount(api); - - // Run the CreateCollection transaction - const alicePrivateKey = privateKeyWrapper('//Alice'); - - let modeprm = {}; - if (mode.type === 'NFT') { - modeprm = {nft: null}; - } else if (mode.type === 'Fungible') { - modeprm = {fungible: mode.decimalPoints}; - } else if (mode.type === 'ReFungible') { - modeprm = {refungible: null}; - } - - const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any, properties: params.properties, tokenPropertyPermissions: params.propPerm}); - const events = await submitTransactionAsync(alicePrivateKey, tx); - const result = getCreateCollectionResult(events); - - // Get number of collections after the transaction - const collectionCountAfter = await getCreatedCollectionCount(api); - - // Get the collection - const collection = await queryCollectionExpectSuccess(api, result.collectionId); - - // What to expect - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.true; - expect(result.collectionId).to.be.equal(collectionCountAfter); - // tslint:disable-next-line:no-unused-expression - expect(collection).to.be.not.null; - expect(collectionCountAfter).to.be.equal(collectionCountBefore + 1, 'Error: NFT collection NOT created.'); - expect(collection.owner.toString()).to.be.equal(toSubstrateAddress(alicePrivateKey)); - expect(utf16ToStr(collection.name.toJSON() as any)).to.be.equal(name); - expect(utf16ToStr(collection.description.toJSON() as any)).to.be.equal(description); - expect(hexToStr(collection.tokenPrefix.toJSON())).to.be.equal(tokenPrefix); - - - collectionId = result.collectionId; - }); - - return collectionId; -} - -export async function createCollectionWithPropsExpectFailure(params: Partial = {}) { - const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params}; - - await usingApi(async (api, privateKeyWrapper) => { - // Get number of collections before the transaction - const collectionCountBefore = await getCreatedCollectionCount(api); - - // Run the CreateCollection transaction - const alicePrivateKey = privateKeyWrapper('//Alice'); - - let modeprm = {}; - if (mode.type === 'NFT') { - modeprm = {nft: null}; - } else if (mode.type === 'Fungible') { - modeprm = {fungible: mode.decimalPoints}; - } else if (mode.type === 'ReFungible') { - modeprm = {refungible: null}; - } - - const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any, properties: params.properties, tokenPropertyPermissions: params.propPerm}); - await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected; - - - // Get number of collections after the transaction - const collectionCountAfter = await getCreatedCollectionCount(api); - - expect(collectionCountAfter).to.be.equal(collectionCountBefore, 'Error: Collection with incorrect data created.'); - }); -} - -export async function createCollectionExpectFailure(params: Partial = {}) { - const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params}; - - let modeprm = {}; - if (mode.type === 'NFT') { - modeprm = {nft: null}; - } else if (mode.type === 'Fungible') { - modeprm = {fungible: mode.decimalPoints}; - } else if (mode.type === 'ReFungible') { - modeprm = {refungible: null}; - } - - await usingApi(async (api, privateKeyWrapper) => { - // Get number of collections before the transaction - const collectionCountBefore = await getCreatedCollectionCount(api); - - // Run the CreateCollection transaction - const alicePrivateKey = privateKeyWrapper('//Alice'); - const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any}); - await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected; - - // Get number of collections after the transaction - const collectionCountAfter = await getCreatedCollectionCount(api); - - // What to expect - expect(collectionCountAfter).to.be.equal(collectionCountBefore, 'Error: Collection with incorrect data created.'); - }); -} - -export async function findUnusedAddress(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, seedAddition = ''): Promise { - let bal = 0n; - let unused; - do { - const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition; - unused = privateKeyWrapper(`//${randomSeed}`); - bal = (await api.query.system.account(unused.address)).data.free.toBigInt(); - } while (bal !== 0n); - return unused; -} - -export async function getAllowance(api: ApiPromise, collectionId: number, owner: CrossAccountId | string | IKeyringPair, approved: CrossAccountId | string | IKeyringPair, tokenId: number) { - return (await api.rpc.unique.allowance(collectionId, normalizeAccountId(owner), normalizeAccountId(approved), tokenId)).toBigInt(); -} - -export function findUnusedAddresses(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, amount: number): Promise { - return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, privateKeyWrapper, '_' + Date.now()))); -} - -export async function findNotExistingCollection(api: ApiPromise): Promise { - const totalNumber = await getCreatedCollectionCount(api); - const newCollection: number = totalNumber + 1; - return newCollection; -} - -function getDestroyResult(events: EventRecord[]): boolean { - let success = false; - events.forEach(({event: {method}}) => { - if (method == 'ExtrinsicSuccess') { - success = true; - } - }); - return success; -} - -export async function destroyCollectionExpectFailure(collectionId: number, senderSeed = '//Alice') { - await usingApi(async (api, privateKeyWrapper) => { - // Run the DestroyCollection transaction - const alicePrivateKey = privateKeyWrapper(senderSeed); - const tx = api.tx.unique.destroyCollection(collectionId); - await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected; - }); -} - -export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed = '//Alice') { - await usingApi(async (api, privateKeyWrapper) => { - // Run the DestroyCollection transaction - const alicePrivateKey = privateKeyWrapper(senderSeed); - const tx = api.tx.unique.destroyCollection(collectionId); - const events = await submitTransactionAsync(alicePrivateKey, tx); - const result = getDestroyResult(events); - expect(result).to.be.true; - - // What to expect - expect(await getDetailedCollectionInfo(api, collectionId)).to.be.null; - }); -} - -export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) { - await usingApi(async (api) => { - const tx = api.tx.unique.setCollectionLimits(collectionId, limits); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - - expect(result.success).to.be.true; - }); -} - -export const setCollectionPermissionsExpectSuccess = async (sender: IKeyringPair, collectionId: number, permissions: any) => { - await usingApi(async(api) => { - const tx = api.tx.unique.setCollectionPermissions(collectionId, permissions); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - - expect(result.success).to.be.true; - }); -}; - -export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) { - await usingApi(async (api) => { - const tx = api.tx.unique.setCollectionLimits(collectionId, limits); - const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - const result = getGenericResult(events); - - expect(result.success).to.be.false; - }); -} - -export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string, sender = '//Alice') { - await usingApi(async (api, privateKeyWrapper) => { - - // Run the transaction - const senderPrivateKey = privateKeyWrapper(sender); - const tx = api.tx.unique.setCollectionSponsor(collectionId, sponsor); - const events = await submitTransactionAsync(senderPrivateKey, tx); - const result = getGenericResult(events); - - // Get the collection - const collection = await queryCollectionExpectSuccess(api, collectionId); - - // What to expect - expect(result.success).to.be.true; - expect(collection.sponsorship.toJSON()).to.deep.equal({ - unconfirmed: sponsor, - }); - }); -} - -export async function removeCollectionSponsorExpectSuccess(collectionId: number, sender = '//Alice') { - await usingApi(async (api, privateKeyWrapper) => { - - // Run the transaction - const alicePrivateKey = privateKeyWrapper(sender); - const tx = api.tx.unique.removeCollectionSponsor(collectionId); - const events = await submitTransactionAsync(alicePrivateKey, tx); - const result = getGenericResult(events); - - // Get the collection - const collection = await queryCollectionExpectSuccess(api, collectionId); - - // What to expect - expect(result.success).to.be.true; - expect(collection.sponsorship.toJSON()).to.be.deep.equal({disabled: null}); - }); -} - -export async function removeCollectionSponsorExpectFailure(collectionId: number, senderSeed = '//Alice') { - await usingApi(async (api, privateKeyWrapper) => { - - // Run the transaction - const alicePrivateKey = privateKeyWrapper(senderSeed); - const tx = api.tx.unique.removeCollectionSponsor(collectionId); - await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected; - }); -} - -export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed = '//Alice') { - await usingApi(async (api, privateKeyWrapper) => { - - // Run the transaction - const alicePrivateKey = privateKeyWrapper(senderSeed); - const tx = api.tx.unique.setCollectionSponsor(collectionId, sponsor); - await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected; - }); -} - -export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed = '//Alice') { - await usingApi(async (api, privateKeyWrapper) => { - - // Run the transaction - const sender = privateKeyWrapper(senderSeed); - await confirmSponsorshipByKeyExpectSuccess(collectionId, sender); - }); -} - -export async function confirmSponsorshipByKeyExpectSuccess(collectionId: number, sender: IKeyringPair) { - await usingApi(async (api, privateKeyWrapper) => { - - // Run the transaction - const tx = api.tx.unique.confirmSponsorship(collectionId); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - - // Get the collection - const collection = await queryCollectionExpectSuccess(api, collectionId); - - // What to expect - expect(result.success).to.be.true; - expect(collection.sponsorship.toJSON()).to.be.deep.equal({ - confirmed: sender.address, - }); - }); -} - - -export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed = '//Alice') { - await usingApi(async (api, privateKeyWrapper) => { - - // Run the transaction - const sender = privateKeyWrapper(senderSeed); - const tx = api.tx.unique.confirmSponsorship(collectionId); - await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - }); -} - -export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) { - await usingApi(async (api) => { - const tx = api.tx.unique.enableContractSponsoring(contractAddress, enable); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - - expect(result.success).to.be.true; - }); -} - -export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) { - await usingApi(async (api) => { - const tx = api.tx.unique.enableContractSponsoring(contractAddress, enable); - const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - const result = getGenericResult(events); - - expect(result.success).to.be.false; - }); -} - -export async function setTransferFlagExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) { - - await usingApi(async (api) => { - - const tx = api.tx.unique.setTransfersEnabledFlag(collectionId, enabled); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - - expect(result.success).to.be.true; - }); -} - -export async function setTransferFlagExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) { - - await usingApi(async (api) => { - - const tx = api.tx.unique.setTransfersEnabledFlag(collectionId, enabled); - const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - const result = getGenericResult(events); - - expect(result.success).to.be.false; - }); -} - -export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) { - await usingApi(async (api) => { - const tx = api.tx.unique.setContractSponsoringRateLimit(contractAddress, rateLimit); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - - expect(result.success).to.be.true; - }); -} - -export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) { - await usingApi(async (api) => { - const tx = api.tx.unique.setContractSponsoringRateLimit(contractAddress, rateLimit); - const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - const result = getGenericResult(events); - - expect(result.success).to.be.false; - }); -} - -export async function getNextSponsored( - api: ApiPromise, - collectionId: number, - account: string | CrossAccountId, - tokenId: number, -): Promise { - return Number((await api.rpc.unique.nextSponsored(collectionId, account, tokenId)).unwrapOr(-1)); -} - -export async function toggleContractAllowlistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, value = true) { - await usingApi(async (api) => { - const tx = api.tx.unique.toggleContractAllowList(contractAddress, value); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - - expect(result.success).to.be.true; - }); -} - -export async function isAllowlistedInContract(contractAddress: AccountId | string, user: string) { - let allowlisted = false; - await usingApi(async (api) => { - allowlisted = (await api.query.unique.contractAllowList(contractAddress, user)).toJSON() as boolean; - }); - return allowlisted; -} - -export async function addToContractAllowListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) { - await usingApi(async (api) => { - const tx = api.tx.unique.addToContractAllowList(contractAddress.toString(), user.toString()); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - - expect(result.success).to.be.true; - }); -} - -export async function removeFromContractAllowListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) { - await usingApi(async (api) => { - const tx = api.tx.unique.removeFromContractAllowList(contractAddress.toString(), user.toString()); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - - expect(result.success).to.be.true; - }); -} - -export async function removeFromContractAllowListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) { - await usingApi(async (api) => { - const tx = api.tx.unique.removeFromContractAllowList(contractAddress.toString(), user.toString()); - const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - const result = getGenericResult(events); - - expect(result.success).to.be.false; - }); -} - -export interface CreateFungibleData { - readonly Value: bigint; -} - -export interface CreateReFungibleData { } -export interface CreateNftData { } - -export type CreateItemData = { - NFT: CreateNftData; -} | { - Fungible: CreateFungibleData; -} | { - ReFungible: CreateReFungibleData; -}; - -export async function burnItem(api: ApiPromise, sender: IKeyringPair, collectionId: number, tokenId: number, value: number | bigint) : Promise { - const tx = api.tx.unique.burnItem(collectionId, tokenId, value); - const events = await submitTransactionAsync(sender, tx); - return getGenericResult(events).success; -} - -export async function burnItemExpectSuccess(sender: IKeyringPair, collectionId: number, tokenId: number, value: number | bigint = 1) { - await usingApi(async (api) => { - const balanceBefore = await getBalance(api, collectionId, normalizeAccountId(sender), tokenId); - // if burning token by admin - use adminButnItemExpectSuccess - expect(balanceBefore >= BigInt(value)).to.be.true; - - expect(await burnItem(api, sender, collectionId, tokenId, value)).to.be.true; - - const balanceAfter = await getBalance(api, collectionId, normalizeAccountId(sender), tokenId); - expect(balanceAfter + BigInt(value)).to.be.equal(balanceBefore); - }); -} - -export async function burnItemExpectFailure(sender: IKeyringPair, collectionId: number, tokenId: number, value: number | bigint = 1) { - await usingApi(async (api) => { - const tx = api.tx.unique.burnItem(collectionId, tokenId, value); - - const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - const result = getCreateCollectionResult(events); - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.false; - }); -} - -export async function burnFromExpectSuccess(sender: IKeyringPair, from: IKeyringPair | CrossAccountId, collectionId: number, tokenId: number, value: number | bigint = 1) { - await usingApi(async (api) => { - const tx = api.tx.unique.burnFrom(collectionId, normalizeAccountId(from), tokenId, value); - const events = await submitTransactionAsync(sender, tx); - return getGenericResult(events).success; - }); -} - -export async function -approve( - api: ApiPromise, - collectionId: number, - tokenId: number, owner: IKeyringPair, approved: CrossAccountId | string | IKeyringPair, amount: number | bigint, -) { - const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount); - const events = await submitTransactionAsync(owner, approveUniqueTx); - return getGenericResult(events).success; -} - -export async function -approveExpectSuccess( - collectionId: number, - tokenId: number, owner: IKeyringPair, approved: CrossAccountId | string, amount: number | bigint = 1, -) { - await usingApi(async (api: ApiPromise) => { - const result = await approve(api, collectionId, tokenId, owner, approved, amount); - expect(result).to.be.true; - - expect(await getAllowance(api, collectionId, owner, approved, tokenId)).to.be.equal(BigInt(amount)); - }); -} - -export async function adminApproveFromExpectSuccess( - collectionId: number, - tokenId: number, admin: IKeyringPair, owner: CrossAccountId | string, approved: CrossAccountId | string, amount: number | bigint = 1, -) { - await usingApi(async (api: ApiPromise) => { - const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount); - const events = await submitTransactionAsync(admin, approveUniqueTx); - const result = getGenericResult(events); - expect(result.success).to.be.true; - - expect(await getAllowance(api, collectionId, owner, approved, tokenId)).to.be.equal(BigInt(amount)); - }); -} - -export async function -transferFrom( - api: ApiPromise, - collectionId: number, - tokenId: number, - accountApproved: IKeyringPair, - accountFrom: IKeyringPair | CrossAccountId, - accountTo: IKeyringPair | CrossAccountId, - value: number | bigint, -) { - const from = normalizeAccountId(accountFrom); - const to = normalizeAccountId(accountTo); - const transferFromTx = api.tx.unique.transferFrom(from, to, collectionId, tokenId, value); - const events = await submitTransactionAsync(accountApproved, transferFromTx); - return getGenericResult(events).success; -} - -export async function -transferFromExpectSuccess( - collectionId: number, - tokenId: number, - accountApproved: IKeyringPair, - accountFrom: IKeyringPair | CrossAccountId, - accountTo: IKeyringPair | CrossAccountId, - value: number | bigint = 1, - type = 'NFT', -) { - await usingApi(async (api: ApiPromise) => { - const from = normalizeAccountId(accountFrom); - const to = normalizeAccountId(accountTo); - let balanceBefore = 0n; - if (type === 'Fungible' || type === 'ReFungible') { - balanceBefore = await getBalance(api, collectionId, to, tokenId); - } - expect(await transferFrom(api, collectionId, tokenId, accountApproved, accountFrom, accountTo, value)).to.be.true; - if (type === 'NFT') { - expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(to); - } - if (type === 'Fungible') { - const balanceAfter = await getBalance(api, collectionId, to, tokenId); - if (JSON.stringify(to) !== JSON.stringify(from)) { - expect(balanceAfter - balanceBefore).to.be.equal(BigInt(value)); - } else { - expect(balanceAfter).to.be.equal(balanceBefore); - } - } - if (type === 'ReFungible') { - expect(await getBalance(api, collectionId, to, tokenId)).to.be.equal(balanceBefore + BigInt(value)); - } - }); -} - -export async function -transferFromExpectFail( - collectionId: number, - tokenId: number, - accountApproved: IKeyringPair, - accountFrom: IKeyringPair, - accountTo: IKeyringPair, - value: number | bigint = 1, -) { - await usingApi(async (api: ApiPromise) => { - const transferFromTx = api.tx.unique.transferFrom(normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value); - const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected; - const result = getCreateCollectionResult(events); - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.false; - }); -} - -/* eslint no-async-promise-executor: "off" */ -export async function getBlockNumber(api: ApiPromise): Promise { - return new Promise(async (resolve) => { - const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => { - unsubscribe(); - resolve(head.number.toNumber()); - }); - }); -} - -export async function addCollectionAdminExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | CrossAccountId) { - await usingApi(async (api) => { - const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(address)); - const events = await submitTransactionAsync(sender, changeAdminTx); - const result = getCreateCollectionResult(events); - expect(result.success).to.be.true; - }); -} - -export async function adminApproveFromExpectFail( - collectionId: number, - tokenId: number, admin: IKeyringPair, owner: CrossAccountId | string, approved: CrossAccountId | string, amount: number | bigint = 1, -) { - await usingApi(async (api: ApiPromise) => { - const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount); - const events = await expect(submitTransactionAsync(admin, approveUniqueTx)).to.be.rejected; - const result = getGenericResult(events); - expect(result.success).to.be.false; - }); -} - -export async function -getFreeBalance(account: IKeyringPair): Promise { - let balance = 0n; - await usingApi(async (api) => { - balance = BigInt((await api.query.system.account(account.address)).data.free.toString()); - }); - - return balance; -} - -export async function transferBalanceTo(api: ApiPromise, source: IKeyringPair, target: string, amount = 1000n * UNIQUE) { - const tx = api.tx.balances.transfer(target, amount); - const events = await submitTransactionAsync(source, tx); - const result = getGenericResult(events); - expect(result.success).to.be.true; -} - -export async function -scheduleExpectSuccess( - operationTx: any, - sender: IKeyringPair, - blockSchedule: number, - scheduledId: string, - period = 1, - repetitions = 1, -) { - await usingApi(async (api: ApiPromise) => { - const blockNumber: number | undefined = await getBlockNumber(api); - const expectedBlockNumber = blockNumber + blockSchedule; - - expect(blockNumber).to.be.greaterThan(0); - const scheduleTx = api.tx.scheduler.scheduleNamed( // schedule - scheduledId, - expectedBlockNumber, - repetitions > 1 ? [period, repetitions] : null, - 0, - {Value: operationTx as any}, - ); - - const events = await submitTransactionAsync(sender, scheduleTx); - expect(getGenericResult(events).success).to.be.true; - }); -} - -export async function -scheduleExpectFailure( - operationTx: any, - sender: IKeyringPair, - blockSchedule: number, - scheduledId: string, - period = 1, - repetitions = 1, -) { - await usingApi(async (api: ApiPromise) => { - const blockNumber: number | undefined = await getBlockNumber(api); - const expectedBlockNumber = blockNumber + blockSchedule; - - expect(blockNumber).to.be.greaterThan(0); - const scheduleTx = api.tx.scheduler.scheduleNamed( // schedule - scheduledId, - expectedBlockNumber, - repetitions <= 1 ? null : [period, repetitions], - 0, - {Value: operationTx as any}, - ); - - //const events = - await expect(submitTransactionExpectFailAsync(sender, scheduleTx)).to.be.rejected; - //expect(getGenericResult(events).success).to.be.false; - }); -} - -export async function -scheduleTransferAndWaitExpectSuccess( - collectionId: number, - tokenId: number, - sender: IKeyringPair, - recipient: IKeyringPair, - value: number | bigint = 1, - blockSchedule: number, - scheduledId: string, -) { - await usingApi(async (api: ApiPromise) => { - await scheduleTransferExpectSuccess(collectionId, tokenId, sender, recipient, value, blockSchedule, scheduledId); - - const recipientBalanceBefore = (await api.query.system.account(recipient.address)).data.free.toBigInt(); - - // sleep for n + 1 blocks - await waitNewBlocks(blockSchedule + 1); - - const recipientBalanceAfter = (await api.query.system.account(recipient.address)).data.free.toBigInt(); - - expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(recipient.address)); - expect(recipientBalanceAfter).to.be.equal(recipientBalanceBefore); - }); -} - -export async function -scheduleTransferExpectSuccess( - collectionId: number, - tokenId: number, - sender: IKeyringPair, - recipient: IKeyringPair, - value: number | bigint = 1, - blockSchedule: number, - scheduledId: string, -) { - await usingApi(async (api: ApiPromise) => { - const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value); - - await scheduleExpectSuccess(transferTx, sender, blockSchedule, scheduledId); - - expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(sender.address)); - }); -} - -export async function -scheduleTransferFundsPeriodicExpectSuccess( - amount: bigint, - sender: IKeyringPair, - recipient: IKeyringPair, - blockSchedule: number, - scheduledId: string, - period: number, - repetitions: number, -) { - await usingApi(async (api: ApiPromise) => { - const transferTx = api.tx.balances.transfer(recipient.address, amount); - - const balanceBefore = await getFreeBalance(recipient); - - await scheduleExpectSuccess(transferTx, sender, blockSchedule, scheduledId, period, repetitions); - - expect(await getFreeBalance(recipient)).to.be.equal(balanceBefore); - }); -} - -export async function -transfer( - api: ApiPromise, - collectionId: number, - tokenId: number, - sender: IKeyringPair, - recipient: IKeyringPair | CrossAccountId, - value: number | bigint, -) : Promise { - const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient), collectionId, tokenId, value); - const events = await executeTransaction(api, sender, transferTx); - return getGenericResult(events).success; -} - -export async function -transferExpectSuccess( - collectionId: number, - tokenId: number, - sender: IKeyringPair, - recipient: IKeyringPair | CrossAccountId, - value: number | bigint = 1, - type = 'NFT', -) { - await usingApi(async (api: ApiPromise) => { - const from = normalizeAccountId(sender); - const to = normalizeAccountId(recipient); - - let balanceBefore = 0n; - if (type === 'Fungible' || type === 'ReFungible') { - balanceBefore = await getBalance(api, collectionId, to, tokenId); - } - - const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient), collectionId, tokenId, value); - const events = await executeTransaction(api, sender, transferTx); - const result = getTransferResult(api, events); - - expect(result.collectionId).to.be.equal(collectionId); - expect(result.itemId).to.be.equal(tokenId); - expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address)); - expect(result.recipient).to.be.deep.equal(to); - expect(result.value).to.be.equal(BigInt(value)); - - if (type === 'NFT') { - expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(to); - } - if (type === 'Fungible' || type === 'ReFungible') { - const balanceAfter = await getBalance(api, collectionId, to, tokenId); - if (JSON.stringify(to) !== JSON.stringify(from)) { - expect(balanceAfter - balanceBefore).to.be.equal(BigInt(value)); - } else { - expect(balanceAfter).to.be.equal(balanceBefore); - } - } - }); -} - -export async function -transferExpectFailure( - collectionId: number, - tokenId: number, - sender: IKeyringPair, - recipient: IKeyringPair | CrossAccountId, - value: number | bigint = 1, -) { - await usingApi(async (api: ApiPromise) => { - const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient), collectionId, tokenId, value); - const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected; - const result = getGenericResult(events); - // if (events && Array.isArray(events)) { - // const result = getCreateCollectionResult(events); - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.false; - //} - }); -} - -export async function -approveExpectFail( - collectionId: number, - tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1, -) { - await usingApi(async (api: ApiPromise) => { - const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount); - const events = await expect(submitTransactionExpectFailAsync(owner, approveUniqueTx)).to.be.rejected; - const result = getCreateCollectionResult(events); - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.false; - }); -} - -export async function getBalance( - api: ApiPromise, - collectionId: number, - owner: string | CrossAccountId | IKeyringPair, - token: number, -): Promise { - return (await api.rpc.unique.balance(collectionId, normalizeAccountId(owner), token)).toBigInt(); -} -export async function getTokenOwner( - api: ApiPromise, - collectionId: number, - token: number, -): Promise { - const owner = (await api.rpc.unique.tokenOwner(collectionId, token)).toJSON() as any; - if (owner == null) throw new Error('owner == null'); - return normalizeAccountId(owner); -} -export async function getTopmostTokenOwner( - api: ApiPromise, - collectionId: number, - token: number, -): Promise { - const owner = (await api.rpc.unique.topmostTokenOwner(collectionId, token)).toJSON() as any; - if (owner == null) throw new Error('owner == null'); - return normalizeAccountId(owner); -} -export async function getTokenChildren( - api: ApiPromise, - collectionId: number, - tokenId: number, -): Promise { - return (await api.rpc.unique.tokenChildren(collectionId, tokenId)).toJSON() as any; -} -export async function isTokenExists( - api: ApiPromise, - collectionId: number, - token: number, -): Promise { - return (await api.rpc.unique.tokenExists(collectionId, token)).toJSON(); -} -export async function getLastTokenId( - api: ApiPromise, - collectionId: number, -): Promise { - return (await api.rpc.unique.lastTokenId(collectionId)).toJSON(); -} -export async function getAdminList( - api: ApiPromise, - collectionId: number, -): Promise { - return (await api.rpc.unique.adminlist(collectionId)).toHuman() as any; -} -export async function getTokenProperties( - api: ApiPromise, - collectionId: number, - tokenId: number, - propertyKeys: string[], -): Promise { - return (await api.rpc.unique.tokenProperties(collectionId, tokenId, propertyKeys)).toHuman() as any; -} - -export async function createFungibleItemExpectSuccess( - sender: IKeyringPair, - collectionId: number, - data: CreateFungibleData, - owner: CrossAccountId | string = sender.address, -) { - return await usingApi(async (api) => { - const tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), {Fungible: data}); - - const events = await submitTransactionAsync(sender, tx); - const result = getCreateItemResult(events); - - expect(result.success).to.be.true; - return result.itemId; - }); -} - -export async function createMultipleItemsExpectSuccess(sender: IKeyringPair, collectionId: number, itemsData: any, owner: CrossAccountId | string = sender.address) { - await usingApi(async (api) => { - const to = normalizeAccountId(owner); - const tx = api.tx.unique.createMultipleItems(collectionId, to, itemsData); - - const events = await submitTransactionAsync(sender, tx); - expect(getGenericResult(events).success).to.be.true; - }); -} - -export async function createMultipleItemsWithPropsExpectSuccess(sender: IKeyringPair, collectionId: number, itemsData: any, owner: CrossAccountId | string = sender.address) { - await usingApi(async (api) => { - const to = normalizeAccountId(owner); - const tx = api.tx.unique.createMultipleItems(collectionId, to, itemsData); - - const events = await submitTransactionAsync(sender, tx); - const result = getCreateItemsResult(events); - - for (const res of result) { - expect(await api.rpc.unique.tokenProperties(collectionId, res.itemId)).not.to.be.empty; - } - }); -} - -export async function createMultipleItemsExWithPropsExpectSuccess(sender: IKeyringPair, collectionId: number, itemsData: any) { - await usingApi(async (api) => { - const tx = api.tx.unique.createMultipleItemsEx(collectionId, itemsData); - - const events = await submitTransactionAsync(sender, tx); - const result = getCreateItemsResult(events); - - for (const res of result) { - expect(await api.rpc.unique.tokenProperties(collectionId, res.itemId)).not.to.be.empty; - } - }); -} - -export async function createItemWithPropsExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, props: Array, owner: CrossAccountId | string = sender.address) { - let newItemId = 0; - await usingApi(async (api) => { - const to = normalizeAccountId(owner); - const itemCountBefore = await getLastTokenId(api, collectionId); - const itemBalanceBefore = await getBalance(api, collectionId, to, newItemId); - - let tx; - if (createMode === 'Fungible') { - const createData = {fungible: {value: 10}}; - tx = api.tx.unique.createItem(collectionId, to, createData as any); - } else if (createMode === 'ReFungible') { - const createData = {refungible: {pieces: 100}}; - tx = api.tx.unique.createItem(collectionId, to, createData as any); - } else { - const data = api.createType('UpDataStructsCreateItemData', {NFT: {properties: props}}); - tx = api.tx.unique.createItem(collectionId, to, data as UpDataStructsCreateItemData); - } - - const events = await submitTransactionAsync(sender, tx); - const result = getCreateItemResult(events); - - const itemCountAfter = await getLastTokenId(api, collectionId); - const itemBalanceAfter = await getBalance(api, collectionId, to, newItemId); - - if (createMode === 'NFT') { - expect(await api.rpc.unique.tokenProperties(collectionId, result.itemId)).not.to.be.empty; - } - - // What to expect - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.true; - if (createMode === 'Fungible') { - expect(itemBalanceAfter - itemBalanceBefore).to.be.equal(10n); - } else { - expect(itemCountAfter).to.be.equal(itemCountBefore + 1); - } - expect(collectionId).to.be.equal(result.collectionId); - expect(itemCountAfter.toString()).to.be.equal(result.itemId.toString()); - expect(to).to.be.deep.equal(result.recipient); - newItemId = result.itemId; - }); - return newItemId; -} - -export async function createItemWithPropsExpectFailure(sender: IKeyringPair, collectionId: number, createMode: string, props: Array, owner: CrossAccountId | string = sender.address) { - await usingApi(async (api) => { - - let tx; - if (createMode === 'NFT') { - const data = api.createType('UpDataStructsCreateItemData', {NFT: {properties: props}}) as UpDataStructsCreateItemData; - tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), data); - } else { - tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), createMode); - } - - - const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - if(events.message && events.message.toString().indexOf('1002: Verification Error') > -1) return; - const result = getCreateItemResult(events); - - expect(result.success).to.be.false; - }); -} - -export async function createItemExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) { - let newItemId = 0; - await usingApi(async (api) => { - const to = normalizeAccountId(owner); - const itemCountBefore = await getLastTokenId(api, collectionId); - const itemBalanceBefore = await getBalance(api, collectionId, to, newItemId); - - let tx; - if (createMode === 'Fungible') { - const createData = {fungible: {value: 10}}; - tx = api.tx.unique.createItem(collectionId, to, createData as any); - } else if (createMode === 'ReFungible') { - const createData = {refungible: {pieces: 100}}; - tx = api.tx.unique.createItem(collectionId, to, createData as any); - } else { - const createData = {nft: {}}; - tx = api.tx.unique.createItem(collectionId, to, createData as any); - } - - const events = await submitTransactionAsync(sender, tx); - const result = getCreateItemResult(events); - - const itemCountAfter = await getLastTokenId(api, collectionId); - const itemBalanceAfter = await getBalance(api, collectionId, to, newItemId); - - // What to expect - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.true; - if (createMode === 'Fungible') { - expect(itemBalanceAfter - itemBalanceBefore).to.be.equal(10n); - } else { - expect(itemCountAfter).to.be.equal(itemCountBefore + 1); - } - expect(collectionId).to.be.equal(result.collectionId); - expect(itemCountAfter.toString()).to.be.equal(result.itemId.toString()); - expect(to).to.be.deep.equal(result.recipient); - newItemId = result.itemId; - }); - return newItemId; -} - -export async function createRefungibleToken(api: ApiPromise, sender: IKeyringPair, collectionId: number, amount: bigint, owner: CrossAccountId | IKeyringPair | string = sender.address) : Promise { - const createData = {refungible: {pieces: amount}}; - const tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), createData as any); - - const events = await submitTransactionAsync(sender, tx); - return getCreateItemResult(events); -} - -export async function createItemExpectFailure(sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) { - await usingApi(async (api) => { - const tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), createMode); - - const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - const result = getCreateItemResult(events); - - expect(result.success).to.be.false; - }); -} - -export async function setPublicAccessModeExpectSuccess( - sender: IKeyringPair, collectionId: number, - accessMode: 'Normal' | 'AllowList', -) { - await usingApi(async (api) => { - - // Run the transaction - const tx = api.tx.unique.setCollectionPermissions(collectionId, {access: accessMode}); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - - // Get the collection - const collection = await queryCollectionExpectSuccess(api, collectionId); - - // What to expect - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.true; - expect(collection.permissions.access.toHuman()).to.be.equal(accessMode); - }); -} - -export async function setPublicAccessModeExpectFail( - sender: IKeyringPair, collectionId: number, - accessMode: 'Normal' | 'AllowList', -) { - await usingApi(async (api) => { - - // Run the transaction - const tx = api.tx.unique.setCollectionPermissions(collectionId, {access: accessMode}); - const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - const result = getGenericResult(events); - - // What to expect - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.false; - }); -} - -export async function enableAllowListExpectSuccess(sender: IKeyringPair, collectionId: number) { - await setPublicAccessModeExpectSuccess(sender, collectionId, 'AllowList'); -} - -export async function enableAllowListExpectFail(sender: IKeyringPair, collectionId: number) { - await setPublicAccessModeExpectFail(sender, collectionId, 'AllowList'); -} - -export async function disableAllowListExpectSuccess(sender: IKeyringPair, collectionId: number) { - await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal'); -} - -export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) { - await usingApi(async (api) => { - - // Run the transaction - const tx = api.tx.unique.setCollectionPermissions(collectionId, {mintMode: enabled}); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - expect(result.success).to.be.true; - - // Get the collection - const collection = await queryCollectionExpectSuccess(api, collectionId); - - expect(collection.permissions.mintMode.toHuman()).to.be.equal(enabled); - }); -} - -export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) { - await setMintPermissionExpectSuccess(sender, collectionId, true); -} - -export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) { - await usingApi(async (api) => { - // Run the transaction - const tx = api.tx.unique.setCollectionPermissions(collectionId, {mintMode: enabled}); - const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - const result = getCreateCollectionResult(events); - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.false; - }); -} - -export async function setChainLimitsExpectFailure(sender: IKeyringPair, limits: IChainLimits) { - await usingApi(async (api) => { - // Run the transaction - const tx = api.tx.unique.setChainLimits(limits); - const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - const result = getCreateCollectionResult(events); - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.false; - }); -} - -export async function isAllowlisted(api: ApiPromise, collectionId: number, address: string | CrossAccountId) { - return (await api.rpc.unique.allowed(collectionId, normalizeAccountId(address))).toJSON(); -} - -export async function addToAllowListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId | CrossAccountId) { - await usingApi(async (api) => { - expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.false; - - // Run the transaction - const tx = api.tx.unique.addToAllowList(collectionId, normalizeAccountId(address)); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - expect(result.success).to.be.true; - - expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.true; - }); -} - -export async function addToAllowListAgainExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) { - await usingApi(async (api) => { - - expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.true; - - // Run the transaction - const tx = api.tx.unique.addToAllowList(collectionId, normalizeAccountId(address)); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - expect(result.success).to.be.true; - - expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.true; - }); -} - -export async function addToAllowListExpectFail(sender: IKeyringPair, collectionId: number, address: string | AccountId) { - await usingApi(async (api) => { - - // Run the transaction - const tx = api.tx.unique.addToAllowList(collectionId, normalizeAccountId(address)); - const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - const result = getGenericResult(events); - - // What to expect - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.false; - }); -} - -export async function removeFromAllowListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) { - await usingApi(async (api) => { - // Run the transaction - const tx = api.tx.unique.removeFromAllowList(collectionId, normalizeAccountId(address)); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - - // What to expect - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.true; - }); -} - -export async function removeFromAllowListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) { - await usingApi(async (api) => { - // Run the transaction - const tx = api.tx.unique.removeFromAllowList(collectionId, normalizeAccountId(address)); - const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected; - const result = getGenericResult(events); - - // What to expect - // tslint:disable-next-line:no-unused-expression - expect(result.success).to.be.false; - }); -} - -export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number) - : Promise => { - return (await api.rpc.unique.collectionById(collectionId)).unwrapOr(null); -}; - -export const getCreatedCollectionCount = async (api: ApiPromise): Promise => { - // set global object - collectionsCount - return (await api.rpc.unique.collectionStats()).created.toNumber(); -}; - -export async function queryCollectionExpectSuccess(api: ApiPromise, collectionId: number): Promise { - return (await api.rpc.unique.collectionById(collectionId)).unwrap(); -} - -export async function waitNewBlocks(blocksCount = 1): Promise { - await usingApi(async (api) => { - const promise = new Promise(async (resolve) => { - const unsubscribe = await api.rpc.chain.subscribeNewHeads(() => { - if (blocksCount > 0) { - blocksCount--; - } else { - unsubscribe(); - resolve(); - } - }); - }); - return promise; - }); -} - -export async function repartitionRFT( - api: ApiPromise, - collectionId: number, - sender: IKeyringPair, - tokenId: number, - amount: bigint, -): Promise { - const tx = api.tx.unique.repartition(collectionId, tokenId, amount); - const events = await submitTransactionAsync(sender, tx); - const result = getGenericResult(events); - - return result.success; -} diff --git a/tests/src/util/index.ts b/tests/src/util/index.ts index 06ce1f93aa..65ef2dc90e 100644 --- a/tests/src/util/index.ts +++ b/tests/src/util/index.ts @@ -3,16 +3,18 @@ import * as path from 'path'; import * as crypto from 'crypto'; -import {IKeyringPair} from '@polkadot/types/types'; +import {IKeyringPair} from '@polkadot/types/types/interfaces'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; +import chaiSubset from 'chai-subset'; import {Context} from 'mocha'; import config from '../config'; import {ChainHelperBase} from './playgrounds/unique'; import {ILogger} from './playgrounds/types'; -import {DevUniqueHelper, SilentLogger, SilentConsole, DevMoonbeamHelper, DevMoonriverHelper, DevAcalaHelper, DevKaruraHelper, DevRelayHelper, DevWestmintHelper} from './playgrounds/unique.dev'; +import {DevUniqueHelper, SilentLogger, SilentConsole, DevMoonbeamHelper, DevMoonriverHelper, DevAcalaHelper, DevKaruraHelper, DevRelayHelper, DevWestmintHelper, DevStatemineHelper, DevStatemintHelper} from './playgrounds/unique.dev'; chai.use(chaiAsPromised); +chai.use(chaiSubset); export const expect = chai.expect; const getTestHash = (filename: string) => { @@ -39,7 +41,7 @@ async function usingPlaygroundsGeneral(helperType: ne else { const actualSeed = getTestSeed(seed.filename); let account = helper.util.fromSeed(actualSeed, ss58Format); - // here's to hoping that no + // here's to hoping that no if (!seed.ignoreFundsPresence && ((helper as any)['balance'] == undefined || await (helper as any).balance.getSubstrate(account.address) < MINIMUM_DONOR_FUND)) { console.warn(`${path.basename(seed.filename)}: Not enough funds present on the filename account. Using the default one as the donor instead.`); account = helper.util.fromSeed('//Alice', ss58Format); @@ -63,6 +65,14 @@ export const usingWestmintPlaygrounds = (url: string, code: (helper: DevWestmint return usingPlaygroundsGeneral(DevWestmintHelper, url, code); }; +export const usingStateminePlaygrounds = (url: string, code: (helper: DevWestmintHelper, privateKey: (seed: string) => Promise) => Promise) => { + return usingPlaygroundsGeneral(DevWestmintHelper, url, code); +}; + +export const usingStatemintPlaygrounds = (url: string, code: (helper: DevWestmintHelper, privateKey: (seed: string) => Promise) => Promise) => { + return usingPlaygroundsGeneral(DevWestmintHelper, url, code); +}; + export const usingRelayPlaygrounds = (url: string, code: (helper: DevRelayHelper, privateKey: (seed: string) => Promise) => Promise) => { return usingPlaygroundsGeneral(DevRelayHelper, url, code); }; @@ -100,11 +110,12 @@ export enum Pallets { NFT = 'nonfungible', Scheduler = 'scheduler', AppPromotion = 'apppromotion', + TestUtils = 'testutils', } export function requirePalletsOrSkip(test: Context, helper: DevUniqueHelper, requiredPallets: string[]) { const missingPallets = helper.fetchMissingPalletNames(requiredPallets); - + if (missingPallets.length > 0) { const skipMsg = `\tSkipping test '${test.test?.title}'.\n\tThe following pallets are missing:\n\t- ${missingPallets.join('\n\t- ')}`; console.warn('\x1b[38:5:208m%s\x1b[0m', skipMsg); @@ -113,13 +124,13 @@ export function requirePalletsOrSkip(test: Context, helper: DevUniqueHelper, req } export function itSub(name: string, cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) { - (opts.only ? it.only : + (opts.only ? it.only : opts.skip ? it.skip : it)(name, async function () { await usingPlaygrounds(async (helper, privateKey) => { if (opts.requiredPallets) { requirePalletsOrSkip(this, helper, opts.requiredPallets); } - + await cb({helper, privateKey}); }); }); @@ -134,6 +145,24 @@ itSubIfWithPallet.only = (name: string, required: string[], cb: (apis: { helper: itSubIfWithPallet.skip = (name: string, required: string[], cb: (apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise }) => any) => itSubIfWithPallet(name, required, cb, {skip: true}); itSub.ifWithPallets = itSubIfWithPallet; +export type SchedKind = 'anon' | 'named'; + +export function itSched( + name: string, + cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise }) => any, + opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}, +) { + itSub(name + ' (anonymous scheduling)', (apis) => cb('anon', apis), opts); + itSub(name + ' (named scheduling)', (apis) => cb('named', apis), opts); +} +itSched.only = (name: string, cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise }) => any) => itSched(name, cb, {only: true}); +itSched.skip = (name: string, cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise }) => any) => itSched(name, cb, {skip: true}); +itSched.ifWithPallets = itSchedIfWithPallets; + +function itSchedIfWithPallets(name: string, required: string[], cb: (schedKind: SchedKind, apis: { helper: DevUniqueHelper, privateKey: (seed: string) => Promise }) => any, opts: { only?: boolean, skip?: boolean, requiredPallets?: string[] } = {}) { + return itSched(name, cb, {requiredPallets: required, ...opts}); +} + export function describeXCM(title: string, fn: (this: Mocha.Suite) => void, opts: {skip?: boolean} = {}) { (process.env.RUN_XCM_TESTS && !opts.skip ? describe diff --git a/tests/src/util/playgrounds/types.ts b/tests/src/util/playgrounds/types.ts index 2d5cdb8833..cda039ecf0 100644 --- a/tests/src/util/playgrounds/types.ts +++ b/tests/src/util/playgrounds/types.ts @@ -26,7 +26,7 @@ export interface ITransactionResult { export interface ISubscribeBlockEventsData { number: number; hash: string; - timestamp: number; + timestamp: number; events: IEvent[]; } @@ -56,7 +56,7 @@ export interface IApiListeners { connected?: (...args: any[]) => any; disconnected?: (...args: any[]) => any; error?: (...args: any[]) => any; - ready?: (...args: any[]) => any; + ready?: (...args: any[]) => any; decorated?: (...args: any[]) => any; } @@ -70,6 +70,13 @@ export interface ICrossAccountIdLower { ethereum?: TEthereumAccount; } +export interface IEthCrossAccountId { + 0: TEthereumAccount; + 1: TSubstrateAccount; + eth: TEthereumAccount; + sub: TSubstrateAccount; +} + export interface ICollectionLimits { accountTokenOwnershipLimit?: number | null; sponsoredDataSize?: number | null; @@ -164,7 +171,16 @@ export interface IStakingInfo { amount: bigint, } +export interface IPovInfo { + proofSize: number, + compactProofSize: number, + compressedProofSize: number, + results: any[], + kv: any, +} + export interface ISchedulerOptions { + scheduledId?: string, priority?: number, periodic?: { period: number, @@ -217,3 +233,4 @@ export type TSiblingNetworkds = 'moonbeam' | 'moonriver' | 'acala' | 'karura' | export type TRelayNetworks = 'rococo' | 'westend'; export type TNetworks = TUniqueNetworks | TSiblingNetworkds | TRelayNetworks; export type TSigner = IKeyringPair; // | 'string' +export type TCollectionMode = 'nft' | 'rft' | 'ft'; diff --git a/tests/src/util/playgrounds/unique.dev.ts b/tests/src/util/playgrounds/unique.dev.ts index 66fa679da2..b443dd9fa0 100644 --- a/tests/src/util/playgrounds/unique.dev.ts +++ b/tests/src/util/playgrounds/unique.dev.ts @@ -8,8 +8,11 @@ import {ApiPromise, Keyring, WsProvider} from '@polkadot/api'; import * as defs from '../../interfaces/definitions'; import {IKeyringPair} from '@polkadot/types/types'; import {EventRecord} from '@polkadot/types/interfaces'; -import {ICrossAccountId} from './types'; +import {ICrossAccountId, IPovInfo, TSigner} from './types'; import {FrameSystemEventRecord} from '@polkadot/types/lookup'; +import {VoidFn} from '@polkadot/api/types'; +import {Pallets} from '..'; +import {spawnSync} from 'child_process'; export class SilentLogger { log(_msg: any, _level: any): void { } @@ -33,7 +36,7 @@ export class SilentConsole { this.consoleWarn = console.warn; } - enable() { + enable() { const outFn = (printer: any) => (...args: any[]) => { for (const arg of args) { if (typeof arg !== 'string') @@ -43,7 +46,7 @@ export class SilentConsole { } printer(...args); }; - + console.error = outFn(this.consoleErr.bind(console)); console.log = outFn(this.consoleLog.bind(console)); console.warn = outFn(this.consoleWarn.bind(console)); @@ -63,6 +66,7 @@ export class DevUniqueHelper extends UniqueHelper { arrange: ArrangeGroup; wait: WaitGroup; admin: AdminGroup; + testUtils: TestUtilGroup; constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) { options.helperBase = options.helperBase ?? DevUniqueHelper; @@ -71,6 +75,7 @@ export class DevUniqueHelper extends UniqueHelper { this.arrange = new ArrangeGroup(this); this.wait = new WaitGroup(this); this.admin = new AdminGroup(this); + this.testUtils = new TestUtilGroup(this); } async connect(wsEndpoint: string, _listeners?: any): Promise { @@ -94,6 +99,7 @@ export class DevUniqueHelper extends UniqueHelper { rpc: { unique: defs.unique.rpc, appPromotion: defs.appPromotion.rpc, + povinfo: defs.povinfo.rpc, rmrk: defs.rmrk.rpc, eth: { feeHistory: { @@ -111,10 +117,20 @@ export class DevUniqueHelper extends UniqueHelper { }); await this.api.isReadyOrError; this.network = await UniqueHelper.detectNetwork(this.api); + this.wsEndpoint = wsEndpoint; } } -export class DevRelayHelper extends RelayHelper {} +export class DevRelayHelper extends RelayHelper { + wait: WaitGroup; + + constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) { + options.helperBase = options.helperBase ?? DevRelayHelper; + + super(logger, options); + this.wait = new WaitGroup(this); + } +} export class DevWestmintHelper extends WestmintHelper { wait: WaitGroup; @@ -127,12 +143,17 @@ export class DevWestmintHelper extends WestmintHelper { } } +export class DevStatemineHelper extends DevWestmintHelper {} + +export class DevStatemintHelper extends DevWestmintHelper {} + export class DevMoonbeamHelper extends MoonbeamHelper { account: MoonbeamAccountGroup; wait: WaitGroup; constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) { options.helperBase = options.helperBase ?? DevMoonbeamHelper; + options.notePreimagePallet = options.notePreimagePallet ?? 'democracy'; super(logger, options); this.account = new MoonbeamAccountGroup(this); @@ -140,7 +161,12 @@ export class DevMoonbeamHelper extends MoonbeamHelper { } } -export class DevMoonriverHelper extends DevMoonbeamHelper {} +export class DevMoonriverHelper extends DevMoonbeamHelper { + constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) { + options.notePreimagePallet = options.notePreimagePallet ?? 'preimage'; + super(logger, options); + } +} export class DevAcalaHelper extends AcalaHelper { wait: WaitGroup; @@ -158,16 +184,18 @@ export class DevKaruraHelper extends DevAcalaHelper {} class ArrangeGroup { helper: DevUniqueHelper; + scheduledIdSlider = 0; + constructor(helper: DevUniqueHelper) { this.helper = helper; } /** - * Generates accounts with the specified UNQ token balance + * Generates accounts with the specified UNQ token balance * @param balances balances for generated accounts. Each balance will be multiplied by the token nominal. * @param donor donor account for balances * @returns array of newly created accounts - * @example const [acc1, acc2, acc3] = await createAccounts([0n, 10n, 20n], donor); + * @example const [acc1, acc2, acc3] = await createAccounts([0n, 10n, 20n], donor); */ createAccounts = async (balances: bigint[], donor: IKeyringPair): Promise => { let nonce = await this.helper.chain.getNonce(donor.address); @@ -187,7 +215,7 @@ class ArrangeGroup { } await Promise.all(transactions).catch(_e => {}); - + //#region TODO remove this region, when nonce problem will be solved const checkBalances = async () => { let isSuccess = true; @@ -217,7 +245,7 @@ class ArrangeGroup { }; // TODO combine this method and createAccounts into one - createCrowd = async (accountsToCreate: number, withBalance: bigint, donor: IKeyringPair): Promise => { + createCrowd = async (accountsToCreate: number, withBalance: bigint, donor: IKeyringPair): Promise => { const createAsManyAsCan = async () => { let transactions: any = []; const accounts: IKeyringPair[] = []; @@ -225,9 +253,9 @@ class ArrangeGroup { const tokenNominal = this.helper.balance.getOneTokenNominal(); for (let i = 0; i < accountsToCreate; i++) { if (i === 500) { // if there are too many accounts to create - await Promise.allSettled(transactions); // wait while first 500 (should be 100 for devnode) tx will be settled + await Promise.allSettled(transactions); // wait while first 500 (should be 100 for devnode) tx will be settled transactions = []; // - nonce = await this.helper.chain.getNonce(donor.address); // update nonce + nonce = await this.helper.chain.getNonce(donor.address); // update nonce } const recepient = this.helper.util.fromSeed(mnemonicGenerate()); accounts.push(recepient); @@ -237,7 +265,7 @@ class ArrangeGroup { nonce++; } } - + const fullfilledAccounts = []; await Promise.allSettled(transactions); for (const account of accounts) { @@ -249,7 +277,7 @@ class ArrangeGroup { return fullfilledAccounts; }; - + const crowd: IKeyringPair[] = []; // do up to 5 retries for (let index = 0; index < 5 && accountsToCreate !== 0; index++) { @@ -266,7 +294,7 @@ class ArrangeGroup { isDevNode = async () => { let blockNumber = (await this.helper.callRpc('api.query.system.number')).toJSON(); if (blockNumber == 0) { - await this.helper.wait.newBlocks(1); + await this.helper.wait.newBlocks(1); blockNumber = (await this.helper.callRpc('api.query.system.number')).toJSON(); } const block2 = await this.helper.callRpc('api.rpc.chain.getBlock', [await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber])]); @@ -285,22 +313,85 @@ class ArrangeGroup { const block2date = await findCreationDate(block2); if(block2date! - block1date! < 9000) return true; }; - + async calculcateFee(payer: ICrossAccountId, promise: () => Promise): Promise { const address = payer.Substrate ? payer.Substrate : await this.helper.address.ethToSubstrate(payer.Ethereum!); - let balance = await this.helper.balance.getSubstrate(address); - + let balance = await this.helper.balance.getSubstrate(address); + await promise(); - + balance -= await this.helper.balance.getSubstrate(address); - + return balance; } + async calculatePoVInfo(txs: any[]): Promise { + const rawPovInfo = await this.helper.callRpc('api.rpc.povinfo.estimateExtrinsicPoV', [txs]); + + const kvJson: {[key: string]: string} = {}; + + for (const kv of rawPovInfo.keyValues) { + kvJson[kv.key.toHex()] = kv.value.toHex(); + } + + const kvStr = JSON.stringify(kvJson); + + const chainql = spawnSync( + 'chainql', + [ + `--tla-code=data=${kvStr}`, + '-e', `function(data) cql.dump(cql.chain("${this.helper.getEndpoint()}").latest._meta, data, {omit_empty:true})`, + ], + ); + + if (!chainql.stdout) { + throw Error('unable to get an output from the `chainql`'); + } + + return { + proofSize: rawPovInfo.proofSize.toNumber(), + compactProofSize: rawPovInfo.compactProofSize.toNumber(), + compressedProofSize: rawPovInfo.compressedProofSize.toNumber(), + results: rawPovInfo.results, + kv: JSON.parse(chainql.stdout.toString()), + }; + } + calculatePalletAddress(palletId: any) { const address = stringToU8a(('modl' + palletId).padEnd(32, '\0')); return encodeAddress(address, this.helper.chain.getChainProperties().ss58Format); } + + makeScheduledIds(num: number): string[] { + function makeId(slider: number) { + const scheduledIdSize = 64; + const hexId = slider.toString(16); + const prefixSize = scheduledIdSize - hexId.length; + + const scheduledId = '0x' + '0'.repeat(prefixSize) + hexId; + + return scheduledId; + } + + const ids = []; + for (let i = 0; i < num; i++) { + ids.push(makeId(this.scheduledIdSlider)); + this.scheduledIdSlider += 1; + } + + return ids; + } + + makeScheduledId(): string { + return (this.makeScheduledIds(1))[0]; + } + + async captureEvents(eventSection: string, eventMethod: string): Promise { + const capture = new EventCapture(this.helper, eventSection, eventMethod); + await capture.startCapture(); + + return capture; + } } class MoonbeamAccountGroup { @@ -368,7 +459,7 @@ class WaitGroup { /** * Wait for specified number of blocks * @param blocksCount number of blocks to wait - * @returns + * @returns */ async newBlocks(blocksCount = 1, timeout?: number): Promise { timeout = timeout ?? blocksCount * 60_000; @@ -387,7 +478,7 @@ class WaitGroup { return promise; } - async forParachainBlockNumber(blockNumber: bigint, timeout?: number) { + async forParachainBlockNumber(blockNumber: bigint | number, timeout?: number) { timeout = timeout ?? 30 * 60 * 1000; // eslint-disable-next-line no-async-promise-executor const promise = new Promise(async (resolve) => { @@ -401,8 +492,8 @@ class WaitGroup { await this.waitWithTimeout(promise, timeout); return promise; } - - async forRelayBlockNumber(blockNumber: bigint, timeout?: number) { + + async forRelayBlockNumber(blockNumber: bigint | number, timeout?: number) { timeout = timeout ?? 30 * 60 * 1000; // eslint-disable-next-line no-async-promise-executor const promise = new Promise(async (resolve) => { @@ -418,6 +509,24 @@ class WaitGroup { return promise; } + noScheduledTasks() { + const api = this.helper.getApi(); + + // eslint-disable-next-line no-async-promise-executor + const promise = new Promise(async resolve => { + const unsubscribe = await api.rpc.chain.subscribeNewHeads(async () => { + const areThereScheduledTasks = await api.query.scheduler.lookup.entries(); + + if(areThereScheduledTasks.length == 0) { + unsubscribe(); + resolve(); + } + }); + }); + + return promise; + } + event(maxBlocksToWait: number, eventSection: string, eventMethod: string) { // eslint-disable-next-line no-async-promise-executor const promise = new Promise(async (resolve) => { @@ -426,16 +535,16 @@ class WaitGroup { const blockHash = header.hash; const eventIdStr = `${eventSection}.${eventMethod}`; const waitLimitStr = `wait blocks remaining: ${maxBlocksToWait}`; - + this.helper.logger.log(`[Block #${blockNumber}] Waiting for event \`${eventIdStr}\` (${waitLimitStr})`); - + const apiAt = await this.helper.getApi().at(blockHash); const eventRecords = (await apiAt.query.system.events()) as any; - + const neededEvent = eventRecords.toArray().find((r: FrameSystemEventRecord) => { return r.event.section == eventSection && r.event.method == eventMethod; }); - + if (neededEvent) { unsubscribe(); resolve(neededEvent); @@ -443,7 +552,6 @@ class WaitGroup { maxBlocksToWait--; } else { this.helper.logger.log(`Event \`${eventIdStr}\` is NOT found`); - unsubscribe(); resolve(null); } @@ -453,6 +561,90 @@ class WaitGroup { } } +class TestUtilGroup { + helper: DevUniqueHelper; + + constructor(helper: DevUniqueHelper) { + this.helper = helper; + } + + async enable() { + if (this.helper.fetchMissingPalletNames([Pallets.TestUtils]).length != 0) { + return; + } + + const signer = this.helper.util.fromSeed('//Alice'); + await this.helper.getSudo().executeExtrinsic(signer, 'api.tx.testUtils.enable', [], true); + } + + async setTestValue(signer: TSigner, testVal: number) { + await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.setTestValue', [testVal], true); + } + + async incTestValue(signer: TSigner) { + await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.incTestValue', [], true); + } + + async setTestValueAndRollback(signer: TSigner, testVal: number) { + await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.setTestValueAndRollback', [testVal], true); + } + + async testValue(blockIdx?: number) { + const api = blockIdx + ? await this.helper.getApi().at(await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockIdx])) + : this.helper.getApi(); + + return (await api.query.testUtils.testValue()).toJSON(); + } + + async justTakeFee(signer: TSigner) { + await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.justTakeFee', [], true); + } + + async selfCancelingInc(signer: TSigner, scheduledId: string, maxTestVal: number) { + await this.helper.executeExtrinsic(signer, 'api.tx.testUtils.selfCancelingInc', [scheduledId, maxTestVal], true); + } +} + +class EventCapture { + helper: DevUniqueHelper; + eventSection: string; + eventMethod: string; + events: EventRecord[] = []; + unsubscribe: VoidFn | null = null; + + constructor( + helper: DevUniqueHelper, + eventSection: string, + eventMethod: string, + ) { + this.helper = helper; + this.eventSection = eventSection; + this.eventMethod = eventMethod; + } + + async startCapture() { + this.stopCapture(); + this.unsubscribe = (await this.helper.getApi().query.system.events((eventRecords: FrameSystemEventRecord[]) => { + const newEvents = eventRecords.filter(r => { + return r.event.section == this.eventSection && r.event.method == this.eventMethod; + }); + + this.events.push(...newEvents); + })) as any; + } + + stopCapture() { + if (this.unsubscribe !== null) { + this.unsubscribe(); + } + } + + extractCapturedEvents() { + return this.events; + } +} + class AdminGroup { helper: UniqueHelper; diff --git a/tests/src/util/playgrounds/unique.ts b/tests/src/util/playgrounds/unique.ts index ec3d5a87a7..f7d2229430 100644 --- a/tests/src/util/playgrounds/unique.ts +++ b/tests/src/util/playgrounds/unique.ts @@ -7,9 +7,44 @@ import {ApiPromise, WsProvider, Keyring} from '@polkadot/api'; import {ApiInterfaceEvents, SignerOptions} from '@polkadot/api/types'; -import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm} from '@polkadot/util-crypto'; +import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto'; import {IKeyringPair} from '@polkadot/types/types'; -import {IApiListeners, IBlock, IEvent, IChainProperties, ICollectionCreationOptions, ICollectionLimits, ICollectionPermissions, ICrossAccountId, ICrossAccountIdLower, ILogger, INestingPermissions, IProperty, IStakingInfo, ISchedulerOptions, ISubstrateBalance, IToken, ITokenPropertyPermission, ITransactionResult, IUniqueHelperLog, TApiAllowedListeners, TEthereumAccount, TSigner, TSubstrateAccount, IForeignAssetMetadata, TNetworks, MoonbeamAssetInfo, DemocracyStandardAccountVote, AcalaAssetMetadata} from './types'; +import {hexToU8a} from '@polkadot/util/hex'; +import {u8aConcat} from '@polkadot/util/u8a'; +import { + IApiListeners, + IBlock, + IEvent, + IChainProperties, + ICollectionCreationOptions, + ICollectionLimits, + ICollectionPermissions, + ICrossAccountId, + ICrossAccountIdLower, + ILogger, + INestingPermissions, + IProperty, + IStakingInfo, + ISchedulerOptions, + ISubstrateBalance, + IToken, + ITokenPropertyPermission, + ITransactionResult, + IUniqueHelperLog, + TApiAllowedListeners, + TEthereumAccount, + TSigner, + TSubstrateAccount, + TNetworks, + IForeignAssetMetadata, + AcalaAssetMetadata, + MoonbeamAssetInfo, + DemocracyStandardAccountVote, + IEthCrossAccountId, +} from './types'; +import {RuntimeDispatchInfo} from '@polkadot/types/interfaces'; +import type {Vec} from '@polkadot/types-codec'; +import {FrameSystemEventRecord} from '@polkadot/types/lookup'; export class CrossAccountId implements ICrossAccountId { Substrate?: TSubstrateAccount; @@ -38,7 +73,7 @@ export class CrossAccountId implements ICrossAccountId { static withNormalizedSubstrate(address: TSubstrateAccount, ss58Format = 42): CrossAccountId { return new CrossAccountId({Substrate: CrossAccountId.normalizeSubstrateAddress(address, ss58Format)}); } - + withNormalizedSubstrate(ss58Format = 42): CrossAccountId { if (this.Substrate) return CrossAccountId.withNormalizedSubstrate(this.Substrate, ss58Format); return this; @@ -61,7 +96,7 @@ export class CrossAccountId implements ICrossAccountId { if (this.Ethereum) return new CrossAccountId({Substrate: CrossAccountId.translateEthToSub(this.Ethereum, ss58Format)}); return this; } - + toLowerCase(): CrossAccountId { if (this.Substrate) this.Substrate = this.Substrate.toLowerCase(); if (this.Ethereum) this.Ethereum = this.Ethereum.toLowerCase(); @@ -161,7 +196,7 @@ class UniqueUtil { } static extractTokensFromCreationResult(creationResult: ITransactionResult): { - success: boolean, + success: boolean, tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[], } { if (creationResult.status !== this.transactionStatus.SUCCESS) { @@ -185,7 +220,7 @@ class UniqueUtil { } static extractTokensFromBurnResult(burnResult: ITransactionResult): { - success: boolean, + success: boolean, tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[], } { if (burnResult.status !== this.transactionStatus.SUCCESS) { @@ -256,7 +291,7 @@ class UniqueUtil { static bigIntToDecimals(number: bigint, decimals = 18) { const numberStr = number.toString(); const dotPos = numberStr.length - decimals; - + if (dotPos <= 0) { return '0.' + '0'.repeat(Math.abs(dotPos)) + numberStr; } else { @@ -286,13 +321,17 @@ class UniqueEventHelper { return obj; } - + + private static toHuman(data: any) { + return data && data.toHuman ? data.toHuman() : `${data}`; + } + private static extractData(data: any, type: any): any { - if(!type) return data.toHuman(); + if(!type) return this.toHuman(data); if (['u16', 'u32'].indexOf(type.type) > -1) return data.toNumber(); if (['u64', 'u128', 'u256'].indexOf(type.type) > -1) return data.toBigInt(); if(type.hasOwnProperty('sub')) return this.extractSub(data, type.sub); - return data.toHuman(); + return this.toHuman(data); } public static extractEvents(events: {event: any, phase: any}[]): IEvent[] { @@ -332,6 +371,7 @@ export class ChainHelperBase { api: ApiPromise | null; forcedNetwork: TNetworks | null; network: TNetworks | null; + wsEndpoint: string | null; chainLog: IUniqueHelperLog[]; children: ChainHelperBase[]; address: AddressGroup; @@ -347,6 +387,7 @@ export class ChainHelperBase { this.api = null; this.forcedNetwork = null; this.network = null; + this.wsEndpoint = null; this.chainLog = []; this.children = []; this.address = new AddressGroup(this); @@ -366,11 +407,31 @@ export class ChainHelperBase { return newHelper; } + getEndpoint(): string { + if (this.wsEndpoint === null) throw Error('No connection was established'); + return this.wsEndpoint; + } + getApi(): ApiPromise { if(this.api === null) throw Error('API not initialized'); return this.api; } + async subscribeEvents(expectedEvents: {section: string, names: string[]}[]) { + const collectedEvents: IEvent[] = []; + const unsubscribe = await this.getApi().query.system.events((events: Vec) => { + const ievents = this.eventHelper.extractEvents(events); + ievents.forEach((event) => { + expectedEvents.forEach((e => { + if (event.section === e.section && e.names.includes(event.method)) { + collectedEvents.push(event); + } + })); + }); + }); + return {unsubscribe: unsubscribe as any, collectedEvents}; + } + clearChainLog(): void { this.chainLog = []; } @@ -382,6 +443,7 @@ export class ChainHelperBase { async connect(wsEndpoint: string, listeners?: IApiListeners) { if (this.api !== null) throw Error('Already connected'); const {api, network} = await ChainHelperBase.createConnection(wsEndpoint, listeners, this.forcedNetwork); + this.wsEndpoint = wsEndpoint; this.api = api; this.network = network; } @@ -532,6 +594,40 @@ export class ChainHelperBase { }); } + async signTransactionWithoutSending(signer: TSigner, tx: any) { + const api = this.getApi(); + const signingInfo = await api.derive.tx.signingInfo(signer.address); + + tx.sign(signer, { + blockHash: api.genesisHash, + genesisHash: api.genesisHash, + runtimeVersion: api.runtimeVersion, + nonce: signingInfo.nonce, + }); + + return tx.toHex(); + } + + async getPaymentInfo(signer: TSigner, tx: any, len: number | null) { + const api = this.getApi(); + const signingInfo = await api.derive.tx.signingInfo(signer.address); + + // We need to sign the tx because + // unsigned transactions does not have an inclusion fee + tx.sign(signer, { + blockHash: api.genesisHash, + genesisHash: api.genesisHash, + runtimeVersion: api.runtimeVersion, + nonce: signingInfo.nonce, + }); + + if (len === null) { + return (await this.callRpc('api.rpc.payment.queryInfo', [tx.toHex()])) as RuntimeDispatchInfo; + } else { + return (await api.call.transactionPaymentApi.queryInfo(tx, len)) as RuntimeDispatchInfo; + } + } + constructApiCall(apiCall: string, params: any[]) { if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`); let call = this.getApi() as any; @@ -781,7 +877,7 @@ class CollectionGroup extends HelperGroup { true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorSet'); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorSet'); } /** @@ -799,7 +895,7 @@ class CollectionGroup extends HelperGroup { true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'SponsorshipConfirmed'); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'SponsorshipConfirmed'); } /** @@ -817,7 +913,7 @@ class CollectionGroup extends HelperGroup { true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorRemoved'); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorRemoved'); } /** @@ -844,7 +940,7 @@ class CollectionGroup extends HelperGroup { true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionLimitSet'); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionLimitSet'); } /** @@ -863,7 +959,7 @@ class CollectionGroup extends HelperGroup { true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionOwnedChanged'); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionOwnerChanged'); } /** @@ -882,7 +978,7 @@ class CollectionGroup extends HelperGroup { true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminAdded'); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminAdded'); } /** @@ -901,12 +997,12 @@ class CollectionGroup extends HelperGroup { true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminRemoved'); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminRemoved'); } /** * Check if user is in allow list. - * + * * @param collectionId ID of collection * @param user Account to check * @example await getAdmins(1) @@ -930,7 +1026,7 @@ class CollectionGroup extends HelperGroup { true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressAdded'); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressAdded'); } /** @@ -948,7 +1044,7 @@ class CollectionGroup extends HelperGroup { true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressRemoved'); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressRemoved'); } /** @@ -967,7 +1063,7 @@ class CollectionGroup extends HelperGroup { true, ); - return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionPermissionSet'); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPermissionSet'); } /** @@ -1016,7 +1112,7 @@ class CollectionGroup extends HelperGroup { /** * Get collection properties. - * + * * @param collectionId ID of collection * @param propertyKeys optionally filter the returned properties to only these keys * @example getProperties(1219, ['location', 'date', 'time', 'isParadise']); @@ -1029,7 +1125,7 @@ class CollectionGroup extends HelperGroup { async getPropertiesConsumedSpace(collectionId: number): Promise { const api = this.helper.getApi(); const props = (await api.query.common.collectionProperties(collectionId)).toJSON(); - + return (props! as any).consumedSpace; } @@ -1244,8 +1340,8 @@ class NFTnRFT extends CollectionGroup { if (tokenData === null || tokenData.owner === null) return null; const owner = {} as any; for (const key of Object.keys(tokenData.owner)) { - owner[key.toLocaleLowerCase()] = key.toLocaleLowerCase() == 'substrate' - ? CrossAccountId.normalizeSubstrateAddress(tokenData.owner[key]) + owner[key.toLocaleLowerCase()] = key.toLocaleLowerCase() == 'substrate' + ? CrossAccountId.normalizeSubstrateAddress(tokenData.owner[key]) : tokenData.owner[key]; } tokenData.normalizedOwner = CrossAccountId.fromLowerCaseKeys(owner); @@ -1275,7 +1371,7 @@ class NFTnRFT extends CollectionGroup { /** * Get token property permissions. - * + * * @param collectionId ID of collection * @param propertyKeys optionally filter the returned property permissions to only these keys * @example getPropertyPermissions(1219, ['location', 'date', 'time', 'isParadise']); @@ -1307,7 +1403,7 @@ class NFTnRFT extends CollectionGroup { /** * Get properties, metadata assigned to a token. - * + * * @param collectionId ID of collection * @param tokenId ID of token * @param propertyKeys optionally filter the returned properties to only these keys @@ -1367,6 +1463,32 @@ class NFTnRFT extends CollectionGroup { getTokenObject(_collectionId: number, _tokenId: number): any { return null; } + + /** + * Tells whether the given `owner` approves the `operator`. + * @param collectionId ID of collection + * @param owner owner address + * @param operator operator addrees + * @returns true if operator is enabled + */ + async allowanceForAll(collectionId: number, owner: ICrossAccountId, operator: ICrossAccountId): Promise { + return (await this.helper.callRpc('api.rpc.unique.allowanceForAll', [collectionId, owner, operator])).toJSON(); + } + + /** Sets or unsets the approval of a given operator. + * The `operator` is allowed to transfer all tokens of the `caller` on their behalf. + * @param operator Operator + * @param approved Should operator status be granted or revoked? + * @returns ```true``` if extrinsic success, otherwise ```false``` + */ + async setAllowanceForAll(signer: TSigner, collectionId: number, operator: ICrossAccountId, approved: boolean): Promise { + const result = await this.helper.executeExtrinsic( + signer, + 'api.tx.unique.setAllowanceForAll', [collectionId, operator, approved], + true, + ); + return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'ApprovedForAll'); + } } @@ -2099,6 +2221,15 @@ class ChainGroup extends HelperGroup { return (await this.helper.callRpc('api.rpc.chain.getBlock', [blockHash])).toHuman().block; } + /** + * Get latest relay block + * @returns {number} relay block + */ + async getRelayBlockNumber(): Promise { + const blockNumber = (await this.helper.callRpc('api.query.parachainSystem.validationData')).toJSON().relayParentNumber; + return BigInt(blockNumber); + } + /** * Get account nonce * @param address substrate address @@ -2142,8 +2273,8 @@ class SubstrateBalanceGroup extends HelperGroup { }; } }); - const isSuccess = this.helper.address.normalizeSubstrate(typeof signer === 'string' ? signer : signer.address) === transfer.from - && this.helper.address.normalizeSubstrate(address) === transfer.to + const isSuccess = this.helper.address.normalizeSubstrate(typeof signer === 'string' ? signer : signer.address) === transfer.from + && this.helper.address.normalizeSubstrate(address) === transfer.to && BigInt(amount) === transfer.amount; return isSuccess; } @@ -2157,6 +2288,11 @@ class SubstrateBalanceGroup extends HelperGroup { const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data; return {free: accountInfo.free.toBigInt(), miscFrozen: accountInfo.miscFrozen.toBigInt(), feeFrozen: accountInfo.feeFrozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()}; } + + async getLocked(address: TSubstrateAccount): Promise<[{id: string, amount: bigint, reason: string}]> { + const locks = (await this.helper.callRpc('api.query.balances.locks', [address])).toHuman(); + return locks.map((lock: any) => {return {id: lock.id, amount: BigInt(lock.amount.replace(/,/g, '')), reasons: lock.reasons};}); + } } class EthereumBalanceGroup extends HelperGroup { @@ -2191,8 +2327,8 @@ class EthereumBalanceGroup extends HelperGroup { }; } }); - const isSuccess = (typeof signer === 'string' ? signer : signer.address) === transfer.from - && address === transfer.to + const isSuccess = (typeof signer === 'string' ? signer : signer.address) === transfer.from + && address === transfer.to && BigInt(amount) === transfer.amount; return isSuccess; } @@ -2240,6 +2376,15 @@ class BalanceGroup extends HelperGroup { return this.subBalanceGroup.getSubstrateFull(address); } + /** + * Get locked balances + * @param address substrate address + * @returns locked balances with reason via api.query.balances.locks + */ + getLocked(address: TSubstrateAccount) { + return this.subBalanceGroup.getLocked(address); + } + /** * Get ethereum address balance * @param address ethereum address @@ -2261,6 +2406,71 @@ class BalanceGroup extends HelperGroup { transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise { return this.subBalanceGroup.transferToSubstrate(signer, address, amount); } + + async forceTransferToSubstrate(signer: TSigner, from: TSubstrateAccount, to: TSubstrateAccount, amount: bigint | string): Promise { + const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceTransfer', [from, to, amount], true); + + let transfer = {from: null, to: null, amount: 0n} as any; + result.result.events.forEach(({event: {data, method, section}}) => { + if ((section === 'balances') && (method === 'Transfer')) { + transfer = { + from: this.helper.address.normalizeSubstrate(data[0]), + to: this.helper.address.normalizeSubstrate(data[1]), + amount: BigInt(data[2]), + }; + } + }); + let isSuccess = this.helper.address.normalizeSubstrate(from) === transfer.from; + isSuccess = isSuccess && this.helper.address.normalizeSubstrate(to) === transfer.to; + isSuccess = isSuccess && BigInt(amount) === transfer.amount; + return isSuccess; + } + + /** + * Transfer tokens with the unlock period + * @param signer signers Keyring + * @param address Substrate address of recipient + * @param schedule Schedule params + * @example vestedTransfer(signer, recepient.address, 20000, 100, 10, 50 * nominal); // total amount of vested tokens will be 100 * 50 = 5000 + */ + async vestedTransfer(signer: TSigner, address: TSubstrateAccount, schedule: {start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint}): Promise { + const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.vestedTransfer', [address, schedule]); + const event = result.result.events + .find(e => e.event.section === 'vesting' && + e.event.method === 'VestingScheduleAdded' && + e.event.data[0].toHuman() === signer.address); + if (!event) throw Error('Cannot find transfer in events'); + } + + /** + * Get schedule for recepient of vested transfer + * @param address Substrate address of recipient + * @returns + */ + async getVestingSchedules(address: TSubstrateAccount): Promise<{start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint}[]> { + const schedule = (await this.helper.callRpc('api.query.vesting.vestingSchedules', [address])).toJSON(); + return schedule.map((schedule: any) => { + return { + start: BigInt(schedule.start), + period: BigInt(schedule.period), + periodCount: BigInt(schedule.periodCount), + perPeriod: BigInt(schedule.perPeriod), + }; + }); + } + + /** + * Claim vested tokens + * @param signer signers Keyring + */ + async claim(signer: TSigner) { + const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.claim', []); + const event = result.result.events + .find(e => e.event.section === 'vesting' && + e.event.method === 'Claimed' && + e.event.data[0].toHuman() === signer.address); + if (!event) throw Error('Cannot find claim in events'); + } } class AddressGroup extends HelperGroup { @@ -2306,6 +2516,73 @@ class AddressGroup extends HelperGroup { return CrossAccountId.translateSubToEth(subAddress); } + /** + * Encode key to substrate address + * @param key key for encoding address + * @param ss58Format prefix for encoding to the address of the corresponding network + * @returns encoded substrate address + */ + encodeSubstrateAddress (key: Uint8Array | string | bigint, ss58Format = 42): string { + const u8a :Uint8Array = typeof key === 'string' + ? hexToU8a(key) + : typeof key === 'bigint' + ? hexToU8a(key.toString(16)) + : key; + + if (ss58Format < 0 || ss58Format > 16383 || [46, 47].includes(ss58Format)) { + throw new Error(`ss58Format is not valid, received ${typeof ss58Format} "${ss58Format}"`); + } + + const allowedDecodedLengths = [1, 2, 4, 8, 32, 33]; + if (!allowedDecodedLengths.includes(u8a.length)) { + throw new Error(`key length is not valid, received ${u8a.length}, valid values are ${allowedDecodedLengths.join(', ')}`); + } + + const u8aPrefix = ss58Format < 64 + ? new Uint8Array([ss58Format]) + : new Uint8Array([ + ((ss58Format & 0xfc) >> 2) | 0x40, + (ss58Format >> 8) | ((ss58Format & 0x03) << 6), + ]); + + const input = u8aConcat(u8aPrefix, u8a); + + return base58Encode(u8aConcat( + input, + blake2AsU8a(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1), + )); + } + + /** + * Restore substrate address from bigint representation + * @param number decimal representation of substrate address + * @returns substrate address + */ + restoreCrossAccountFromBigInt(number: bigint): TSubstrateAccount { + if (this.helper.api === null) { + throw 'Not connected'; + } + const res = this.helper.api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON(); + if (res === undefined || res === null) { + throw 'Restore address error'; + } + return res.toString(); + } + + /** + * Convert etherium cross account id to substrate cross account id + * @param ethCrossAccount etherium cross account + * @returns substrate cross account id + */ + convertCrossAccountFromEthCrossAccount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId { + if (ethCrossAccount.sub === '0') { + return {Ethereum: ethCrossAccount.eth.toLocaleLowerCase()}; + } + + const ss58 = this.restoreCrossAccountFromBigInt(BigInt(ethCrossAccount.sub)); + return {Substrate: ss58}; + } + paraSiblingSovereignAccount(paraid: number) { // We are getting a *sibling* parachain sovereign account, // so we need a sibling prefix: encoded(b"sibl") == 0x7369626c @@ -2371,7 +2648,7 @@ class StakingGroup extends HelperGroup { async getTotalStakedPerBlock(address: ICrossAccountId): Promise { const rawTotalStakerdPerBlock = await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address]); return rawTotalStakerdPerBlock.map(([block, amount]: any[]) => { - return { + return { block: block.toBigInt(), amount: amount.toBigInt(), }; @@ -2428,24 +2705,21 @@ class SchedulerGroup extends HelperGroup { } scheduleAt( - scheduledId: string, executionBlockNumber: number, options: ISchedulerOptions = {}, ) { - return this.schedule('scheduleNamed', scheduledId, executionBlockNumber, options); + return this.schedule('schedule', executionBlockNumber, options); } scheduleAfter( - scheduledId: string, blocksBeforeExecution: number, options: ISchedulerOptions = {}, ) { - return this.schedule('scheduleNamedAfter', scheduledId, blocksBeforeExecution, options); + return this.schedule('scheduleAfter', blocksBeforeExecution, options); } schedule( - scheduleFn: 'scheduleNamed' | 'scheduleNamedAfter', - scheduledId: string, + scheduleFn: 'schedule' | 'scheduleAfter', blocksNum: number, options: ISchedulerOptions = {}, ) { @@ -2453,7 +2727,6 @@ class SchedulerGroup extends HelperGroup { const ScheduledHelperType = ScheduledUniqueHelper(this.helper.helperBase); return this.helper.clone(ScheduledHelperType, { scheduleFn, - scheduledId, blocksNum, options, }) as T; @@ -2489,21 +2762,72 @@ class XcmGroup extends HelperGroup { this.palletName = palletName; } - async limitedReserveTransferAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number, weightLimit: number) { - await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, {Limited: weightLimit}], true); + async limitedReserveTransferAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number, weightLimit: any) { + await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, weightLimit], true); + } + + async teleportAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number) { + await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.teleportAssets`, [destination, beneficiary, assets, feeAssetItem], true); + } + + async teleportNativeAsset(signer: TSigner, destinationParaId: number, targetAccount: Uint8Array, amount: bigint) { + const destination = { + V1: { + parents: 0, + interior: { + X1: { + Parachain: destinationParaId, + }, + }, + }, + }; + + const beneficiary = { + V1: { + parents: 0, + interior: { + X1: { + AccountId32: { + network: 'Any', + id: targetAccount, + }, + }, + }, + }, + }; + + const assets = { + V1: [ + { + id: { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + fun: { + Fungible: amount, + }, + }, + ], + }; + + const feeAssetItem = 0; + + await this.teleportAssets(signer, destination, beneficiary, assets, feeAssetItem); } } class XTokensGroup extends HelperGroup { - async transfer(signer: TSigner, currencyId: any, amount: bigint, destination: any, destWeight: number) { + async transfer(signer: TSigner, currencyId: any, amount: bigint, destination: any, destWeight: any) { await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transfer', [currencyId, amount, destination, destWeight], true); } - async transferMultiasset(signer: TSigner, asset: any, destination: any, destWeight: number) { + async transferMultiasset(signer: TSigner, asset: any, destination: any, destWeight: any) { await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMultiasset', [asset, destination, destWeight], true); } - async transferMulticurrencies(signer: TSigner, currencies: any[], feeItem: number, destLocation: any, destWeight: number) { + async transferMulticurrencies(signer: TSigner, currencies: any[], feeItem: number, destLocation: any, destWeight: any) { await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMulticurrencies', [currencies, feeItem, destLocation, destWeight], true); } } @@ -2572,12 +2896,19 @@ class MoonbeamAssetManagerGroup extends HelperGroup { } class MoonbeamDemocracyGroup extends HelperGroup { + notePreimagePallet: string; + + constructor(helper: MoonbeamHelper, options: {[key: string]: any} = {}) { + super(helper); + this.notePreimagePallet = options.notePreimagePallet; + } + async notePreimage(signer: TSigner, encodedProposal: string) { - await this.helper.executeExtrinsic(signer, 'api.tx.democracy.notePreimage', [encodedProposal], true); + await this.helper.executeExtrinsic(signer, `api.tx.${this.notePreimagePallet}.notePreimage`, [encodedProposal], true); } - externalProposeMajority(proposalHash: string) { - return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposalHash]); + externalProposeMajority(proposal: any) { + return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposal]); } fastTrack(proposalHash: string, votingPeriod: number, delayPeriod: number) { @@ -2606,7 +2937,7 @@ class MoonbeamCollectiveGroup extends HelperGroup { await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve], true); } - async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: number, lengthBound: number) { + async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: any, lengthBound: number) { await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [proposalHash, proposalIndex, weightBound, lengthBound], true); } @@ -2666,11 +2997,13 @@ export class XcmChainHelper extends ChainHelperBase { } export class RelayHelper extends XcmChainHelper { + balance: SubstrateBalanceGroup; xcm: XcmGroup; constructor(logger?: ILogger, options: {[key: string]: any} = {}) { super(logger, options.helperBase ?? RelayHelper); + this.balance = new SubstrateBalanceGroup(this); this.xcm = new XcmGroup(this, 'xcmPallet'); } } @@ -2709,7 +3042,7 @@ export class MoonbeamHelper extends XcmChainHelper { this.assetManager = new MoonbeamAssetManagerGroup(this); this.assets = new AssetsGroup(this); this.xTokens = new XTokensGroup(this); - this.democracy = new MoonbeamDemocracyGroup(this); + this.democracy = new MoonbeamDemocracyGroup(this, options); this.collective = { council: new MoonbeamCollectiveGroup(this, 'councilCollective'), techCommittee: new MoonbeamCollectiveGroup(this, 'techCommitteeCollective'), @@ -2742,16 +3075,14 @@ export class AcalaHelper extends XcmChainHelper { // eslint-disable-next-line @typescript-eslint/naming-convention function ScheduledUniqueHelper(Base: T) { return class extends Base { - scheduleFn: 'scheduleNamed' | 'scheduleNamedAfter'; - scheduledId: string; + scheduleFn: 'schedule' | 'scheduleAfter'; blocksNum: number; options: ISchedulerOptions; constructor(...args: any[]) { const logger = args[0] as ILogger; const options = args[1] as { - scheduleFn: 'scheduleNamed' | 'scheduleNamedAfter', - scheduledId: string, + scheduleFn: 'schedule' | 'scheduleAfter', blocksNum: number, options: ISchedulerOptions }; @@ -2759,25 +3090,42 @@ function ScheduledUniqueHelper(Base: T) { super(logger); this.scheduleFn = options.scheduleFn; - this.scheduledId = options.scheduledId; this.blocksNum = options.blocksNum; this.options = options.options; } executeExtrinsic(sender: IKeyringPair, scheduledExtrinsic: string, scheduledParams: any[], expectSuccess?: boolean): Promise { const scheduledTx = this.constructApiCall(scheduledExtrinsic, scheduledParams); - const extrinsic = 'api.tx.scheduler.' + this.scheduleFn; + + const mandatorySchedArgs = [ + this.blocksNum, + this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null, + this.options.priority ?? null, + scheduledTx, + ]; + + let schedArgs; + let scheduleFn; + + if (this.options.scheduledId) { + schedArgs = [this.options.scheduledId!, ...mandatorySchedArgs]; + + if (this.scheduleFn == 'schedule') { + scheduleFn = 'scheduleNamed'; + } else if (this.scheduleFn == 'scheduleAfter') { + scheduleFn = 'scheduleNamedAfter'; + } + } else { + schedArgs = mandatorySchedArgs; + scheduleFn = this.scheduleFn; + } + + const extrinsic = 'api.tx.scheduler.' + scheduleFn; return super.executeExtrinsic( sender, extrinsic, - [ - this.scheduledId, - this.blocksNum, - this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null, - this.options.priority ?? null, - {Value: scheduledTx}, - ], + schedArgs, expectSuccess, ); } @@ -2798,7 +3146,6 @@ function SudoHelper(Base: T) { expectSuccess?: boolean, ): Promise { const call = this.constructApiCall(extrinsic, params); - return super.executeExtrinsic( sender, 'api.tx.sudo.sudo', @@ -2919,20 +3266,18 @@ export class UniqueBaseCollection { } scheduleAt( - scheduledId: string, executionBlockNumber: number, options: ISchedulerOptions = {}, ) { - const scheduledHelper = this.helper.scheduler.scheduleAt(scheduledId, executionBlockNumber, options); + const scheduledHelper = this.helper.scheduler.scheduleAt(executionBlockNumber, options); return new UniqueBaseCollection(this.collectionId, scheduledHelper); } scheduleAfter( - scheduledId: string, blocksBeforeExecution: number, options: ISchedulerOptions = {}, ) { - const scheduledHelper = this.helper.scheduler.scheduleAfter(scheduledId, blocksBeforeExecution, options); + const scheduledHelper = this.helper.scheduler.scheduleAfter(blocksBeforeExecution, options); return new UniqueBaseCollection(this.collectionId, scheduledHelper); } @@ -2978,7 +3323,7 @@ export class UniqueNFTCollection extends UniqueBaseCollection { async getTokenPropertiesConsumedSpace(tokenId: number): Promise { const api = this.helper.getApi(); const props = (await api.query.nonfungible.tokenProperties(this.collectionId, tokenId)).toJSON(); - + return (props! as any).consumedSpace; } @@ -3035,20 +3380,18 @@ export class UniqueNFTCollection extends UniqueBaseCollection { } scheduleAt( - scheduledId: string, executionBlockNumber: number, options: ISchedulerOptions = {}, ) { - const scheduledHelper = this.helper.scheduler.scheduleAt(scheduledId, executionBlockNumber, options); + const scheduledHelper = this.helper.scheduler.scheduleAt(executionBlockNumber, options); return new UniqueNFTCollection(this.collectionId, scheduledHelper); } scheduleAfter( - scheduledId: string, blocksBeforeExecution: number, options: ISchedulerOptions = {}, ) { - const scheduledHelper = this.helper.scheduler.scheduleAfter(scheduledId, blocksBeforeExecution, options); + const scheduledHelper = this.helper.scheduler.scheduleAfter(blocksBeforeExecution, options); return new UniqueNFTCollection(this.collectionId, scheduledHelper); } @@ -3098,7 +3441,7 @@ export class UniqueRFTCollection extends UniqueBaseCollection { async getTokenPropertiesConsumedSpace(tokenId: number): Promise { const api = this.helper.getApi(); const props = (await api.query.refungible.tokenProperties(this.collectionId, tokenId)).toJSON(); - + return (props! as any).consumedSpace; } @@ -3147,20 +3490,18 @@ export class UniqueRFTCollection extends UniqueBaseCollection { } scheduleAt( - scheduledId: string, executionBlockNumber: number, options: ISchedulerOptions = {}, ) { - const scheduledHelper = this.helper.scheduler.scheduleAt(scheduledId, executionBlockNumber, options); + const scheduledHelper = this.helper.scheduler.scheduleAt(executionBlockNumber, options); return new UniqueRFTCollection(this.collectionId, scheduledHelper); } scheduleAfter( - scheduledId: string, blocksBeforeExecution: number, options: ISchedulerOptions = {}, ) { - const scheduledHelper = this.helper.scheduler.scheduleAfter(scheduledId, blocksBeforeExecution, options); + const scheduledHelper = this.helper.scheduler.scheduleAfter(blocksBeforeExecution, options); return new UniqueRFTCollection(this.collectionId, scheduledHelper); } @@ -3216,20 +3557,18 @@ export class UniqueFTCollection extends UniqueBaseCollection { } scheduleAt( - scheduledId: string, executionBlockNumber: number, options: ISchedulerOptions = {}, ) { - const scheduledHelper = this.helper.scheduler.scheduleAt(scheduledId, executionBlockNumber, options); + const scheduledHelper = this.helper.scheduler.scheduleAt(executionBlockNumber, options); return new UniqueFTCollection(this.collectionId, scheduledHelper); } scheduleAfter( - scheduledId: string, blocksBeforeExecution: number, options: ISchedulerOptions = {}, ) { - const scheduledHelper = this.helper.scheduler.scheduleAfter(scheduledId, blocksBeforeExecution, options); + const scheduledHelper = this.helper.scheduler.scheduleAfter(blocksBeforeExecution, options); return new UniqueFTCollection(this.collectionId, scheduledHelper); } @@ -3279,20 +3618,18 @@ export class UniqueBaseToken { } scheduleAt( - scheduledId: string, executionBlockNumber: number, options: ISchedulerOptions = {}, ) { - const scheduledCollection = this.collection.scheduleAt(scheduledId, executionBlockNumber, options); + const scheduledCollection = this.collection.scheduleAt(executionBlockNumber, options); return new UniqueBaseToken(this.tokenId, scheduledCollection); } scheduleAfter( - scheduledId: string, blocksBeforeExecution: number, options: ISchedulerOptions = {}, ) { - const scheduledCollection = this.collection.scheduleAfter(scheduledId, blocksBeforeExecution, options); + const scheduledCollection = this.collection.scheduleAfter(blocksBeforeExecution, options); return new UniqueBaseToken(this.tokenId, scheduledCollection); } @@ -3359,20 +3696,18 @@ export class UniqueNFToken extends UniqueBaseToken { } scheduleAt( - scheduledId: string, executionBlockNumber: number, options: ISchedulerOptions = {}, ) { - const scheduledCollection = this.collection.scheduleAt(scheduledId, executionBlockNumber, options); + const scheduledCollection = this.collection.scheduleAt(executionBlockNumber, options); return new UniqueNFToken(this.tokenId, scheduledCollection); } scheduleAfter( - scheduledId: string, blocksBeforeExecution: number, options: ISchedulerOptions = {}, ) { - const scheduledCollection = this.collection.scheduleAfter(scheduledId, blocksBeforeExecution, options); + const scheduledCollection = this.collection.scheduleAfter(blocksBeforeExecution, options); return new UniqueNFToken(this.tokenId, scheduledCollection); } @@ -3434,20 +3769,18 @@ export class UniqueRFToken extends UniqueBaseToken { } scheduleAt( - scheduledId: string, executionBlockNumber: number, options: ISchedulerOptions = {}, ) { - const scheduledCollection = this.collection.scheduleAt(scheduledId, executionBlockNumber, options); + const scheduledCollection = this.collection.scheduleAt(executionBlockNumber, options); return new UniqueRFToken(this.tokenId, scheduledCollection); } scheduleAfter( - scheduledId: string, blocksBeforeExecution: number, options: ISchedulerOptions = {}, ) { - const scheduledCollection = this.collection.scheduleAfter(scheduledId, blocksBeforeExecution, options); + const scheduledCollection = this.collection.scheduleAfter(blocksBeforeExecution, options); return new UniqueRFToken(this.tokenId, scheduledCollection); } diff --git a/tests/src/vesting.test.ts b/tests/src/vesting.test.ts new file mode 100644 index 0000000000..9b36f0945d --- /dev/null +++ b/tests/src/vesting.test.ts @@ -0,0 +1,160 @@ +// Copyright 2019-2022 Unique Network (Gibraltar) Ltd. +// This file is part of Unique Network. + +// Unique Network is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Unique Network is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Unique Network. If not, see . + +import {IKeyringPair} from '@polkadot/types/types'; +import {itSub, usingPlaygrounds, expect} from './util'; + +describe('Vesting', () => { + let donor: IKeyringPair; + let nominal: bigint; + + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + donor = await privateKey({filename: __filename}); + nominal = helper.balance.getOneTokenNominal(); + }); + }); + + itSub('can perform vestedTransfer and claim tokens', async ({helper}) => { + // arrange + const [sender, recepient] = await helper.arrange.createAccounts([1000n, 1n], donor); + const currentRelayBlock = await helper.chain.getRelayBlockNumber(); + const SCHEDULE_1_PERIOD = 6n; // 6 blocks one period + const SCHEDULE_1_START = currentRelayBlock + 6n; // Block when 1 schedule starts + const SCHEDULE_2_PERIOD = 12n; // 12 blocks one period + const SCHEDULE_2_START = currentRelayBlock + 12n; // Block when 2 schedule starts + const schedule1 = {start: SCHEDULE_1_START, period: SCHEDULE_1_PERIOD, periodCount: 2n, perPeriod: 50n * nominal}; + const schedule2 = {start: SCHEDULE_2_START, period: SCHEDULE_2_PERIOD, periodCount: 2n, perPeriod: 100n * nominal}; + + // act + await helper.balance.vestedTransfer(sender, recepient.address, schedule1); + await helper.balance.vestedTransfer(sender, recepient.address, schedule2); + let schedule = await helper.balance.getVestingSchedules(recepient.address); + + // check senders balance after vesting: + let balanceSender = await helper.balance.getSubstrateFull(sender.address); + expect(balanceSender.free / nominal).to.eq(699n); + expect(balanceSender.feeFrozen).to.eq(0n); + expect(balanceSender.miscFrozen).to.eq(0n); + expect(balanceSender.reserved).to.eq(0n); + + // check recepient balance after vesting: + let balanceRecepient = await helper.balance.getSubstrateFull(recepient.address); + expect(balanceRecepient.free).to.eq(301n * nominal); + expect(balanceRecepient.feeFrozen).to.eq(300n * nominal); + expect(balanceRecepient.miscFrozen).to.eq(300n * nominal); + expect(balanceRecepient.reserved).to.eq(0n); + + // Schedules list correct: + expect(schedule).to.has.length(2); + expect(schedule[0]).to.deep.eq(schedule1); + expect(schedule[1]).to.deep.eq(schedule2); + + // Wait first part available: + await helper.wait.forRelayBlockNumber(SCHEDULE_1_START + SCHEDULE_1_PERIOD); + await helper.balance.claim(recepient); + + // check recepient balance after claim (50 tokens claimed, 250 left): + balanceRecepient = await helper.balance.getSubstrateFull(recepient.address); + expect(balanceRecepient.free / nominal).to.eq(300n); + expect(balanceRecepient.feeFrozen).to.eq(250n * nominal); + expect(balanceRecepient.miscFrozen).to.eq(250n * nominal); + expect(balanceRecepient.reserved).to.eq(0n); + + // Wait first schedule ends and first part od second schedule: + await helper.wait.forRelayBlockNumber(SCHEDULE_2_START + SCHEDULE_2_PERIOD); + await helper.balance.claim(recepient); + + // check recepient balance after second claim (150 tokens claimed, 100 left): + balanceRecepient = await helper.balance.getSubstrateFull(recepient.address); + expect(balanceRecepient.free / nominal).to.eq(300n); + expect(balanceRecepient.feeFrozen).to.eq(100n * nominal); + expect(balanceRecepient.miscFrozen).to.eq(100n * nominal); + expect(balanceRecepient.reserved).to.eq(0n); + + // Schedules list contain 1 vesting: + schedule = await helper.balance.getVestingSchedules(recepient.address); + expect(schedule).to.has.length(1); + expect(schedule[0]).to.deep.eq(schedule2); + + // Wait 2 schedule ends: + await helper.wait.forRelayBlockNumber(SCHEDULE_2_START + SCHEDULE_2_PERIOD * 2n); + await helper.balance.claim(recepient); + + // check recepient balance after second claim (100 tokens claimed, 0 left): + balanceRecepient = await helper.balance.getSubstrateFull(recepient.address); + expect(balanceRecepient.free / nominal).to.eq(300n); + expect(balanceRecepient.feeFrozen).to.eq(0n); + expect(balanceRecepient.miscFrozen).to.eq(0n); + expect(balanceRecepient.reserved).to.eq(0n); + + // check sender balance does not changed: + balanceSender = await helper.balance.getSubstrateFull(sender.address); + expect(balanceSender.free / nominal).to.eq(699n); + expect(balanceSender.feeFrozen).to.eq(0n); + expect(balanceSender.miscFrozen).to.eq(0n); + expect(balanceSender.reserved).to.eq(0n); + }); + + itSub('cannot send more tokens than have', async ({helper}) => { + const [sender, receiver] = await helper.arrange.createAccounts([1000n, 1n], donor); + const schedule = {start: 0n, period: 1n, periodCount: 1n, perPeriod: 100n * nominal}; + const manyPeriodsSchedule = {start: 0n, period: 1n, periodCount: 100n, perPeriod: 10n * nominal}; + const oneBigSumSchedule = {start: 0n, period: 1n, periodCount: 1n, perPeriod: 5000n * nominal}; + + // Sender cannot send vestedTransfer to self or other + await expect(helper.balance.vestedTransfer(sender, sender.address, manyPeriodsSchedule)).to.be.rejectedWith(/InsufficientBalance/); + await expect(helper.balance.vestedTransfer(sender, receiver.address, manyPeriodsSchedule)).to.be.rejectedWith(/InsufficientBalance/); + await expect(helper.balance.vestedTransfer(sender, sender.address, oneBigSumSchedule)).to.be.rejectedWith(/InsufficientBalance/); + await expect(helper.balance.vestedTransfer(sender, receiver.address, oneBigSumSchedule)).to.be.rejectedWith(/InsufficientBalance/); + + const balanceSender = await helper.balance.getSubstrateFull(sender.address); + const balanceReceiver = await helper.balance.getSubstrateFull(receiver.address); + + // Sender's balance has not changed + expect(balanceSender.free / nominal).to.eq(999n); + expect(balanceSender.feeFrozen).to.eq(0n); + expect(balanceSender.miscFrozen).to.eq(0n); + expect(balanceSender.reserved).to.eq(0n); + + // Receiver's balance has not changed + expect(balanceReceiver.free).to.be.eq(1n * nominal); + expect(balanceReceiver.feeFrozen).to.be.eq(0n); + expect(balanceReceiver.miscFrozen).to.be.eq(0n); + expect(balanceReceiver.reserved).to.be.eq(0n); + + // Receiver cannot send vestedTransfer back because of freeze + await expect(helper.balance.vestedTransfer(receiver, sender.address, schedule)).to.be.rejectedWith(/InsufficientBalance/); + }); + + itSub('cannot send vestedTransfer with incorrect parameters', async ({helper}) => { + const [sender, receiver] = await helper.arrange.createAccounts([1000n, 1n], donor); + const incorrectperiodSchedule = {start: 0n, period: 0n, periodCount: 10n, perPeriod: 10n * nominal}; + const incorrectPeriodCountSchedule = {start: 0n, period: 1n, periodCount: 0n, perPeriod: 10n * nominal}; + const incorrectPerPeriodSchedule = {start: 0n, period: 1n, periodCount: 1n, perPeriod: 0n * nominal}; + + await expect(helper.balance.vestedTransfer(sender, sender.address, incorrectperiodSchedule)).to.be.rejectedWith(/vesting.ZeroVestingPeriod/); + await expect(helper.balance.vestedTransfer(sender, receiver.address, incorrectPeriodCountSchedule)).to.be.rejectedWith(/vesting.ZeroVestingPeriod/); + await expect(helper.balance.vestedTransfer(sender, receiver.address, incorrectPerPeriodSchedule)).to.be.rejectedWith(/vesting.AmountLow/); + + const balanceSender = await helper.balance.getSubstrateFull(sender.address); + // Sender's balance has not changed + expect(balanceSender.free / nominal).to.eq(999n); + expect(balanceSender.feeFrozen).to.eq(0n); + expect(balanceSender.miscFrozen).to.eq(0n); + expect(balanceSender.reserved).to.eq(0n); + }); +}); diff --git a/tests/src/xcm/xcmOpal.test.ts b/tests/src/xcm/xcmOpal.test.ts index 5ba3c4c44c..17871f023b 100644 --- a/tests/src/xcm/xcmOpal.test.ts +++ b/tests/src/xcm/xcmOpal.test.ts @@ -31,17 +31,18 @@ const ASSET_METADATA_NAME = 'USDT'; const ASSET_METADATA_DESCRIPTION = 'USDT'; const ASSET_METADATA_MINIMAL_BALANCE = 1n; +const RELAY_DECIMALS = 12; const WESTMINT_DECIMALS = 12; const TRANSFER_AMOUNT = 1_000_000_000_000_000_000n; // 10,000.00 (ten thousands) USDT -const ASSET_AMOUNT = 1_000_000_000_000_000_000_000n; +const ASSET_AMOUNT = 1_000_000_000_000_000_000_000n; describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => { let alice: IKeyringPair; let bob: IKeyringPair; - + let balanceStmnBefore: bigint; let balanceStmnAfter: bigint; @@ -65,7 +66,7 @@ describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => { await usingWestmintPlaygrounds(westmintUrl, async (helper) => { // 350.00 (three hundred fifty) DOT - const fundingAmount = 3_500_000_000_000n; + const fundingAmount = 3_500_000_000_000n; await helper.assets.create(alice, ASSET_ID, alice.address, ASSET_METADATA_MINIMAL_BALANCE); await helper.assets.setMetadata(alice, ASSET_ID, ASSET_METADATA_NAME, ASSET_METADATA_DESCRIPTION, ASSET_METADATA_DECIMALS); @@ -147,11 +148,10 @@ describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => { }; const feeAssetItem = 0; - const weightLimit = 5_000_000_000; - await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, weightLimit); + await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited'); }); - + }); itSub('Should connect and send USDT from Westmint to Opal', async ({helper}) => { @@ -190,7 +190,7 @@ describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => { }, { GeneralIndex: ASSET_ID, - }, + }, ]}, }, }, @@ -202,16 +202,15 @@ describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => { }; const feeAssetItem = 0; - const weightLimit = 5000000000; balanceStmnBefore = await helper.balance.getSubstrate(alice.address); - await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, weightLimit); + await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited'); balanceStmnAfter = await helper.balance.getSubstrate(alice.address); // common good parachain take commission in it native token console.log( - 'Opal to Westmint transaction fees on Westmint: %s WND', + '[Westmint -> Opal] transaction fees on Westmint: %s WND', helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, WESTMINT_DECIMALS), ); expect(balanceStmnBefore > balanceStmnAfter).to.be.true; @@ -227,18 +226,19 @@ describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => { balanceOpalAfter = await helper.balance.getSubstrate(alice.address); - // commission has not paid in USDT token - expect(free == TRANSFER_AMOUNT).to.be.true; console.log( - 'Opal to Westmint transaction fees on Opal: %s USDT', - helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free), + '[Westmint -> Opal] transaction fees on Opal: %s USDT', + helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, ASSET_METADATA_DECIMALS), + ); + console.log( + '[Westmint -> Opal] transaction fees on Opal: %s OPL', + helper.util.bigIntToDecimals(balanceOpalAfter - balanceOpalBefore), ); + + // commission has not paid in USDT token + expect(free == TRANSFER_AMOUNT).to.be.true; // ... and parachain native token expect(balanceOpalAfter == balanceOpalBefore).to.be.true; - console.log( - 'Opal to Westmint transaction fees on Opal: %s WND', - helper.util.bigIntToDecimals(balanceOpalAfter - balanceOpalBefore, WESTMINT_DECIMALS), - ); }); itSub('Should connect and send USDT from Unique to Statemine back', async ({helper}) => { @@ -266,7 +266,7 @@ describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => { }, //10_000_000_000_000_000n, TRANSFER_AMOUNT, - ], + ], [ { NativeAssetId: 'Parent', @@ -276,19 +276,18 @@ describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => { ]; const feeItem = 1; - const destWeight = 500000000000; - await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, destWeight); - + await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited'); + // the commission has been paid in parachain native token balanceOpalFinal = await helper.balance.getSubstrate(alice.address); expect(balanceOpalAfter > balanceOpalFinal).to.be.true; await usingWestmintPlaygrounds(westmintUrl, async (helper) => { await helper.wait.newBlocks(3); - + // The USDT token never paid fees. Its amount not changed from begin value. - // Also check that xcm transfer has been succeeded + // Also check that xcm transfer has been succeeded expect((await helper.assets.account(ASSET_ID, alice.address))! == ASSET_AMOUNT).to.be.true; }); }); @@ -339,17 +338,16 @@ describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => { }; const feeAssetItem = 0; - const weightLimit = 5_000_000_000; - await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, weightLimit); + await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited'); }); - + await helper.wait.newBlocks(3); - balanceBobAfter = await helper.balance.getSubstrate(bob.address); + balanceBobAfter = await helper.balance.getSubstrate(bob.address); balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'}); - const wndFee = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore; + const wndFee = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore; console.log( 'Relay (Westend) to Opal transaction fees: %s OPL', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore), @@ -363,20 +361,23 @@ describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => { }); itSub('Should connect and send Relay token back', async ({helper}) => { + let relayTokenBalanceBefore: bigint; + let relayTokenBalanceAfter: bigint; + await usingRelayPlaygrounds(relayUrl, async (helper) => { + relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address); + }); + const destination = { V1: { parents: 1, - interior: {X2: [ - { - Parachain: STATEMINE_CHAIN, - }, - { + interior: { + X1:{ AccountId32: { network: 'Any', id: bob.addressRaw, }, }, - ]}, + }, }, }; @@ -390,11 +391,19 @@ describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => { ]; const feeItem = 0; - const destWeight = 500000000000; - await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, destWeight); + await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited'); balanceBobFinal = await helper.balance.getSubstrate(bob.address); - console.log('Relay (Westend) to Opal transaction fees: %s OPL', balanceBobAfter - balanceBobFinal); + console.log('[Opal -> Relay (Westend)] transaction fees: %s OPL', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal)); + + await usingRelayPlaygrounds(relayUrl, async (helper) => { + await helper.wait.newBlocks(10); + relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address); + + const diff = relayTokenBalanceAfter - relayTokenBalanceBefore; + console.log('[Opal -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS)); + expect(diff > 0, 'Relay tokens was not delivered back').to.be.true; + }); }); }); diff --git a/tests/src/xcm/xcmQuartz.test.ts b/tests/src/xcm/xcmQuartz.test.ts index eeb8291251..b961e312d6 100644 --- a/tests/src/xcm/xcmQuartz.test.ts +++ b/tests/src/xcm/xcmQuartz.test.ts @@ -17,21 +17,430 @@ import {IKeyringPair} from '@polkadot/types/types'; import {blake2AsHex} from '@polkadot/util-crypto'; import config from '../config'; -import {XcmV2TraitsOutcome, XcmV2TraitsError} from '../interfaces'; -import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds} from '../util'; +import {XcmV2TraitsError} from '../interfaces'; +import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds} from '../util'; const QUARTZ_CHAIN = 2095; +const STATEMINE_CHAIN = 1000; const KARURA_CHAIN = 2000; const MOONRIVER_CHAIN = 2023; +const STATEMINE_PALLET_INSTANCE = 50; + const relayUrl = config.relayUrl; +const statemineUrl = config.statemineUrl; const karuraUrl = config.karuraUrl; const moonriverUrl = config.moonriverUrl; +const RELAY_DECIMALS = 12; +const STATEMINE_DECIMALS = 12; const KARURA_DECIMALS = 12; const TRANSFER_AMOUNT = 2000000000000000000000000n; +const FUNDING_AMOUNT = 3_500_000_0000_000_000n; + +const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n; + +const USDT_ASSET_ID = 100; +const USDT_ASSET_METADATA_DECIMALS = 18; +const USDT_ASSET_METADATA_NAME = 'USDT'; +const USDT_ASSET_METADATA_DESCRIPTION = 'USDT'; +const USDT_ASSET_METADATA_MINIMAL_BALANCE = 1n; +const USDT_ASSET_AMOUNT = 10_000_000_000_000_000_000_000_000n; + +describeXCM('[XCM] Integration test: Exchanging USDT with Statemine', () => { + let alice: IKeyringPair; + let bob: IKeyringPair; + + let balanceStmnBefore: bigint; + let balanceStmnAfter: bigint; + + let balanceQuartzBefore: bigint; + let balanceQuartzAfter: bigint; + let balanceQuartzFinal: bigint; + + let balanceBobBefore: bigint; + let balanceBobAfter: bigint; + let balanceBobFinal: bigint; + + let balanceBobRelayTokenBefore: bigint; + let balanceBobRelayTokenAfter: bigint; + + + before(async () => { + await usingPlaygrounds(async (_helper, privateKey) => { + alice = await privateKey('//Alice'); + bob = await privateKey('//Bob'); // sovereign account on Statemine(t) funds donor + }); + + await usingRelayPlaygrounds(relayUrl, async (helper) => { + // Fund accounts on Statemine(t) + await helper.xcm.teleportNativeAsset(alice, STATEMINE_CHAIN, alice.addressRaw, FUNDING_AMOUNT); + await helper.xcm.teleportNativeAsset(alice, STATEMINE_CHAIN, bob.addressRaw, FUNDING_AMOUNT); + }); + + await usingStateminePlaygrounds(statemineUrl, async (helper) => { + const sovereignFundingAmount = 3_500_000_000n; + + await helper.assets.create( + alice, + USDT_ASSET_ID, + alice.address, + USDT_ASSET_METADATA_MINIMAL_BALANCE, + ); + await helper.assets.setMetadata( + alice, + USDT_ASSET_ID, + USDT_ASSET_METADATA_NAME, + USDT_ASSET_METADATA_DESCRIPTION, + USDT_ASSET_METADATA_DECIMALS, + ); + await helper.assets.mint( + alice, + USDT_ASSET_ID, + alice.address, + USDT_ASSET_AMOUNT, + ); + + // funding parachain sovereing account on Statemine(t). + // The sovereign account should be created before any action + // (the assets pallet on Statemine(t) check if the sovereign account exists) + const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(QUARTZ_CHAIN); + await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, sovereignFundingAmount); + }); + + + await usingPlaygrounds(async (helper) => { + const location = { + V1: { + parents: 1, + interior: {X3: [ + { + Parachain: STATEMINE_CHAIN, + }, + { + PalletInstance: STATEMINE_PALLET_INSTANCE, + }, + { + GeneralIndex: USDT_ASSET_ID, + }, + ]}, + }, + }; + + const metadata = + { + name: USDT_ASSET_ID, + symbol: USDT_ASSET_METADATA_NAME, + decimals: USDT_ASSET_METADATA_DECIMALS, + minimalBalance: USDT_ASSET_METADATA_MINIMAL_BALANCE, + }; + await helper.getSudo().foreignAssets.register(alice, alice.address, location, metadata); + balanceQuartzBefore = await helper.balance.getSubstrate(alice.address); + }); + + + // Providing the relay currency to the quartz sender account + // (fee for USDT XCM are paid in relay tokens) + await usingRelayPlaygrounds(relayUrl, async (helper) => { + const destination = { + V1: { + parents: 0, + interior: {X1: { + Parachain: QUARTZ_CHAIN, + }, + }, + }}; + + const beneficiary = { + V1: { + parents: 0, + interior: {X1: { + AccountId32: { + network: 'Any', + id: alice.addressRaw, + }, + }}, + }, + }; + + const assets = { + V1: [ + { + id: { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + fun: { + Fungible: TRANSFER_AMOUNT_RELAY, + }, + }, + ], + }; + + const feeAssetItem = 0; + + await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited'); + }); + + }); + + itSub('Should connect and send USDT from Statemine to Quartz', async ({helper}) => { + await usingStateminePlaygrounds(statemineUrl, async (helper) => { + const dest = { + V1: { + parents: 1, + interior: {X1: { + Parachain: QUARTZ_CHAIN, + }, + }, + }}; + + const beneficiary = { + V1: { + parents: 0, + interior: {X1: { + AccountId32: { + network: 'Any', + id: alice.addressRaw, + }, + }}, + }, + }; + + const assets = { + V1: [ + { + id: { + Concrete: { + parents: 0, + interior: { + X2: [ + { + PalletInstance: STATEMINE_PALLET_INSTANCE, + }, + { + GeneralIndex: USDT_ASSET_ID, + }, + ]}, + }, + }, + fun: { + Fungible: TRANSFER_AMOUNT, + }, + }, + ], + }; + + const feeAssetItem = 0; + + balanceStmnBefore = await helper.balance.getSubstrate(alice.address); + await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited'); + + balanceStmnAfter = await helper.balance.getSubstrate(alice.address); + + // common good parachain take commission in it native token + console.log( + '[Statemine -> Quartz] transaction fees on Statemine: %s WND', + helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, STATEMINE_DECIMALS), + ); + expect(balanceStmnBefore > balanceStmnAfter).to.be.true; + + }); + + + // ensure that asset has been delivered + await helper.wait.newBlocks(3); + + // expext collection id will be with id 1 + const free = await helper.ft.getBalance(1, {Substrate: alice.address}); + + balanceQuartzAfter = await helper.balance.getSubstrate(alice.address); + + console.log( + '[Statemine -> Quartz] transaction fees on Quartz: %s USDT', + helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, USDT_ASSET_METADATA_DECIMALS), + ); + console.log( + '[Statemine -> Quartz] transaction fees on Quartz: %s QTZ', + helper.util.bigIntToDecimals(balanceQuartzAfter - balanceQuartzBefore), + ); + // commission has not paid in USDT token + expect(free).to.be.equal(TRANSFER_AMOUNT); + // ... and parachain native token + expect(balanceQuartzAfter == balanceQuartzBefore).to.be.true; + }); + + itSub('Should connect and send USDT from Quartz to Statemine back', async ({helper}) => { + const destination = { + V1: { + parents: 1, + interior: {X2: [ + { + Parachain: STATEMINE_CHAIN, + }, + { + AccountId32: { + network: 'Any', + id: alice.addressRaw, + }, + }, + ]}, + }, + }; + + const relayFee = 400_000_000_000_000n; + const currencies: [any, bigint][] = [ + [ + { + ForeignAssetId: 0, + }, + TRANSFER_AMOUNT, + ], + [ + { + NativeAssetId: 'Parent', + }, + relayFee, + ], + ]; + + const feeItem = 1; + + await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited'); + + // the commission has been paid in parachain native token + balanceQuartzFinal = await helper.balance.getSubstrate(alice.address); + console.log('[Quartz -> Statemine] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(balanceQuartzFinal - balanceQuartzAfter)); + expect(balanceQuartzAfter > balanceQuartzFinal).to.be.true; + + await usingStateminePlaygrounds(statemineUrl, async (helper) => { + await helper.wait.newBlocks(3); + + // The USDT token never paid fees. Its amount not changed from begin value. + // Also check that xcm transfer has been succeeded + expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true; + }); + }); + + itSub('Should connect and send Relay token to Quartz', async ({helper}) => { + balanceBobBefore = await helper.balance.getSubstrate(bob.address); + balanceBobRelayTokenBefore = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'}); + + await usingRelayPlaygrounds(relayUrl, async (helper) => { + const destination = { + V1: { + parents: 0, + interior: {X1: { + Parachain: QUARTZ_CHAIN, + }, + }, + }}; + + const beneficiary = { + V1: { + parents: 0, + interior: {X1: { + AccountId32: { + network: 'Any', + id: bob.addressRaw, + }, + }}, + }, + }; + + const assets = { + V1: [ + { + id: { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + fun: { + Fungible: TRANSFER_AMOUNT_RELAY, + }, + }, + ], + }; + + const feeAssetItem = 0; + + await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited'); + }); + + await helper.wait.newBlocks(3); + + balanceBobAfter = await helper.balance.getSubstrate(bob.address); + balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'}); + + const wndFeeOnQuartz = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore; + const wndDiffOnQuartz = balanceBobRelayTokenAfter - balanceBobRelayTokenBefore; + console.log( + '[Relay (Westend) -> Quartz] transaction fees: %s QTZ', + helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore), + ); + console.log( + '[Relay (Westend) -> Quartz] transaction fees: %s WND', + helper.util.bigIntToDecimals(wndFeeOnQuartz, STATEMINE_DECIMALS), + ); + console.log('[Relay (Westend) -> Quartz] actually delivered: %s WND', wndDiffOnQuartz); + expect(wndFeeOnQuartz == 0n, 'No incoming WND fees should be taken').to.be.true; + expect(balanceBobBefore == balanceBobAfter, 'No incoming QTZ fees should be taken').to.be.true; + }); + + itSub('Should connect and send Relay token back', async ({helper}) => { + let relayTokenBalanceBefore: bigint; + let relayTokenBalanceAfter: bigint; + await usingRelayPlaygrounds(relayUrl, async (helper) => { + relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address); + }); + + const destination = { + V1: { + parents: 1, + interior: { + X1:{ + AccountId32: { + network: 'Any', + id: bob.addressRaw, + }, + }, + }, + }, + }; + + const currencies: any = [ + [ + { + NativeAssetId: 'Parent', + }, + TRANSFER_AMOUNT_RELAY, + ], + ]; + + const feeItem = 0; + + await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited'); + + balanceBobFinal = await helper.balance.getSubstrate(bob.address); + console.log('[Quartz -> Relay (Westend)] transaction fees: %s QTZ', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal)); + + await usingRelayPlaygrounds(relayUrl, async (helper) => { + await helper.wait.newBlocks(10); + relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address); + + const diff = relayTokenBalanceAfter - relayTokenBalanceBefore; + console.log('[Quartz -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS)); + expect(diff > 0, 'Relay tokens was not delivered back').to.be.true; + }); + }); +}); + describeXCM('[XCM] Integration test: Exchanging tokens with Karura', () => { let alice: IKeyringPair; let randomAccount: IKeyringPair; @@ -123,14 +532,13 @@ describeXCM('[XCM] Integration test: Exchanging tokens with Karura', () => { }; const feeAssetItem = 0; - const weightLimit = 5000000000; - await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, weightLimit); + await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited'); balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccount.address); const qtzFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT; + expect(qtzFees > 0n, 'Negative fees QTZ, looks like nothing was transferred').to.be.true; console.log('[Quartz -> Karura] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(qtzFees)); - expect(qtzFees > 0n).to.be.true; await usingKaruraPlaygrounds(karuraUrl, async (helper) => { await helper.wait.newBlocks(3); @@ -173,9 +581,7 @@ describeXCM('[XCM] Integration test: Exchanging tokens with Karura', () => { ForeignAsset: 0, }; - const destWeight = 50000000; - - await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, destWeight); + await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, 'Unlimited'); balanceKaruraTokenFinal = await helper.balance.getSubstrate(randomAccount.address); balanceQuartzForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id); @@ -188,7 +594,7 @@ describeXCM('[XCM] Integration test: Exchanging tokens with Karura', () => { ); console.log('[Karura -> Quartz] outcome %s QTZ', helper.util.bigIntToDecimals(qtzOutcomeTransfer)); - expect(karFees > 0).to.be.true; + expect(karFees > 0, 'Negative fees KAR, looks like nothing was transferred').to.be.true; expect(qtzOutcomeTransfer == TRANSFER_AMOUNT).to.be.true; }); @@ -216,75 +622,6 @@ describeXCM('[XCM] Integration test: Quartz rejects non-native tokens', () => { }); }); - itSub('Quartz rejects tokens from the Relay', async ({helper}) => { - await usingRelayPlaygrounds(relayUrl, async (helper) => { - const destination = { - V1: { - parents: 0, - interior: {X1: { - Parachain: QUARTZ_CHAIN, - }, - }, - }}; - - const beneficiary = { - V1: { - parents: 0, - interior: {X1: { - AccountId32: { - network: 'Any', - id: alice.addressRaw, - }, - }}, - }, - }; - - const assets = { - V1: [ - { - id: { - Concrete: { - parents: 0, - interior: 'Here', - }, - }, - fun: { - Fungible: 50_000_000_000_000_000n, - }, - }, - ], - }; - - const feeAssetItem = 0; - const weightLimit = 5_000_000_000; - - await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, weightLimit); - }); - - const maxWaitBlocks = 3; - - const dmpQueueExecutedDownward = await helper.wait.event(maxWaitBlocks, 'dmpQueue', 'ExecutedDownward'); - - expect( - dmpQueueExecutedDownward != null, - '[Relay] dmpQueue.ExecutedDownward event is expected', - ).to.be.true; - - const event = dmpQueueExecutedDownward!.event; - const outcome = event.data[1] as XcmV2TraitsOutcome; - - expect( - outcome.isIncomplete, - '[Relay] The outcome of the XCM should be `Incomplete`', - ).to.be.true; - - const incomplete = outcome.asIncomplete; - expect( - incomplete[1].toString() == 'AssetNotFound', - '[Relay] The XCM error should be `AssetNotFound`', - ).to.be.true; - }); - itSub('Quartz rejects KAR tokens from Karura', async ({helper}) => { await usingKaruraPlaygrounds(karuraUrl, async (helper) => { const destination = { @@ -308,9 +645,7 @@ describeXCM('[XCM] Integration test: Quartz rejects non-native tokens', () => { Token: 'KAR', }; - const destWeight = 50000000; - - await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, destWeight); + await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, 'Unlimited'); }); const maxWaitBlocks = 3; @@ -326,8 +661,8 @@ describeXCM('[XCM] Integration test: Quartz rejects non-native tokens', () => { const outcome = event.data[1] as XcmV2TraitsError; expect( - outcome.isUntrustedReserveLocation, - '[Karura] The XCM error should be `UntrustedReserveLocation`', + outcome.isFailedToTransactAsset, + '[Karura] The XCM error should be `FailedToTransactAsset`', ).to.be.true; }); }); @@ -420,7 +755,7 @@ describeXCM('[XCM] Integration test: Exchanging QTZ with Moonriver', () => { // >>> Propose external motion through council >>> console.log('Propose external motion through council.......'); - const externalMotion = helper.democracy.externalProposeMajority(proposalHash); + const externalMotion = helper.democracy.externalProposeMajority({Legacy: proposalHash}); const encodedMotion = externalMotion?.method.toHex() || ''; const motionHash = blake2AsHex(encodedMotion); console.log('Motion hash is %s', motionHash); @@ -431,7 +766,16 @@ describeXCM('[XCM] Integration test: Exchanging QTZ with Moonriver', () => { await helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true); await helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true); - await helper.collective.council.close(dorothyAccount, motionHash, councilProposalIdx, 1_000_000_000, externalMotion.encodedLength); + await helper.collective.council.close( + dorothyAccount, + motionHash, + councilProposalIdx, + { + refTime: 1_000_000_000, + proofSize: 1_000_000, + }, + externalMotion.encodedLength, + ); console.log('Propose external motion through council.......DONE'); // <<< Propose external motion through council <<< @@ -448,7 +792,16 @@ describeXCM('[XCM] Integration test: Exchanging QTZ with Moonriver', () => { await helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true); await helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true); - await helper.collective.techCommittee.close(baltatharAccount, fastTrackHash, techProposalIdx, 1_000_000_000, fastTrack.encodedLength); + await helper.collective.techCommittee.close( + baltatharAccount, + fastTrackHash, + techProposalIdx, + { + refTime: 1_000_000_000, + proofSize: 1_000_000, + }, + fastTrack.encodedLength, + ); console.log('Fast track proposal through technical committee.......DONE'); // <<< Fast track proposal through technical committee <<< @@ -504,16 +857,15 @@ describeXCM('[XCM] Integration test: Exchanging QTZ with Moonriver', () => { }, }; const amount = TRANSFER_AMOUNT; - const destWeight = 850000000; - await helper.xTokens.transfer(randomAccountQuartz, currencyId, amount, dest, destWeight); + await helper.xTokens.transfer(randomAccountQuartz, currencyId, amount, dest, 'Unlimited'); balanceQuartzTokenMiddle = await helper.balance.getSubstrate(randomAccountQuartz.address); expect(balanceQuartzTokenMiddle < balanceQuartzTokenInit).to.be.true; const transactionFees = balanceQuartzTokenInit - balanceQuartzTokenMiddle - TRANSFER_AMOUNT; console.log('[Quartz -> Moonriver] transaction fees on Quartz: %s QTZ', helper.util.bigIntToDecimals(transactionFees)); - expect(transactionFees > 0).to.be.true; + expect(transactionFees > 0, 'Negative fees QTZ, looks like nothing was transferred').to.be.true; await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => { await helper.wait.newBlocks(3); @@ -559,15 +911,14 @@ describeXCM('[XCM] Integration test: Exchanging QTZ with Moonriver', () => { }, }, }; - const destWeight = 50000000; - await helper.xTokens.transferMultiasset(randomAccountMoonriver, asset, destination, destWeight); + await helper.xTokens.transferMultiasset(randomAccountMoonriver, asset, destination, 'Unlimited'); balanceMovrTokenFinal = await helper.balance.getEthereum(randomAccountMoonriver.address); const movrFees = balanceMovrTokenMiddle - balanceMovrTokenFinal; console.log('[Moonriver -> Quartz] transaction fees on Moonriver: %s MOVR', helper.util.bigIntToDecimals(movrFees)); - expect(movrFees > 0).to.be.true; + expect(movrFees > 0, 'Negative fees MOVR, looks like nothing was transferred').to.be.true; const qtzRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonriver.address); diff --git a/tests/src/xcm/xcmUnique.test.ts b/tests/src/xcm/xcmUnique.test.ts index 7ab7f9d960..fea3939bc2 100644 --- a/tests/src/xcm/xcmUnique.test.ts +++ b/tests/src/xcm/xcmUnique.test.ts @@ -17,21 +17,430 @@ import {IKeyringPair} from '@polkadot/types/types'; import {blake2AsHex} from '@polkadot/util-crypto'; import config from '../config'; -import {XcmV2TraitsError, XcmV2TraitsOutcome} from '../interfaces'; -import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds} from '../util'; +import {XcmV2TraitsError} from '../interfaces'; +import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds, usingStatemintPlaygrounds} from '../util'; const UNIQUE_CHAIN = 2037; +const STATEMINT_CHAIN = 1000; const ACALA_CHAIN = 2000; const MOONBEAM_CHAIN = 2004; +const STATEMINT_PALLET_INSTANCE = 50; + const relayUrl = config.relayUrl; +const statemintUrl = config.statemintUrl; const acalaUrl = config.acalaUrl; const moonbeamUrl = config.moonbeamUrl; +const RELAY_DECIMALS = 12; +const STATEMINT_DECIMALS = 12; const ACALA_DECIMALS = 12; const TRANSFER_AMOUNT = 2000000000000000000000000n; +const FUNDING_AMOUNT = 3_500_000_0000_000_000n; + +const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n; + +const USDT_ASSET_ID = 100; +const USDT_ASSET_METADATA_DECIMALS = 18; +const USDT_ASSET_METADATA_NAME = 'USDT'; +const USDT_ASSET_METADATA_DESCRIPTION = 'USDT'; +const USDT_ASSET_METADATA_MINIMAL_BALANCE = 1n; +const USDT_ASSET_AMOUNT = 10_000_000_000_000_000_000_000_000n; + +describeXCM('[XCM] Integration test: Exchanging USDT with Statemint', () => { + let alice: IKeyringPair; + let bob: IKeyringPair; + + let balanceStmnBefore: bigint; + let balanceStmnAfter: bigint; + + let balanceUniqueBefore: bigint; + let balanceUniqueAfter: bigint; + let balanceUniqueFinal: bigint; + + let balanceBobBefore: bigint; + let balanceBobAfter: bigint; + let balanceBobFinal: bigint; + + let balanceBobRelayTokenBefore: bigint; + let balanceBobRelayTokenAfter: bigint; + + + before(async () => { + await usingPlaygrounds(async (_helper, privateKey) => { + alice = await privateKey('//Alice'); + bob = await privateKey('//Bob'); // sovereign account on Statemint funds donor + }); + + await usingRelayPlaygrounds(relayUrl, async (helper) => { + // Fund accounts on Statemint + await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, alice.addressRaw, FUNDING_AMOUNT); + await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, bob.addressRaw, FUNDING_AMOUNT); + }); + + await usingStatemintPlaygrounds(statemintUrl, async (helper) => { + const sovereignFundingAmount = 3_500_000_000n; + + await helper.assets.create( + alice, + USDT_ASSET_ID, + alice.address, + USDT_ASSET_METADATA_MINIMAL_BALANCE, + ); + await helper.assets.setMetadata( + alice, + USDT_ASSET_ID, + USDT_ASSET_METADATA_NAME, + USDT_ASSET_METADATA_DESCRIPTION, + USDT_ASSET_METADATA_DECIMALS, + ); + await helper.assets.mint( + alice, + USDT_ASSET_ID, + alice.address, + USDT_ASSET_AMOUNT, + ); + + // funding parachain sovereing account on Statemint. + // The sovereign account should be created before any action + // (the assets pallet on Statemint check if the sovereign account exists) + const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(UNIQUE_CHAIN); + await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, sovereignFundingAmount); + }); + + + await usingPlaygrounds(async (helper) => { + const location = { + V1: { + parents: 1, + interior: {X3: [ + { + Parachain: STATEMINT_CHAIN, + }, + { + PalletInstance: STATEMINT_PALLET_INSTANCE, + }, + { + GeneralIndex: USDT_ASSET_ID, + }, + ]}, + }, + }; + + const metadata = + { + name: USDT_ASSET_ID, + symbol: USDT_ASSET_METADATA_NAME, + decimals: USDT_ASSET_METADATA_DECIMALS, + minimalBalance: USDT_ASSET_METADATA_MINIMAL_BALANCE, + }; + await helper.getSudo().foreignAssets.register(alice, alice.address, location, metadata); + balanceUniqueBefore = await helper.balance.getSubstrate(alice.address); + }); + + + // Providing the relay currency to the unique sender account + // (fee for USDT XCM are paid in relay tokens) + await usingRelayPlaygrounds(relayUrl, async (helper) => { + const destination = { + V1: { + parents: 0, + interior: {X1: { + Parachain: UNIQUE_CHAIN, + }, + }, + }}; + + const beneficiary = { + V1: { + parents: 0, + interior: {X1: { + AccountId32: { + network: 'Any', + id: alice.addressRaw, + }, + }}, + }, + }; + + const assets = { + V1: [ + { + id: { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + fun: { + Fungible: TRANSFER_AMOUNT_RELAY, + }, + }, + ], + }; + + const feeAssetItem = 0; + + await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited'); + }); + + }); + + itSub('Should connect and send USDT from Statemint to Unique', async ({helper}) => { + await usingStatemintPlaygrounds(statemintUrl, async (helper) => { + const dest = { + V1: { + parents: 1, + interior: {X1: { + Parachain: UNIQUE_CHAIN, + }, + }, + }}; + + const beneficiary = { + V1: { + parents: 0, + interior: {X1: { + AccountId32: { + network: 'Any', + id: alice.addressRaw, + }, + }}, + }, + }; + + const assets = { + V1: [ + { + id: { + Concrete: { + parents: 0, + interior: { + X2: [ + { + PalletInstance: STATEMINT_PALLET_INSTANCE, + }, + { + GeneralIndex: USDT_ASSET_ID, + }, + ]}, + }, + }, + fun: { + Fungible: TRANSFER_AMOUNT, + }, + }, + ], + }; + + const feeAssetItem = 0; + + balanceStmnBefore = await helper.balance.getSubstrate(alice.address); + await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited'); + + balanceStmnAfter = await helper.balance.getSubstrate(alice.address); + + // common good parachain take commission in it native token + console.log( + '[Statemint -> Unique] transaction fees on Statemint: %s WND', + helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, STATEMINT_DECIMALS), + ); + expect(balanceStmnBefore > balanceStmnAfter).to.be.true; + + }); + + + // ensure that asset has been delivered + await helper.wait.newBlocks(3); + + // expext collection id will be with id 1 + const free = await helper.ft.getBalance(1, {Substrate: alice.address}); + + balanceUniqueAfter = await helper.balance.getSubstrate(alice.address); + + console.log( + '[Statemint -> Unique] transaction fees on Unique: %s USDT', + helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, USDT_ASSET_METADATA_DECIMALS), + ); + console.log( + '[Statemint -> Unique] transaction fees on Unique: %s UNQ', + helper.util.bigIntToDecimals(balanceUniqueAfter - balanceUniqueBefore), + ); + // commission has not paid in USDT token + expect(free).to.be.equal(TRANSFER_AMOUNT); + // ... and parachain native token + expect(balanceUniqueAfter == balanceUniqueBefore).to.be.true; + }); + + itSub('Should connect and send USDT from Unique to Statemint back', async ({helper}) => { + const destination = { + V1: { + parents: 1, + interior: {X2: [ + { + Parachain: STATEMINT_CHAIN, + }, + { + AccountId32: { + network: 'Any', + id: alice.addressRaw, + }, + }, + ]}, + }, + }; + + const relayFee = 400_000_000_000_000n; + const currencies: [any, bigint][] = [ + [ + { + ForeignAssetId: 0, + }, + TRANSFER_AMOUNT, + ], + [ + { + NativeAssetId: 'Parent', + }, + relayFee, + ], + ]; + + const feeItem = 1; + + await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited'); + + // the commission has been paid in parachain native token + balanceUniqueFinal = await helper.balance.getSubstrate(alice.address); + console.log('[Unique -> Statemint] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(balanceUniqueFinal - balanceUniqueAfter)); + expect(balanceUniqueAfter > balanceUniqueFinal).to.be.true; + + await usingStatemintPlaygrounds(statemintUrl, async (helper) => { + await helper.wait.newBlocks(3); + + // The USDT token never paid fees. Its amount not changed from begin value. + // Also check that xcm transfer has been succeeded + expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true; + }); + }); + + itSub('Should connect and send Relay token to Unique', async ({helper}) => { + balanceBobBefore = await helper.balance.getSubstrate(bob.address); + balanceBobRelayTokenBefore = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'}); + + await usingRelayPlaygrounds(relayUrl, async (helper) => { + const destination = { + V1: { + parents: 0, + interior: {X1: { + Parachain: UNIQUE_CHAIN, + }, + }, + }}; + + const beneficiary = { + V1: { + parents: 0, + interior: {X1: { + AccountId32: { + network: 'Any', + id: bob.addressRaw, + }, + }}, + }, + }; + + const assets = { + V1: [ + { + id: { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + fun: { + Fungible: TRANSFER_AMOUNT_RELAY, + }, + }, + ], + }; + + const feeAssetItem = 0; + + await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited'); + }); + + await helper.wait.newBlocks(3); + + balanceBobAfter = await helper.balance.getSubstrate(bob.address); + balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'}); + + const wndFeeOnUnique = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore; + const wndDiffOnUnique = balanceBobRelayTokenAfter - balanceBobRelayTokenBefore; + console.log( + '[Relay (Westend) -> Unique] transaction fees: %s UNQ', + helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore), + ); + console.log( + '[Relay (Westend) -> Unique] transaction fees: %s WND', + helper.util.bigIntToDecimals(wndFeeOnUnique, STATEMINT_DECIMALS), + ); + console.log('[Relay (Westend) -> Unique] actually delivered: %s WND', wndDiffOnUnique); + expect(wndFeeOnUnique == 0n, 'No incoming WND fees should be taken').to.be.true; + expect(balanceBobBefore == balanceBobAfter, 'No incoming UNQ fees should be taken').to.be.true; + }); + + itSub('Should connect and send Relay token back', async ({helper}) => { + let relayTokenBalanceBefore: bigint; + let relayTokenBalanceAfter: bigint; + await usingRelayPlaygrounds(relayUrl, async (helper) => { + relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address); + }); + + const destination = { + V1: { + parents: 1, + interior: { + X1:{ + AccountId32: { + network: 'Any', + id: bob.addressRaw, + }, + }, + }, + }, + }; + + const currencies: any = [ + [ + { + NativeAssetId: 'Parent', + }, + TRANSFER_AMOUNT_RELAY, + ], + ]; + + const feeItem = 0; + + await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited'); + + balanceBobFinal = await helper.balance.getSubstrate(bob.address); + console.log('[Unique -> Relay (Westend)] transaction fees: %s UNQ', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal)); + + await usingRelayPlaygrounds(relayUrl, async (helper) => { + await helper.wait.newBlocks(10); + relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address); + + const diff = relayTokenBalanceAfter - relayTokenBalanceBefore; + console.log('[Unique -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS)); + expect(diff > 0, 'Relay tokens was not delivered back').to.be.true; + }); + }); +}); + describeXCM('[XCM] Integration test: Exchanging tokens with Acala', () => { let alice: IKeyringPair; let randomAccount: IKeyringPair; @@ -124,15 +533,13 @@ describeXCM('[XCM] Integration test: Exchanging tokens with Acala', () => { }; const feeAssetItem = 0; - const weightLimit = 5000000000; - - await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, weightLimit); + await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited'); balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address); const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT; console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees)); - expect(unqFees > 0n).to.be.true; + expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true; await usingAcalaPlaygrounds(acalaUrl, async (helper) => { await helper.wait.newBlocks(3); @@ -176,10 +583,7 @@ describeXCM('[XCM] Integration test: Exchanging tokens with Acala', () => { ForeignAsset: 0, }; - const destWeight = 50000000; - - await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, destWeight); - + await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, 'Unlimited'); balanceAcalaTokenFinal = await helper.balance.getSubstrate(randomAccount.address); balanceUniqueForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id); @@ -192,7 +596,7 @@ describeXCM('[XCM] Integration test: Exchanging tokens with Acala', () => { ); console.log('[Acala -> Unique] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer)); - expect(acaFees > 0).to.be.true; + expect(acaFees > 0, 'Negative fees ACA, looks like nothing was transferred').to.be.true; expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true; }); @@ -220,75 +624,6 @@ describeXCM('[XCM] Integration test: Unique rejects non-native tokens', () => { }); }); - itSub('Unique rejects tokens from the Relay', async ({helper}) => { - await usingRelayPlaygrounds(relayUrl, async (helper) => { - const destination = { - V1: { - parents: 0, - interior: {X1: { - Parachain: UNIQUE_CHAIN, - }, - }, - }}; - - const beneficiary = { - V1: { - parents: 0, - interior: {X1: { - AccountId32: { - network: 'Any', - id: alice.addressRaw, - }, - }}, - }, - }; - - const assets = { - V1: [ - { - id: { - Concrete: { - parents: 0, - interior: 'Here', - }, - }, - fun: { - Fungible: 50_000_000_000_000_000n, - }, - }, - ], - }; - - const feeAssetItem = 0; - const weightLimit = 5_000_000_000; - - await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, weightLimit); - }); - - const maxWaitBlocks = 3; - - const dmpQueueExecutedDownward = await helper.wait.event(maxWaitBlocks, 'dmpQueue', 'ExecutedDownward'); - - expect( - dmpQueueExecutedDownward != null, - '[Relay] dmpQueue.ExecutedDownward event is expected', - ).to.be.true; - - const event = dmpQueueExecutedDownward!.event; - const outcome = event.data[1] as XcmV2TraitsOutcome; - - expect( - outcome.isIncomplete, - '[Relay] The outcome of the XCM should be `Incomplete`', - ).to.be.true; - - const incomplete = outcome.asIncomplete; - expect( - incomplete[1].toString() == 'AssetNotFound', - '[Relay] The XCM error should be `AssetNotFound`', - ).to.be.true; - }); - itSub('Unique rejects ACA tokens from Acala', async ({helper}) => { await usingAcalaPlaygrounds(acalaUrl, async (helper) => { const destination = { @@ -312,9 +647,7 @@ describeXCM('[XCM] Integration test: Unique rejects non-native tokens', () => { Token: 'ACA', }; - const destWeight = 50000000; - - await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, destWeight); + await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, 'Unlimited'); }); const maxWaitBlocks = 3; @@ -330,8 +663,8 @@ describeXCM('[XCM] Integration test: Unique rejects non-native tokens', () => { const outcome = event.data[1] as XcmV2TraitsError; expect( - outcome.isUntrustedReserveLocation, - '[Acala] The XCM error should be `UntrustedReserveLocation`', + outcome.isFailedToTransactAsset, + '[Acala] The XCM error should be `FailedToTransactAsset`', ).to.be.true; }); }); @@ -508,16 +841,15 @@ describeXCM('[XCM] Integration test: Exchanging UNQ with Moonbeam', () => { }, }; const amount = TRANSFER_AMOUNT; - const destWeight = 850000000; - await helper.xTokens.transfer(randomAccountUnique, currencyId, amount, dest, destWeight); + await helper.xTokens.transfer(randomAccountUnique, currencyId, amount, dest, 'Unlimited'); balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccountUnique.address); expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true; const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT; console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(transactionFees)); - expect(transactionFees > 0).to.be.true; + expect(transactionFees > 0, 'Negative fees UNQ, looks like nothing was transferred').to.be.true; await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => { await helper.wait.newBlocks(3); @@ -572,12 +904,12 @@ describeXCM('[XCM] Integration test: Exchanging UNQ with Moonbeam', () => { const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal; console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees)); - expect(glmrFees > 0).to.be.true; + expect(glmrFees > 0, 'Negative fees GLMR, looks like nothing was transferred').to.be.true; const unqRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonbeam.address); expect(unqRandomAccountAsset).to.be.null; - + balanceForeignUnqTokenFinal = 0n; const unqOutcomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenFinal; diff --git a/tests/yarn.lock b/tests/yarn.lock index 157cfc567e..929de1fc54 100644 --- a/tests/yarn.lock +++ b/tests/yarn.lock @@ -17,49 +17,50 @@ dependencies: "@babel/highlight" "^7.18.6" -"@babel/compat-data@^7.19.3": - version "7.19.4" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.19.4.tgz#95c86de137bf0317f3a570e1b6e996b427299747" - integrity sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw== +"@babel/compat-data@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.5.tgz#86f172690b093373a933223b4745deeb6049e733" + integrity sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g== -"@babel/core@^7.19.3": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.19.6.tgz#7122ae4f5c5a37c0946c066149abd8e75f81540f" - integrity sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg== +"@babel/core@^7.20.5": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.7.tgz#37072f951bd4d28315445f66e0ec9f6ae0c8c35f" + integrity sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.19.6" - "@babel/helper-compilation-targets" "^7.19.3" - "@babel/helper-module-transforms" "^7.19.6" - "@babel/helpers" "^7.19.4" - "@babel/parser" "^7.19.6" - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.19.6" - "@babel/types" "^7.19.4" + "@babel/generator" "^7.20.7" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-module-transforms" "^7.20.7" + "@babel/helpers" "^7.20.7" + "@babel/parser" "^7.20.7" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.7" + "@babel/types" "^7.20.7" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.1" semver "^6.3.0" -"@babel/generator@^7.19.6": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.19.6.tgz#9e481a3fe9ca6261c972645ae3904ec0f9b34a1d" - integrity sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA== +"@babel/generator@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.7.tgz#f8ef57c8242665c5929fe2e8d82ba75460187b4a" + integrity sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw== dependencies: - "@babel/types" "^7.19.4" + "@babel/types" "^7.20.7" "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" -"@babel/helper-compilation-targets@^7.19.3": - version "7.19.3" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz#a10a04588125675d7c7ae299af86fa1b2ee038ca" - integrity sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg== +"@babel/helper-compilation-targets@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz#a6cd33e93629f5eb473b021aac05df62c4cd09bb" + integrity sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ== dependencies: - "@babel/compat-data" "^7.19.3" + "@babel/compat-data" "^7.20.5" "@babel/helper-validator-option" "^7.18.6" browserslist "^4.21.3" + lru-cache "^5.1.1" semver "^6.3.0" "@babel/helper-environment-visitor@^7.18.9": @@ -89,26 +90,26 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-module-transforms@^7.19.6": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz#6c52cc3ac63b70952d33ee987cbee1c9368b533f" - integrity sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw== +"@babel/helper-module-transforms@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.20.7.tgz#7a6c9a1155bef55e914af574153069c9d9470c43" + integrity sha512-FNdu7r67fqMUSVuQpFQGE6BPdhJIhitoxhGzDbAXNcA07uoVG37fOiMk3OSV8rEICuyG6t8LGkd9EE64qIEoIA== dependencies: "@babel/helper-environment-visitor" "^7.18.9" "@babel/helper-module-imports" "^7.18.6" - "@babel/helper-simple-access" "^7.19.4" + "@babel/helper-simple-access" "^7.20.2" "@babel/helper-split-export-declaration" "^7.18.6" "@babel/helper-validator-identifier" "^7.19.1" - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.19.6" - "@babel/types" "^7.19.4" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.7" + "@babel/types" "^7.20.7" -"@babel/helper-simple-access@^7.19.4": - version "7.19.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz#be553f4951ac6352df2567f7daa19a0ee15668e7" - integrity sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg== +"@babel/helper-simple-access@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz#0ab452687fe0c2cfb1e2b9e0015de07fc2d62dd9" + integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== dependencies: - "@babel/types" "^7.19.4" + "@babel/types" "^7.20.2" "@babel/helper-split-export-declaration@^7.18.6": version "7.18.6" @@ -132,14 +133,14 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== -"@babel/helpers@^7.19.4": - version "7.19.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.19.4.tgz#42154945f87b8148df7203a25c31ba9a73be46c5" - integrity sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw== +"@babel/helpers@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.7.tgz#04502ff0feecc9f20ecfaad120a18f011a8e6dce" + integrity sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA== dependencies: - "@babel/template" "^7.18.10" - "@babel/traverse" "^7.19.4" - "@babel/types" "^7.19.4" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.7" + "@babel/types" "^7.20.7" "@babel/highlight@^7.18.6": version "7.18.6" @@ -150,10 +151,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.18.10", "@babel/parser@^7.19.6": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.6.tgz#b923430cb94f58a7eae8facbffa9efd19130e7f8" - integrity sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA== +"@babel/parser@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.7.tgz#66fe23b3c8569220817d5feb8b9dcdc95bb4f71b" + integrity sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg== "@babel/register@^7.18.9": version "7.18.9" @@ -166,42 +167,42 @@ pirates "^4.0.5" source-map-support "^0.5.16" -"@babel/runtime@^7.18.9", "@babel/runtime@^7.19.4": - version "7.19.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.4.tgz#a42f814502ee467d55b38dd1c256f53a7b885c78" - integrity sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA== +"@babel/runtime@^7.20.6": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.7.tgz#fcb41a5a70550e04a7b708037c7c32f7f356d8fd" + integrity sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ== dependencies: - regenerator-runtime "^0.13.4" + regenerator-runtime "^0.13.11" -"@babel/template@^7.18.10": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" - integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== +"@babel/template@^7.18.10", "@babel/template@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" + integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== dependencies: "@babel/code-frame" "^7.18.6" - "@babel/parser" "^7.18.10" - "@babel/types" "^7.18.10" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" -"@babel/traverse@^7.19.4", "@babel/traverse@^7.19.6": - version "7.19.6" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.6.tgz#7b4c865611df6d99cb131eec2e8ac71656a490dc" - integrity sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ== +"@babel/traverse@^7.20.7": + version "7.20.8" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.8.tgz#e3a23eb04af24f8bbe8a8ba3eef6155b77df0b08" + integrity sha512-/RNkaYDeCy4MjyV70+QkSHhxbvj2JO/5Ft2Pa880qJOG8tWrqcT/wXUuCCv43yogfqPzHL77Xu101KQPf4clnQ== dependencies: "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.19.6" + "@babel/generator" "^7.20.7" "@babel/helper-environment-visitor" "^7.18.9" "@babel/helper-function-name" "^7.19.0" "@babel/helper-hoist-variables" "^7.18.6" "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.19.6" - "@babel/types" "^7.19.4" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.19.4": - version "7.19.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.4.tgz#0dd5c91c573a202d600490a35b33246fed8a41c7" - integrity sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw== +"@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.20.2", "@babel/types@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f" + integrity sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg== dependencies: "@babel/helper-string-parser" "^7.19.4" "@babel/helper-validator-identifier" "^7.19.1" @@ -214,22 +215,30 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@eslint/eslintrc@^1.3.3": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.3.tgz#2b044ab39fdfa75b4688184f9e573ce3c5b0ff95" - integrity sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg== +"@eslint/eslintrc@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.0.tgz#8ec64e0df3e7a1971ee1ff5158da87389f167a63" + integrity sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A== dependencies: ajv "^6.12.4" debug "^4.3.2" espree "^9.4.0" - globals "^13.15.0" + globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@ethereumjs/common@^2.5.0", "@ethereumjs/common@^2.6.4": +"@ethereumjs/common@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.5.0.tgz#ec61551b31bef7a69d1dc634d8932468866a4268" + integrity sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg== + dependencies: + crc-32 "^1.2.0" + ethereumjs-util "^7.1.1" + +"@ethereumjs/common@^2.5.0": version "2.6.5" resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.5.tgz#0a75a22a046272579d91919cb12d84f2756e8d30" integrity sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA== @@ -237,13 +246,13 @@ crc-32 "^1.2.0" ethereumjs-util "^7.1.5" -"@ethereumjs/tx@^3.3.2": - version "3.5.2" - resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.5.2.tgz#197b9b6299582ad84f9527ca961466fce2296c1c" - integrity sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw== +"@ethereumjs/tx@3.3.2": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.3.2.tgz#348d4624bf248aaab6c44fec2ae67265efe3db00" + integrity sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog== dependencies: - "@ethereumjs/common" "^2.6.4" - ethereumjs-util "^7.1.5" + "@ethereumjs/common" "^2.5.0" + ethereumjs-util "^7.1.2" "@ethersproject/abi@^5.6.3": version "5.7.0" @@ -422,14 +431,14 @@ "@ethersproject/properties" "^5.7.0" "@ethersproject/strings" "^5.7.0" -"@humanwhocodes/config-array@^0.10.5": - version "0.10.7" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.10.7.tgz#6d53769fd0c222767e6452e8ebda825c22e9f0dc" - integrity sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w== +"@humanwhocodes/config-array@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" + integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== dependencies: "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" - minimatch "^3.0.4" + minimatch "^3.0.5" "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" @@ -512,7 +521,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -520,352 +529,352 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@polkadot/api-augment@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/api-augment/-/api-augment-9.5.2.tgz#55168dd112517028fea5f2ab9c54ea627e43ac3a" - integrity sha512-dH6QMY8Z3zI6CrgSU3eSe6f0KWDb5PYGztg/FXGPrjh7Vjic7syWZ1LD6zaHJAFWDp80BEdEXfqr4lConrCKGg== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/api-base" "9.5.2" - "@polkadot/rpc-augment" "9.5.2" - "@polkadot/types" "9.5.2" - "@polkadot/types-augment" "9.5.2" - "@polkadot/types-codec" "9.5.2" - "@polkadot/util" "^10.1.11" - -"@polkadot/api-base@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/api-base/-/api-base-9.5.2.tgz#ac0a6b5546a54bcc753ac55c9f033caa9f8b4e5c" - integrity sha512-BBsH9SLB1FHgjdiU32cZX1puL3Eh8IjOJHjRsO/5SdttciQhF5g/u/m/mM/55qnlXmffI9s2Jre18G0XtVU9Aw== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/rpc-core" "9.5.2" - "@polkadot/types" "9.5.2" - "@polkadot/util" "^10.1.11" - rxjs "^7.5.7" - -"@polkadot/api-derive@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-9.5.2.tgz#c0412cfc13fa71f93b315d126b12b5ab38e6438c" - integrity sha512-kWn12dlqfIES1trNLd3O1i2qa4T97v/co1VMCgVstICwCt3+mGZgpxkMqQqPiWHagKEVeBNoAn+h8eOiQlbujA== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/api" "9.5.2" - "@polkadot/api-augment" "9.5.2" - "@polkadot/api-base" "9.5.2" - "@polkadot/rpc-core" "9.5.2" - "@polkadot/types" "9.5.2" - "@polkadot/types-codec" "9.5.2" - "@polkadot/util" "^10.1.11" - "@polkadot/util-crypto" "^10.1.11" - rxjs "^7.5.7" - -"@polkadot/api@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-9.5.2.tgz#cef83928e47c393fbebf2788bc86841b6ab37a41" - integrity sha512-iEF/E8vQan3fHmIEl3bX7Yn/1jQLlvSDwPOxiQdj4tIcF36HX6vCbkdhQKRif0CNYES58TA9EKFiCNg81k+kXw== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/api-augment" "9.5.2" - "@polkadot/api-base" "9.5.2" - "@polkadot/api-derive" "9.5.2" - "@polkadot/keyring" "^10.1.11" - "@polkadot/rpc-augment" "9.5.2" - "@polkadot/rpc-core" "9.5.2" - "@polkadot/rpc-provider" "9.5.2" - "@polkadot/types" "9.5.2" - "@polkadot/types-augment" "9.5.2" - "@polkadot/types-codec" "9.5.2" - "@polkadot/types-create" "9.5.2" - "@polkadot/types-known" "9.5.2" - "@polkadot/util" "^10.1.11" - "@polkadot/util-crypto" "^10.1.11" +"@polkadot/api-augment@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/api-augment/-/api-augment-9.10.2.tgz#9d1875bffe9d8677a4f03d53ca6df3d0d7e7f53d" + integrity sha512-B0xC7yvPAZqPZpKJzrlFSDfHBawCJISwdV4/nBSs1/AaqQIXVu2ZqPUaSdq7eisZL/EZziptK0SpCtDcb6LpAg== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/api-base" "9.10.2" + "@polkadot/rpc-augment" "9.10.2" + "@polkadot/types" "9.10.2" + "@polkadot/types-augment" "9.10.2" + "@polkadot/types-codec" "9.10.2" + "@polkadot/util" "^10.2.1" + +"@polkadot/api-base@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/api-base/-/api-base-9.10.2.tgz#39248e966b468ecff7c0ed00bb61dfca14ca99d4" + integrity sha512-M/Yushqk6eEAfbkF90vy3GCVg+a2uVeSXyTBKbmkjZtcE7x39GiXs7LOJuYkIim51hlwcvVSeInX8HufwnTUMw== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/rpc-core" "9.10.2" + "@polkadot/types" "9.10.2" + "@polkadot/util" "^10.2.1" + rxjs "^7.6.0" + +"@polkadot/api-derive@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-9.10.2.tgz#d6b0eb558ee057416b87a304ca2790b19afa4be6" + integrity sha512-Ut1aqbGvqAkxXq7M4HgJ7BVhUyfbQigqt5LISmnjWdGkhroBxtIJ24saOUPYNr0O/c3jocJpoWqGK2CuucL81w== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/api" "9.10.2" + "@polkadot/api-augment" "9.10.2" + "@polkadot/api-base" "9.10.2" + "@polkadot/rpc-core" "9.10.2" + "@polkadot/types" "9.10.2" + "@polkadot/types-codec" "9.10.2" + "@polkadot/util" "^10.2.1" + "@polkadot/util-crypto" "^10.2.1" + rxjs "^7.6.0" + +"@polkadot/api@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-9.10.2.tgz#9a3132f0c8a5de6c2b7d56f9d9e9c9c5ed2bc77e" + integrity sha512-5leF7rxwRkkd/g11tGPho/CcbInVX7ZiuyMsLMTwn+2PDX+Ggv/gmxUboa34eyeLp8/AMui5YbqRD4QExLTxqw== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/api-augment" "9.10.2" + "@polkadot/api-base" "9.10.2" + "@polkadot/api-derive" "9.10.2" + "@polkadot/keyring" "^10.2.1" + "@polkadot/rpc-augment" "9.10.2" + "@polkadot/rpc-core" "9.10.2" + "@polkadot/rpc-provider" "9.10.2" + "@polkadot/types" "9.10.2" + "@polkadot/types-augment" "9.10.2" + "@polkadot/types-codec" "9.10.2" + "@polkadot/types-create" "9.10.2" + "@polkadot/types-known" "9.10.2" + "@polkadot/util" "^10.2.1" + "@polkadot/util-crypto" "^10.2.1" eventemitter3 "^4.0.7" - rxjs "^7.5.7" - -"@polkadot/keyring@^10.1.11": - version "10.1.11" - resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-10.1.11.tgz#a3fed011b0c8826ea2097e04f7189e9be66fbf98" - integrity sha512-Nv8cZaOA/KbdslDMTklJ58+y+UPpic3+oMQoozuq48Ccjv7WeW2BX47XM/RNE8nYFg6EHa6Whfm4IFaFb8s7ag== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/util" "10.1.11" - "@polkadot/util-crypto" "10.1.11" - -"@polkadot/networks@10.1.11", "@polkadot/networks@^10.1.11": - version "10.1.11" - resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-10.1.11.tgz#96a5d6c80228f4beada9154cca0f60a63198e7f4" - integrity sha512-4FfOVETXwh6PL6wd6fYJMkRSQKm+xUw3vR5rHqcAnB696FpMFPPErc6asgZ9lYMyzNJRY3yG86HQpFhtCv1nGA== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/util" "10.1.11" - "@substrate/ss58-registry" "^1.33.0" - -"@polkadot/rpc-augment@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/rpc-augment/-/rpc-augment-9.5.2.tgz#739cc3ed2f86f4318432e38381a2cc780dc64f1e" - integrity sha512-QAcunC7p/T4xy6e4m0Q1c9tiVYxnm+S9o10tmtx0K4qXzrc/4I2/tsw3nEGi3BzJhvMpFondSQGcJ3gyLwpmVA== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/rpc-core" "9.5.2" - "@polkadot/types" "9.5.2" - "@polkadot/types-codec" "9.5.2" - "@polkadot/util" "^10.1.11" - -"@polkadot/rpc-core@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-9.5.2.tgz#1a00868038b6c07fe8f58bd0a6cc9519d14001cc" - integrity sha512-4PbNz0GEp3FXYOnsS7mDHZy9DNVBOl56fq8vs09rLkEkrrvGkHmCvabEEWL7OPbwBzwzsCxdgI+IdkVTUKXPkQ== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/rpc-augment" "9.5.2" - "@polkadot/rpc-provider" "9.5.2" - "@polkadot/types" "9.5.2" - "@polkadot/util" "^10.1.11" - rxjs "^7.5.7" - -"@polkadot/rpc-provider@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-9.5.2.tgz#3e38ea4c3639180f12270b6fe8cbcabf728aaf1d" - integrity sha512-Sn2jfvAsvQcl35o0up8JR/XbDMS/3YVDEN2sFuzXtiD77W2njukItbZT+BolfAW+biAUs3bNomump5k/YLiLKg== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/keyring" "^10.1.11" - "@polkadot/types" "9.5.2" - "@polkadot/types-support" "9.5.2" - "@polkadot/util" "^10.1.11" - "@polkadot/util-crypto" "^10.1.11" - "@polkadot/x-fetch" "^10.1.11" - "@polkadot/x-global" "^10.1.11" - "@polkadot/x-ws" "^10.1.11" - "@substrate/connect" "0.7.14" + rxjs "^7.6.0" + +"@polkadot/keyring@^10.2.1": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-10.2.1.tgz#692d4e24dcbbe294b6945640802fc924ea20348e" + integrity sha512-84/zzxDZANQ4AfsCT1vrjX3I23/mj9WUWl1F7q9ruK6UBFyGsl46Y3ABOopFHij9UXhppndhB65IeDnqoOKqxQ== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/util" "10.2.1" + "@polkadot/util-crypto" "10.2.1" + +"@polkadot/networks@10.2.1", "@polkadot/networks@^10.2.1": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/networks/-/networks-10.2.1.tgz#5095011795afa20291ef3e34a2ad38ed2c63fe09" + integrity sha512-cDZIY4jBo2tlDdSXNbECpuWer0NWlPcJNhHHveTiu2idje2QyIBNxBlAPViNGpz+ScAR0EknEzmQKuHOcSKxzg== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/util" "10.2.1" + "@substrate/ss58-registry" "^1.35.0" + +"@polkadot/rpc-augment@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/rpc-augment/-/rpc-augment-9.10.2.tgz#5650aa118d39d0c4b17425a9b327354f7bbf99e5" + integrity sha512-LrGzpSdkqXltZDwuBeBBMev68eVVN1GpgV4auEAytgDYYcjI9XDaeLZm7vUVx9aBO8OYz9hQZeHrWrab/FaKmg== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/rpc-core" "9.10.2" + "@polkadot/types" "9.10.2" + "@polkadot/types-codec" "9.10.2" + "@polkadot/util" "^10.2.1" + +"@polkadot/rpc-core@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-9.10.2.tgz#72362d26012c53397c1079912d5d4aacf910a650" + integrity sha512-qr+q2R3YeRBC++bYxK292jb6t9/KXeLoRheW5z7LbYyre3J60vZPN7WxPxbwm+iCGk1VtvH80Dv1OSCoVC+7hA== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/rpc-augment" "9.10.2" + "@polkadot/rpc-provider" "9.10.2" + "@polkadot/types" "9.10.2" + "@polkadot/util" "^10.2.1" + rxjs "^7.6.0" + +"@polkadot/rpc-provider@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-9.10.2.tgz#83c8e114b3aad75eedaf98a374bc77a2b8cc1dbc" + integrity sha512-mm8l1uZ7DOrsMUN+DELS8apyZVVNIy/SrqEBjHZeZ0AA9noAEbH4ubxR375lG/T32+T97mFudv1rxRnEwXqByg== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/keyring" "^10.2.1" + "@polkadot/types" "9.10.2" + "@polkadot/types-support" "9.10.2" + "@polkadot/util" "^10.2.1" + "@polkadot/util-crypto" "^10.2.1" + "@polkadot/x-fetch" "^10.2.1" + "@polkadot/x-global" "^10.2.1" + "@polkadot/x-ws" "^10.2.1" + "@substrate/connect" "0.7.17" eventemitter3 "^4.0.7" mock-socket "^9.1.5" nock "^13.2.9" -"@polkadot/typegen@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/typegen/-/typegen-9.5.2.tgz#b4f3b5eca69c70cc496c8cd3b7804df32282c336" - integrity sha512-DIiicI3VzbqkfjthvHhLYCaElkaKB/qM+P0mGDmb3+NgttJQsH2Sqy/zsT/mjr07hAB1gXf4dhCmj0QQBiR1og== +"@polkadot/typegen@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/typegen/-/typegen-9.10.2.tgz#3a206feaa664afe2cdcc42707b4fa8fde49ce0cc" + integrity sha512-AyO1f/tx173w6pZrQINPu12sCIH9uvn+yRL2sJuCBS5+aqlnsR1JscBk6HIlR6t6Jctx1QCsHycfvSvin3IVoA== dependencies: - "@babel/core" "^7.19.3" + "@babel/core" "^7.20.5" "@babel/register" "^7.18.9" - "@babel/runtime" "^7.19.4" - "@polkadot/api" "9.5.2" - "@polkadot/api-augment" "9.5.2" - "@polkadot/rpc-augment" "9.5.2" - "@polkadot/rpc-provider" "9.5.2" - "@polkadot/types" "9.5.2" - "@polkadot/types-augment" "9.5.2" - "@polkadot/types-codec" "9.5.2" - "@polkadot/types-create" "9.5.2" - "@polkadot/types-support" "9.5.2" - "@polkadot/util" "^10.1.11" - "@polkadot/util-crypto" "^10.1.11" - "@polkadot/x-ws" "^10.1.11" + "@babel/runtime" "^7.20.6" + "@polkadot/api" "9.10.2" + "@polkadot/api-augment" "9.10.2" + "@polkadot/rpc-augment" "9.10.2" + "@polkadot/rpc-provider" "9.10.2" + "@polkadot/types" "9.10.2" + "@polkadot/types-augment" "9.10.2" + "@polkadot/types-codec" "9.10.2" + "@polkadot/types-create" "9.10.2" + "@polkadot/types-support" "9.10.2" + "@polkadot/util" "^10.2.1" + "@polkadot/util-crypto" "^10.2.1" + "@polkadot/x-ws" "^10.2.1" handlebars "^4.7.7" websocket "^1.0.34" - yargs "^17.6.0" - -"@polkadot/types-augment@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/types-augment/-/types-augment-9.5.2.tgz#d9e77756b0e36455d708f5af8265ef011ddf8d91" - integrity sha512-LDJdv/84sECwA0R5lK85/orxjoozJe3+2jeLjRiKr8S6qm9XRfz0wLCSF866kpSGBZ4B1dYBUhzjoSu95y2Jug== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/types" "9.5.2" - "@polkadot/types-codec" "9.5.2" - "@polkadot/util" "^10.1.11" - -"@polkadot/types-codec@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/types-codec/-/types-codec-9.5.2.tgz#345c38ccef17651b8cabd159a42810893b5e7e44" - integrity sha512-FJPjE3ceTGTcadeC8d5C+aSR8SLKuQrXKIBmMNBky+WwzEo0vufRqxFWcPLxAOEeeUPgBXS967tP15+UU4psGA== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/util" "^10.1.11" - "@polkadot/x-bigint" "^10.1.11" - -"@polkadot/types-create@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/types-create/-/types-create-9.5.2.tgz#a85dcb794ea11e5d528baa34b65e57cfafc905cf" - integrity sha512-YbplL8K0LqUEHoV3FgZ5B83oVV67KGbLXsWHVVaUZBPsmtXJXrbBfSyJgl/80I2n4lXEBmg3sFAYMbaSTvL05A== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/types-codec" "9.5.2" - "@polkadot/util" "^10.1.11" - -"@polkadot/types-known@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-9.5.2.tgz#a71fd08932b1643bbf346321472ed48ab1ade215" - integrity sha512-iNaGOF6dGiTvy3Ns8Z7WNjYD1SGnZiapDAKPH4brPuJqMpN6/FxYpfPSSOKx+IJEamsdINcaggb87eWyPxH8CA== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/networks" "^10.1.11" - "@polkadot/types" "9.5.2" - "@polkadot/types-codec" "9.5.2" - "@polkadot/types-create" "9.5.2" - "@polkadot/util" "^10.1.11" - -"@polkadot/types-support@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/types-support/-/types-support-9.5.2.tgz#f2990d19cbd78c24e5b7116466fb1d89f93a8ca7" - integrity sha512-Zdbl5fvGQjUkyE1r67vhyPEqLUwlZ35GCnkoobY9MgN6gylhSjNue/shpG4uGsEjWVQL7GkFkrPiwtzDArVilg== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/util" "^10.1.11" - -"@polkadot/types@9.5.2": - version "9.5.2" - resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-9.5.2.tgz#33ab2caea08f084141a01038adbe53ed69ab7d9c" - integrity sha512-6C5xzOrMK+fu0JMOlSO+8dPDhpwKPOaKMv3v5BMvBEWtDNKM81/QQoAoYT7DSVXq/V16icSFxPs9IWC+6Qq5ag== - dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/keyring" "^10.1.11" - "@polkadot/types-augment" "9.5.2" - "@polkadot/types-codec" "9.5.2" - "@polkadot/types-create" "9.5.2" - "@polkadot/util" "^10.1.11" - "@polkadot/util-crypto" "^10.1.11" - rxjs "^7.5.7" - -"@polkadot/util-crypto@10.1.11", "@polkadot/util-crypto@^10.1.11": - version "10.1.11" - resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-10.1.11.tgz#e59bdc8e1e2bd98a115e2e2ed45461e68a14a48c" - integrity sha512-wG63frIMAR5T/HXGM0SFNzZZdk7qDBsfLXfn6PIZiXCCCsdEYPzS5WltB7fkhicYpbePJ7VgdCAddj1l4IcGyg== - dependencies: - "@babel/runtime" "^7.19.4" + yargs "^17.6.2" + +"@polkadot/types-augment@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/types-augment/-/types-augment-9.10.2.tgz#2dce4ea8a2879d248339ad377ff5479fae884cd5" + integrity sha512-z0M3bAwGi0pGS3ieXyiJZLzDEc5yBvlqaZvaAbf2r+vto83SylhbjjG1wX8ARI5hqptBUWqS9BssUFH0q6l4sg== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/types" "9.10.2" + "@polkadot/types-codec" "9.10.2" + "@polkadot/util" "^10.2.1" + +"@polkadot/types-codec@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/types-codec/-/types-codec-9.10.2.tgz#7f0e33c33292bdfcd959945b2427742b941df712" + integrity sha512-zQOPzxq2N6PUP6Gkxc3OVT7Ub8AD3qC0PBeCnc/fhKjgX3CoKQK4TC6tDL8pEaaIVFh4LOHlHvhWJhqaUNe95A== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/util" "^10.2.1" + "@polkadot/x-bigint" "^10.2.1" + +"@polkadot/types-create@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/types-create/-/types-create-9.10.2.tgz#eb7dbf5f50eb4d01a965347d324de26a679a25e3" + integrity sha512-U6wDaJe8tZmt0WibxWeDFYVKfvOYa2su8xOwg8HTRraijF6k0/OMugb15bpjEkG6RZ1qg1L7oKrKghugVbRDGQ== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/types-codec" "9.10.2" + "@polkadot/util" "^10.2.1" + +"@polkadot/types-known@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-9.10.2.tgz#d37d984eed6aa17b33603aca9f9d006d6eb468cb" + integrity sha512-Kwxoo+xvAAE1w0jZdGqmNoEJHdfJzncO1xrBJ7WjeCuEFoDsWmjP63u/o8VaC1ZNnfrhjRK0vyvquslJ6NQOUA== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/networks" "^10.2.1" + "@polkadot/types" "9.10.2" + "@polkadot/types-codec" "9.10.2" + "@polkadot/types-create" "9.10.2" + "@polkadot/util" "^10.2.1" + +"@polkadot/types-support@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/types-support/-/types-support-9.10.2.tgz#eff0ef399a3373421a543059f62ca96b85645f0b" + integrity sha512-RQSCNNBH8+mzXbErB/LUDU9oMQScv0GZ4UmM2MPDPKBcqXNCdJ4dK+ajNfVbgGTUucYUEebpp2m5Az1usjE4Ew== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/util" "^10.2.1" + +"@polkadot/types@9.10.2": + version "9.10.2" + resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-9.10.2.tgz#1f6647445b055856bdbd949106f698c89a125386" + integrity sha512-B5Bg/IaAMJEwdWzGp3pil5WBukr5fm9x9NFIMuoCS9TyIqpm9rSHrz2n/408R3B4rwqqtx8RQAxiIETFI+m6Rw== + dependencies: + "@babel/runtime" "^7.20.6" + "@polkadot/keyring" "^10.2.1" + "@polkadot/types-augment" "9.10.2" + "@polkadot/types-codec" "9.10.2" + "@polkadot/types-create" "9.10.2" + "@polkadot/util" "^10.2.1" + "@polkadot/util-crypto" "^10.2.1" + rxjs "^7.6.0" + +"@polkadot/util-crypto@10.2.1", "@polkadot/util-crypto@^10.2.1": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-10.2.1.tgz#f6ce1c81496336ca50c2ca84975bcde79aa16634" + integrity sha512-UH1J4oD92gkLXMfVTLee3Y2vYadNyp1lmS4P2nZwQ0SOzGZ4rN7khD2CrB1cXS9WPq196Zb5oZdGLnPYnXHtjw== + dependencies: + "@babel/runtime" "^7.20.6" "@noble/hashes" "1.1.3" "@noble/secp256k1" "1.7.0" - "@polkadot/networks" "10.1.11" - "@polkadot/util" "10.1.11" - "@polkadot/wasm-crypto" "^6.3.1" - "@polkadot/x-bigint" "10.1.11" - "@polkadot/x-randomvalues" "10.1.11" + "@polkadot/networks" "10.2.1" + "@polkadot/util" "10.2.1" + "@polkadot/wasm-crypto" "^6.4.1" + "@polkadot/x-bigint" "10.2.1" + "@polkadot/x-randomvalues" "10.2.1" "@scure/base" "1.1.1" ed2curve "^0.3.0" tweetnacl "^1.0.3" -"@polkadot/util@10.1.11", "@polkadot/util@^10.1.11": - version "10.1.11" - resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-10.1.11.tgz#22bcdabbd7a0d266417f6569cc655f516d371a82" - integrity sha512-6m51lw6g6ilqO/k4BQY7rD0lYM9NCnC4FiM7CEEUc7j8q86qxdcZ88zdNldkhNsTIQnfmCtkK3GRzZW6VYrbUw== +"@polkadot/util@10.2.1", "@polkadot/util@^10.2.1": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-10.2.1.tgz#a8c3a4fe87091197448bec70f7ea079b60d5abf6" + integrity sha512-ewGKSOp+VXKEeCvpCCP2Qqi/FVkewBF9vb/N8pRwuNQ2XE9k1lnsOZZeQemVBDhKsZz+h3IeNcWejaF6K3vYHQ== dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/x-bigint" "10.1.11" - "@polkadot/x-global" "10.1.11" - "@polkadot/x-textdecoder" "10.1.11" - "@polkadot/x-textencoder" "10.1.11" + "@babel/runtime" "^7.20.6" + "@polkadot/x-bigint" "10.2.1" + "@polkadot/x-global" "10.2.1" + "@polkadot/x-textdecoder" "10.2.1" + "@polkadot/x-textencoder" "10.2.1" "@types/bn.js" "^5.1.1" bn.js "^5.2.1" -"@polkadot/wasm-bridge@6.3.1": - version "6.3.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-bridge/-/wasm-bridge-6.3.1.tgz#439fa78e80947a7cb695443e1f64b25c30bb1487" - integrity sha512-1TYkHsb9AEFhU9uZj3biEnN2yKQNzdrwSjiTvfCYnt97pnEkKsZI6cku+YPZQv5w/x9CQa5Yua9e2DVVZSivGA== +"@polkadot/wasm-bridge@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-bridge/-/wasm-bridge-6.4.1.tgz#e97915dd67ba543ec3381299c2a5b9330686e27e" + integrity sha512-QZDvz6dsUlbYsaMV5biZgZWkYH9BC5AfhT0f0/knv8+LrbAoQdP3Asbvddw8vyU9sbpuCHXrd4bDLBwUCRfrBQ== dependencies: - "@babel/runtime" "^7.18.9" + "@babel/runtime" "^7.20.6" -"@polkadot/wasm-crypto-asmjs@6.3.1": - version "6.3.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-6.3.1.tgz#e8f469c9cf4a7709c8131a96f857291953f3e30a" - integrity sha512-zbombRfA5v/mUWQQhgg2YwaxhRmxRIrvskw65x+lruax3b6xPBFDs7yplopiJU3r8h2pTgQvX/DUksvqz2TCRQ== +"@polkadot/wasm-crypto-asmjs@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-6.4.1.tgz#3cc76bbda5ea4a7a860982c64f9565907b312253" + integrity sha512-UxZTwuBZlnODGIQdCsE2Sn/jU0O2xrNQ/TkhRFELfkZXEXTNu4lw6NpaKq7Iey4L+wKd8h4lT3VPVkMcPBLOvA== dependencies: - "@babel/runtime" "^7.18.9" + "@babel/runtime" "^7.20.6" -"@polkadot/wasm-crypto-init@6.3.1": - version "6.3.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-init/-/wasm-crypto-init-6.3.1.tgz#b590220c53c94b9a54d5dc236d0cbe943db76706" - integrity sha512-9yaUBcu+snwjJLmPPGl3cyGRQ1afyFGm16qzTM0sgG/ZCfUlK4uk8KWZe+sBUKgoxb2oXY7Y4WklKgQI1YBdfw== +"@polkadot/wasm-crypto-init@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-init/-/wasm-crypto-init-6.4.1.tgz#4d9ab0030db52cf177bf707ef8e77aa4ca721668" + integrity sha512-1ALagSi/nfkyFaH6JDYfy/QbicVbSn99K8PV9rctDUfxc7P06R7CoqbjGQ4OMPX6w1WYVPU7B4jPHGLYBlVuMw== dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/wasm-bridge" "6.3.1" - "@polkadot/wasm-crypto-asmjs" "6.3.1" - "@polkadot/wasm-crypto-wasm" "6.3.1" + "@babel/runtime" "^7.20.6" + "@polkadot/wasm-bridge" "6.4.1" + "@polkadot/wasm-crypto-asmjs" "6.4.1" + "@polkadot/wasm-crypto-wasm" "6.4.1" -"@polkadot/wasm-crypto-wasm@6.3.1": - version "6.3.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-6.3.1.tgz#67f720e7f9694fef096abe9d60abbac02e032383" - integrity sha512-idSlzKGVzCfeCMRHsacRvqwojSaTadFxL/Dbls4z1thvfa3U9Ku0d2qVtlwg7Hj+tYWDiuP8Kygs+6bQwfs0XA== +"@polkadot/wasm-crypto-wasm@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-6.4.1.tgz#97180f80583b18f6a13c1054fa5f7e8da40b1028" + integrity sha512-3VV9ZGzh0ZY3SmkkSw+0TRXxIpiO0nB8lFwlRgcwaCihwrvLfRnH9GI8WE12mKsHVjWTEVR3ogzILJxccAUjDA== dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/wasm-util" "6.3.1" + "@babel/runtime" "^7.20.6" + "@polkadot/wasm-util" "6.4.1" -"@polkadot/wasm-crypto@^6.3.1": - version "6.3.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-6.3.1.tgz#63f5798aca2b2ff0696f190e6862d9781d8f280c" - integrity sha512-OO8h0qeVkqp4xYZaRVl4iuWOEtq282pNBHDKb6SOJuI2g59eWGcKh4EQU9Me2VP6qzojIqptrkrVt7KQXC68gA== +"@polkadot/wasm-crypto@^6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-6.4.1.tgz#79310e23ad1ca62362ba893db6a8567154c2536a" + integrity sha512-FH+dcDPdhSLJvwL0pMLtn/LIPd62QDPODZRCmDyw+pFjLOMaRBc7raomWUOqyRWJTnqVf/iscc2rLVLNMyt7ag== dependencies: - "@babel/runtime" "^7.18.9" - "@polkadot/wasm-bridge" "6.3.1" - "@polkadot/wasm-crypto-asmjs" "6.3.1" - "@polkadot/wasm-crypto-init" "6.3.1" - "@polkadot/wasm-crypto-wasm" "6.3.1" - "@polkadot/wasm-util" "6.3.1" + "@babel/runtime" "^7.20.6" + "@polkadot/wasm-bridge" "6.4.1" + "@polkadot/wasm-crypto-asmjs" "6.4.1" + "@polkadot/wasm-crypto-init" "6.4.1" + "@polkadot/wasm-crypto-wasm" "6.4.1" + "@polkadot/wasm-util" "6.4.1" -"@polkadot/wasm-util@6.3.1": - version "6.3.1" - resolved "https://registry.yarnpkg.com/@polkadot/wasm-util/-/wasm-util-6.3.1.tgz#439ebb68a436317af388ed6438b8f879df3afcda" - integrity sha512-12oAv5J7Yoc9m6jixrSaQCxpOkWOyzHx3DMC8qmLjRiwdBWxqLmImOVRVnFsbaxqSbhBIHRuJphVxWE+GZETDg== +"@polkadot/wasm-util@6.4.1": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@polkadot/wasm-util/-/wasm-util-6.4.1.tgz#74aecc85bec427a9225d9874685944ea3dc3ab76" + integrity sha512-Uwo+WpEsDmFExWC5kTNvsVhvqXMZEKf4gUHXFn4c6Xz4lmieRT5g+1bO1KJ21pl4msuIgdV3Bksfs/oiqMFqlw== dependencies: - "@babel/runtime" "^7.18.9" + "@babel/runtime" "^7.20.6" -"@polkadot/x-bigint@10.1.11", "@polkadot/x-bigint@^10.1.11": - version "10.1.11" - resolved "https://registry.yarnpkg.com/@polkadot/x-bigint/-/x-bigint-10.1.11.tgz#7d62ce10cccd55b86a415342db95b9feeb099776" - integrity sha512-TC4KZ+ni/SJhcf/LIwD49C/kwvACu0nCchETNO+sAfJ7COXZwHDUJXVXmwN5PgkQxwsWsKKuJmzR/Fi1bgMWnQ== +"@polkadot/x-bigint@10.2.1", "@polkadot/x-bigint@^10.2.1": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-bigint/-/x-bigint-10.2.1.tgz#aa2d4384bb4ae6b5a3f333aa25bf6fd64d9006c5" + integrity sha512-asFroI2skC4gYv0oIqqb84DqCCxhNUTSCKobEg57WdXoT4TKrN9Uetg2AMSIHRiX/9lP3EPMhUjM1VVGobTQRQ== dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/x-global" "10.1.11" + "@babel/runtime" "^7.20.6" + "@polkadot/x-global" "10.2.1" -"@polkadot/x-fetch@^10.1.11": - version "10.1.11" - resolved "https://registry.yarnpkg.com/@polkadot/x-fetch/-/x-fetch-10.1.11.tgz#8f579bb166096c977acff91a40b3848fb5581900" - integrity sha512-WtyUr9itVD9BLnxCUloJ1iwrXOY/lnlEShEYKHcSm6MIHtbJolePd3v1+o5mOX+bdDbHXhPZnH8anCCqDNDRqg== +"@polkadot/x-fetch@^10.2.1": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-fetch/-/x-fetch-10.2.1.tgz#cb5b33da1d91787eb2e5207ef62806a75ef3c62f" + integrity sha512-6ASJUZIrbLaKW+AOW7E5CuktwJwa2LHhxxRyJe398HxZUjJRjO2VJPdqoSwwCYvfFa1TcIr3FDWS63ooDfvGMA== dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/x-global" "10.1.11" + "@babel/runtime" "^7.20.6" + "@polkadot/x-global" "10.2.1" "@types/node-fetch" "^2.6.2" - node-fetch "^3.2.10" + node-fetch "^3.3.0" -"@polkadot/x-global@10.1.11", "@polkadot/x-global@^10.1.11": - version "10.1.11" - resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-10.1.11.tgz#37dda3ef1cebfd14c68c69279ae6521957817866" - integrity sha512-bWz5gdcELy6+xfr27R1GE5MPX4nfVlchzHQH+DR6OBbSi9g/PeycQAvFB6IkTmP+YEbNNtIpxnSP37zoUaG3xw== +"@polkadot/x-global@10.2.1", "@polkadot/x-global@^10.2.1": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-global/-/x-global-10.2.1.tgz#6fbaab05653e680adc8c69c07947eee49afc1238" + integrity sha512-kWmPku2lCcoYKU16+lWGOb95+6Lu9zo1trvzTWmAt7z0DXw2GlD9+qmDTt5iYGtguJsGXoRZDGilDTo3MeFrkA== dependencies: - "@babel/runtime" "^7.19.4" + "@babel/runtime" "^7.20.6" -"@polkadot/x-randomvalues@10.1.11": - version "10.1.11" - resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-10.1.11.tgz#f9e088f8b400770d3e53ba9e0c0f0d464047f89e" - integrity sha512-V2V37f5hoM5B32eCpGw87Lwstin2+ArXhOZ8ENKncbQLXzbF9yTODueDoA5Vt0MJCs2CDP9cyiCYykcanqVkxg== +"@polkadot/x-randomvalues@10.2.1": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-randomvalues/-/x-randomvalues-10.2.1.tgz#1c463625c0b7cf775e94594f522eb21a5229b42e" + integrity sha512-bEwG6j/+HMZ5LIkyzRbTB0N1Wz2lHyxP25pPFgHFqGqon/KZoRN5kxOwEJ1DpPJIv+9PVn5tt7bc4R3qsaZ93g== dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/x-global" "10.1.11" + "@babel/runtime" "^7.20.6" + "@polkadot/x-global" "10.2.1" -"@polkadot/x-textdecoder@10.1.11": - version "10.1.11" - resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-10.1.11.tgz#314c79e27545a41fe0494a26196bf2dff5cfcb5d" - integrity sha512-QZqie04SR6pAj260PaLBfZUGXWKI357t4ROVJhpaj06qc1zrk1V8Mwkr49+WzjAPFEOqo70HWnzXmPNCH4dQiw== +"@polkadot/x-textdecoder@10.2.1": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-textdecoder/-/x-textdecoder-10.2.1.tgz#c1778ef35e2aa8db8f11bbe31a5bbf5e46017d7d" + integrity sha512-hpFmrdv/rrSM4UNaV8TJBgMtwXsYlNgBTSUmnKWwJIN3PhOUeYxl1qIbPchxGbJBc35WviJCZe7rlLja9JvFcw== dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/x-global" "10.1.11" + "@babel/runtime" "^7.20.6" + "@polkadot/x-global" "10.2.1" -"@polkadot/x-textencoder@10.1.11": - version "10.1.11" - resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-10.1.11.tgz#23b18b3ffbc649572728aa37d7787432bb3a03b5" - integrity sha512-UX+uV9AbDID81waaG/NvTkkf7ZNVW7HSHaddgbWjQEVW2Ex4ByccBarY5jEi6cErEPKfzCamKhgXflu0aV9LWw== +"@polkadot/x-textencoder@10.2.1": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-textencoder/-/x-textencoder-10.2.1.tgz#c09562c73a44659243075d43b007b5c1b39c57a8" + integrity sha512-4gMyY6DCH34KA++bawu/zlUJ0/8+aZJsurwjRBbkdfOS2uLo0K+vJ5GBevAhl0VSznM36ptfh/MpkIBKK/6R0g== dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/x-global" "10.1.11" + "@babel/runtime" "^7.20.6" + "@polkadot/x-global" "10.2.1" -"@polkadot/x-ws@^10.1.11": - version "10.1.11" - resolved "https://registry.yarnpkg.com/@polkadot/x-ws/-/x-ws-10.1.11.tgz#7431ad72064d56519d4293278f03ae97b9ea9271" - integrity sha512-EUbL/R1A/NxYf6Rnb1M7U9yeTuo5r4y2vcQllE5aBLaQ0cFnRykHzlmZlVX1E7O5uy3lYVdxWC7sNgxItIWkWA== +"@polkadot/x-ws@^10.2.1": + version "10.2.1" + resolved "https://registry.yarnpkg.com/@polkadot/x-ws/-/x-ws-10.2.1.tgz#ec119c22a8cb7b9cde00e9909e37b6ba2845efd1" + integrity sha512-oS/WEHc1JSJ+xMArzFXbg1yEeaRrp6GsJLBvObj4DgTyqoWTR5fYkq1G1nHbyqdR729yAnR6755PdaWecIg98g== dependencies: - "@babel/runtime" "^7.19.4" - "@polkadot/x-global" "10.1.11" + "@babel/runtime" "^7.20.6" + "@polkadot/x-global" "10.2.1" "@types/websocket" "^1.0.5" websocket "^1.0.34" @@ -884,27 +893,27 @@ resolved "https://registry.yarnpkg.com/@substrate/connect-extension-protocol/-/connect-extension-protocol-1.0.1.tgz#fa5738039586c648013caa6a0c95c43265dbe77d" integrity sha512-161JhCC1csjH3GE5mPLEd7HbWtwNSPJBg3p1Ksz9SFlTzj/bgEwudiRN2y5i0MoLGCIJRYKyKGMxVnd29PzNjg== -"@substrate/connect@0.7.14": - version "0.7.14" - resolved "https://registry.yarnpkg.com/@substrate/connect/-/connect-0.7.14.tgz#c090e952e9cdd93185a94d24fbc424ea20fe7bbe" - integrity sha512-uW5uBmihpivshmmmw+rsg7qOV0KqVSep4rWOXFMP8aFQinvmqw4JqxP21og4H/7JZxttYUBFQVsdtXHGKJ0aVQ== +"@substrate/connect@0.7.17": + version "0.7.17" + resolved "https://registry.yarnpkg.com/@substrate/connect/-/connect-0.7.17.tgz#b76ce23d24255e89028db81b3cb280c7f86db72e" + integrity sha512-s0XBmGpUCFWZFa+TS0TEvOKtWjJP2uT4xKmvzApH8INB5xbz79wqWFX6WWh3AlK/X1P0Smt+RVEH7HQiLJAYAw== dependencies: "@substrate/connect-extension-protocol" "^1.0.1" - "@substrate/smoldot-light" "0.6.34" + "@substrate/smoldot-light" "0.7.7" eventemitter3 "^4.0.7" -"@substrate/smoldot-light@0.6.34": - version "0.6.34" - resolved "https://registry.yarnpkg.com/@substrate/smoldot-light/-/smoldot-light-0.6.34.tgz#273dba622102281fd0fdb0e375198bff2ec584c3" - integrity sha512-+HK9MaJ0HelJmpf4YYR+salJ7dhVBltmhGlyz5l8OXS9DW18fe0Z2wxEo8P5kX9CUxlCXEb8J9JBRQAYBPHbwQ== +"@substrate/smoldot-light@0.7.7": + version "0.7.7" + resolved "https://registry.yarnpkg.com/@substrate/smoldot-light/-/smoldot-light-0.7.7.tgz#ee5f89bb25af64d2014d97548b959b7da4c67f08" + integrity sha512-ksxeAed6dIUtYSl0f8ehgWQjwXnpDGTIJt+WVRIGt3OObZkA96ZdBWx0xP7GrXZtj37u4n/Y1z7TyTm4bwQvrw== dependencies: pako "^2.0.4" ws "^8.8.1" -"@substrate/ss58-registry@^1.33.0": - version "1.33.0" - resolved "https://registry.yarnpkg.com/@substrate/ss58-registry/-/ss58-registry-1.33.0.tgz#b93218fc86405769716b02f0ce5e61df221b37ae" - integrity sha512-DztMuMcEfu+tJrtIQIIp5gO8/XJZ8N8UwPObDCSNgrp7trtSkPJAUFB9qXaReXtN9UvTcVBMTWk6VPfFi04Wkg== +"@substrate/ss58-registry@^1.35.0": + version "1.36.0" + resolved "https://registry.yarnpkg.com/@substrate/ss58-registry/-/ss58-registry-1.36.0.tgz#22b59fa85cacc0bdf40aa5d8131a377c1b5a8dd8" + integrity sha512-YfQIpe2bIvGg/XWNByycznbOiAknMvpYaUpQJ2sLmNT/OwPx7XjEXk7dLShccuiQDoOQt3trTtF3Frz/Tjv6Fg== "@szmarczak/http-timer@^4.0.5": version "4.0.6" @@ -948,14 +957,14 @@ "@types/node" "*" "@types/cacheable-request@^6.0.1", "@types/cacheable-request@^6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.2.tgz#c324da0197de0a98a2312156536ae262429ff6b9" - integrity sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA== + version "6.0.3" + resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" + integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== dependencies: "@types/http-cache-semantics" "*" - "@types/keyv" "*" + "@types/keyv" "^3.1.4" "@types/node" "*" - "@types/responselike" "*" + "@types/responselike" "^1.0.0" "@types/chai-as-promised@^7.1.5": version "7.1.5" @@ -971,10 +980,17 @@ dependencies: "@types/chai" "*" +"@types/chai-subset@^1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@types/chai-subset/-/chai-subset-1.3.3.tgz#97893814e92abd2c534de422cb377e0e0bdaac94" + integrity sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw== + dependencies: + "@types/chai" "*" + "@types/chai@*", "@types/chai@^4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.3.tgz#3c90752792660c4b562ad73b3fbd68bf3bc7ae07" - integrity sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g== + version "4.3.4" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.4.tgz#e913e8175db8307d78b4e8fa690408ba6b65dee4" + integrity sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw== "@types/http-cache-semantics@*": version "4.0.1" @@ -986,17 +1002,17 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== -"@types/keyv@*": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-4.2.0.tgz#65b97868ab757906f2dbb653590d7167ad023fa0" - integrity sha512-xoBtGl5R9jeKUhc8ZqeYaRDx04qqJ10yhhXYGmJ4Jr8qKpvMsDQQrNUvF/wUJ4klOtmJeJM+p2Xo3zp9uaC3tw== +"@types/keyv@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== dependencies: - keyv "*" + "@types/node" "*" "@types/mocha@^10.0.0": - version "10.0.0" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.0.tgz#3d9018c575f0e3f7386c1de80ee66cc21fbb7a52" - integrity sha512-rADY+HtTOA52l9VZWtgQfn4p+UDVM2eDVkMZT1I6syp0YKxW2F9v+0pbRZLsvskhQv/vMb6ZfCay81GHbz5SHg== + version "10.0.1" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.1.tgz#2f4f65bb08bc368ac39c96da7b2f09140b26851b" + integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q== "@types/node-fetch@^2.6.2": version "2.6.2" @@ -1007,9 +1023,9 @@ form-data "^3.0.0" "@types/node@*", "@types/node@^18.11.2": - version "18.11.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.2.tgz#c59b7641832531264fda3f1ba610362dc9a7dfc8" - integrity sha512-BWN3M23gLO2jVG8g/XHIRFWiiV4/GckeFIqbU/C4V3xpoBBWSMk4OZomouN0wCkfQFPqgZikyLr7DOYDysIkkw== + version "18.11.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.17.tgz#5c009e1d9c38f4a2a9d45c0b0c493fe6cdb4bcb5" + integrity sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng== "@types/node@^12.12.6": version "12.20.55" @@ -1023,7 +1039,7 @@ dependencies: "@types/node" "*" -"@types/responselike@*", "@types/responselike@^1.0.0": +"@types/responselike@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== @@ -1038,9 +1054,9 @@ "@types/node" "*" "@types/semver@^7.3.12": - version "7.3.12" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.12.tgz#920447fdd78d76b19de0438b7f60df3c4a80bf1c" - integrity sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A== + version "7.3.13" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== "@types/websocket@^1.0.5": version "1.0.5" @@ -1049,86 +1065,87 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^5.40.1": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.1.tgz#3203a6ff396b1194083faaa6e5110c401201d7d5" - integrity sha512-FsWboKkWdytGiXT5O1/R9j37YgcjO8MKHSUmWnIEjVaz0krHkplPnYi7mwdb+5+cs0toFNQb0HIrN7zONdIEWg== +"@typescript-eslint/eslint-plugin@^5.47.0": + version "5.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz#dadb79df3b0499699b155839fd6792f16897d910" + integrity sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ== dependencies: - "@typescript-eslint/scope-manager" "5.40.1" - "@typescript-eslint/type-utils" "5.40.1" - "@typescript-eslint/utils" "5.40.1" + "@typescript-eslint/scope-manager" "5.47.0" + "@typescript-eslint/type-utils" "5.47.0" + "@typescript-eslint/utils" "5.47.0" debug "^4.3.4" ignore "^5.2.0" + natural-compare-lite "^1.4.0" regexpp "^3.2.0" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.40.1": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.40.1.tgz#e7f8295dd8154d0d37d661ddd8e2f0ecfdee28dd" - integrity sha512-IK6x55va5w4YvXd4b3VrXQPldV9vQTxi5ov+g4pMANsXPTXOcfjx08CRR1Dfrcc51syPtXHF5bgLlMHYFrvQtg== +"@typescript-eslint/parser@^5.47.0": + version "5.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.47.0.tgz#62e83de93499bf4b500528f74bf2e0554e3a6c8d" + integrity sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw== dependencies: - "@typescript-eslint/scope-manager" "5.40.1" - "@typescript-eslint/types" "5.40.1" - "@typescript-eslint/typescript-estree" "5.40.1" + "@typescript-eslint/scope-manager" "5.47.0" + "@typescript-eslint/types" "5.47.0" + "@typescript-eslint/typescript-estree" "5.47.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.40.1": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.40.1.tgz#a7a5197dfd234622a2421ea590ee0ccc02e18dfe" - integrity sha512-jkn4xsJiUQucI16OLCXrLRXDZ3afKhOIqXs4R3O+M00hdQLKR58WuyXPZZjhKLFCEP2g+TXdBRtLQ33UfAdRUg== +"@typescript-eslint/scope-manager@5.47.0": + version "5.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz#f58144a6b0ff58b996f92172c488813aee9b09df" + integrity sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw== dependencies: - "@typescript-eslint/types" "5.40.1" - "@typescript-eslint/visitor-keys" "5.40.1" + "@typescript-eslint/types" "5.47.0" + "@typescript-eslint/visitor-keys" "5.47.0" -"@typescript-eslint/type-utils@5.40.1": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.40.1.tgz#091e4ce3bebbdb68f4980bae9dee2e4e1725f601" - integrity sha512-DLAs+AHQOe6n5LRraXiv27IYPhleF0ldEmx6yBqBgBLaNRKTkffhV1RPsjoJBhVup2zHxfaRtan8/YRBgYhU9Q== +"@typescript-eslint/type-utils@5.47.0": + version "5.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.47.0.tgz#2b440979c574e317d3473225ae781f292c99e55d" + integrity sha512-1J+DFFrYoDUXQE1b7QjrNGARZE6uVhBqIvdaXTe5IN+NmEyD68qXR1qX1g2u4voA+nCaelQyG8w30SAOihhEYg== dependencies: - "@typescript-eslint/typescript-estree" "5.40.1" - "@typescript-eslint/utils" "5.40.1" + "@typescript-eslint/typescript-estree" "5.47.0" + "@typescript-eslint/utils" "5.47.0" debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.40.1": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.40.1.tgz#de37f4f64de731ee454bb2085d71030aa832f749" - integrity sha512-Icg9kiuVJSwdzSQvtdGspOlWNjVDnF3qVIKXdJ103o36yRprdl3Ge5cABQx+csx960nuMF21v8qvO31v9t3OHw== +"@typescript-eslint/types@5.47.0": + version "5.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.47.0.tgz#67490def406eaa023dbbd8da42ee0d0c9b5229d3" + integrity sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg== -"@typescript-eslint/typescript-estree@5.40.1": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.1.tgz#9a7d25492f02c69882ce5e0cd1857b0c55645d72" - integrity sha512-5QTP/nW5+60jBcEPfXy/EZL01qrl9GZtbgDZtDPlfW5zj/zjNrdI2B5zMUHmOsfvOr2cWqwVdWjobCiHcedmQA== +"@typescript-eslint/typescript-estree@5.47.0": + version "5.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz#ed971a11c5c928646d6ba7fc9dfdd6e997649aca" + integrity sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q== dependencies: - "@typescript-eslint/types" "5.40.1" - "@typescript-eslint/visitor-keys" "5.40.1" + "@typescript-eslint/types" "5.47.0" + "@typescript-eslint/visitor-keys" "5.47.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.40.1": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.40.1.tgz#3204fb73a559d3b7bab7dc9d3c44487c2734a9ca" - integrity sha512-a2TAVScoX9fjryNrW6BZRnreDUszxqm9eQ9Esv8n5nXApMW0zeANUYlwh/DED04SC/ifuBvXgZpIK5xeJHQ3aw== +"@typescript-eslint/utils@5.47.0": + version "5.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.47.0.tgz#b5005f7d2696769a1fdc1e00897005a25b3a0ec7" + integrity sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw== dependencies: "@types/json-schema" "^7.0.9" "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.40.1" - "@typescript-eslint/types" "5.40.1" - "@typescript-eslint/typescript-estree" "5.40.1" + "@typescript-eslint/scope-manager" "5.47.0" + "@typescript-eslint/types" "5.47.0" + "@typescript-eslint/typescript-estree" "5.47.0" eslint-scope "^5.1.1" eslint-utils "^3.0.0" semver "^7.3.7" -"@typescript-eslint/visitor-keys@5.40.1": - version "5.40.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.1.tgz#f3d2bf5af192f4432b84cec6fdcb387193518754" - integrity sha512-A2DGmeZ+FMja0geX5rww+DpvILpwo1OsiQs0M+joPWJYsiEFBLsH0y1oFymPNul6Z5okSmHpP4ivkc2N0Cgfkw== +"@typescript-eslint/visitor-keys@5.47.0": + version "5.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz#4aca4efbdf6209c154df1f7599852d571b80bb45" + integrity sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg== dependencies: - "@typescript-eslint/types" "5.40.1" + "@typescript-eslint/types" "5.47.0" eslint-visitor-keys "^3.3.0" abortcontroller-polyfill@^1.7.3: @@ -1155,9 +1172,9 @@ acorn-walk@^8.1.1: integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== acorn@^8.4.1, acorn@^8.8.0: - version "8.8.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" - integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + version "8.8.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" + integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" @@ -1194,9 +1211,9 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: color-convert "^2.0.1" anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -1298,9 +1315,9 @@ bcrypt-pbkdf@^1.0.0: tweetnacl "^0.14.3" bignumber.js@^9.0.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.0.tgz#8d340146107fe3a6cb8d40699643c302e8773b62" - integrity sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A== + version "9.1.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6" + integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig== binary-extensions@^2.0.0: version "2.2.0" @@ -1539,9 +1556,9 @@ camelcase@^6.0.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001400: - version "1.0.30001422" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001422.tgz#f2d7c6202c49a8359e6e35add894d88ef93edba1" - integrity sha512-hSesn02u1QacQHhaxl/kNMZwqVG35Sz/8DgvmgedxSH8z9UUpcDYSPYgsj3x5dQNRcNp6BwpSfQfVzYUTm+fog== + version "1.0.30001441" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001441.tgz#987437b266260b640a23cd18fbddb509d7f69f3e" + integrity sha512-OyxRR4Vof59I3yGWXws6i908EtGbMzVUi3ganaZQHmydk1iwDhRnvaPG2WaR0KcqrDFKrxVZHULT396LEPhXfg== caseless@~0.12.0: version "0.12.0" @@ -1560,14 +1577,19 @@ chai-like@^1.1.1: resolved "https://registry.yarnpkg.com/chai-like/-/chai-like-1.1.1.tgz#8c558a414c34514e814d497c772547ceb7958f64" integrity sha512-VKa9z/SnhXhkT1zIjtPACFWSoWsqVoaz1Vg+ecrKo5DCKVlgL30F/pEyEvXPBOVwCgLZcWUleCM/C1okaKdTTA== +chai-subset@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/chai-subset/-/chai-subset-1.6.0.tgz#a5d0ca14e329a79596ed70058b6646bd6988cfe9" + integrity sha512-K3d+KmqdS5XKW5DWPd5sgNffL3uxdDe+6GdnJh3AYPhwnBGRY5urfvfcbRtWIvvpz+KxkL9FeBB6MZewLUNwug== + chai@^4.3.6: - version "4.3.6" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c" - integrity sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q== + version "4.3.7" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.7.tgz#ec63f6df01829088e8bf55fca839bcd464a8ec51" + integrity sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A== dependencies: assertion-error "^1.1.0" check-error "^1.0.2" - deep-eql "^3.0.1" + deep-eql "^4.1.2" get-func-name "^2.0.0" loupe "^2.3.1" pathval "^1.1.1" @@ -1852,6 +1874,11 @@ crypto-browserify@3.12.0: randombytes "^2.0.0" randomfill "^1.0.3" +csv-writer@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/csv-writer/-/csv-writer-1.6.0.tgz#d0cea44b6b4d7d3baa2ecc6f3f7209233514bcf9" + integrity sha512-NOx7YDFWEsM/fTRAJjRpPp8t+MKRVvniAg9wQlUKx20MFrPs73WLJhFf5iteqrxNYnsy924K3Iroh3yNHeYd2g== + d@1, d@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" @@ -1891,10 +1918,10 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== +decode-uri-component@^0.2.0, decode-uri-component@^0.2.1: + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== decompress-response@^3.3.0: version "3.3.0" @@ -1910,10 +1937,10 @@ decompress-response@^6.0.0: dependencies: mimic-response "^3.1.0" -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== +deep-eql@^4.1.2: + version "4.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== dependencies: type-detect "^4.0.0" @@ -1927,14 +1954,6 @@ defer-to-connect@^2.0.0, defer-to-connect@^2.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== -define-properties@^1.1.3, define-properties@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" - integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== - dependencies: - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -2051,45 +2070,6 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" -es-abstract@^1.19.0, es-abstract@^1.19.5, es-abstract@^1.20.0: - version "1.20.4" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.4.tgz#1d103f9f8d78d4cf0713edcd6d0ed1a46eed5861" - integrity sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.1.3" - get-symbol-description "^1.0.0" - has "^1.0.3" - has-property-descriptors "^1.0.0" - has-symbols "^1.0.3" - internal-slot "^1.0.3" - is-callable "^1.2.7" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-weakref "^1.0.2" - object-inspect "^1.12.2" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" - safe-regex-test "^1.0.0" - string.prototype.trimend "^1.0.5" - string.prototype.trimstart "^1.0.5" - unbox-primitive "^1.0.2" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - es5-ext@^0.10.35, es5-ext@^0.10.50: version "0.10.62" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" @@ -2183,13 +2163,14 @@ eslint-visitor-keys@^3.3.0: integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== eslint@^8.25.0: - version "8.25.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.25.0.tgz#00eb962f50962165d0c4ee3327708315eaa8058b" - integrity sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A== + version "8.30.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.30.0.tgz#83a506125d089eef7c5b5910eeea824273a33f50" + integrity sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ== dependencies: - "@eslint/eslintrc" "^1.3.3" - "@humanwhocodes/config-array" "^0.10.5" + "@eslint/eslintrc" "^1.4.0" + "@humanwhocodes/config-array" "^0.11.8" "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -2205,14 +2186,14 @@ eslint@^8.25.0: fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" find-up "^5.0.0" - glob-parent "^6.0.1" - globals "^13.15.0" - globby "^11.1.0" + glob-parent "^6.0.2" + globals "^13.19.0" grapheme-splitter "^1.0.4" ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" + is-path-inside "^3.0.3" js-sdsl "^4.1.4" js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" @@ -2227,9 +2208,9 @@ eslint@^8.25.0: text-table "^0.2.0" espree@^9.4.0: - version "9.4.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.0.tgz#cd4bc3d6e9336c433265fc0aa016fc1aaf182f8a" - integrity sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw== + version "9.4.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" + integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== dependencies: acorn "^8.8.0" acorn-jsx "^5.3.2" @@ -2326,7 +2307,7 @@ ethereum-cryptography@^0.1.3: secp256k1 "^4.0.1" setimmediate "^1.0.5" -ethereumjs-util@^7.0.10, ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.5: +ethereumjs-util@^7.0.10, ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereumjs-util@^7.1.5: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== @@ -2449,9 +2430,9 @@ fast-levenshtein@^2.0.6: integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + version "1.14.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.14.0.tgz#107f69d7295b11e0fccc264e1fc6389f623731ce" + integrity sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg== dependencies: reusify "^1.0.4" @@ -2629,21 +2610,6 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" - -functions-have-names@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== - gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -2659,7 +2625,7 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: +get-intrinsic@^1.0.2, get-intrinsic@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== @@ -2680,14 +2646,6 @@ get-stream@^6.0.1: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" @@ -2702,7 +2660,7 @@ glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob-parent@^6.0.1: +glob-parent@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== @@ -2746,10 +2704,10 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.15.0: - version "13.17.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4" - integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw== +globals@^13.19.0: + version "13.19.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.19.0.tgz#7a42de8e6ad4f7242fbcca27ea5b23aca367b5c8" + integrity sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ== dependencies: type-fest "^0.20.2" @@ -2765,6 +2723,13 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + got@12.1.0: version "12.1.0" resolved "https://registry.yarnpkg.com/got/-/got-12.1.0.tgz#099f3815305c682be4fd6b0ee0726d8e4c6b0af4" @@ -2785,9 +2750,9 @@ got@12.1.0: responselike "^2.0.0" got@^11.8.5: - version "11.8.5" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.5.tgz#ce77d045136de56e8f024bebb82ea349bc730046" - integrity sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ== + version "11.8.6" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" + integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== dependencies: "@sindresorhus/is" "^4.0.0" "@szmarczak/http-timer" "^4.0.5" @@ -2836,11 +2801,6 @@ har-validator@~5.1.3: ajv "^6.12.3" har-schema "^2.0.0" -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -2851,13 +2811,6 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== - dependencies: - get-intrinsic "^1.1.1" - has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" @@ -2947,9 +2900,9 @@ http2-wrapper@^1.0.0-beta.5.2: resolve-alpn "^1.0.0" http2-wrapper@^2.1.10: - version "2.1.11" - resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-2.1.11.tgz#d7c980c7ffb85be3859b6a96c800b2951ae257ef" - integrity sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-2.2.0.tgz#b80ad199d216b7d3680195077bd7b9060fa9d7f3" + integrity sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ== dependencies: quick-lru "^5.1.1" resolve-alpn "^1.2.0" @@ -2974,9 +2927,9 @@ ieee754@^1.1.13: integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" @@ -3004,15 +2957,6 @@ inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== - dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" - ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -3026,13 +2970,6 @@ is-arguments@^1.0.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -3040,26 +2977,11 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: +is-callable@^1.1.3: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -3094,23 +3016,16 @@ is-hex-prefixed@1.0.0: resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-obj@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" @@ -3123,44 +3038,15 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== - dependencies: - call-bind "^1.0.2" - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-typed-array@^1.1.3, is-typed-array@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.9.tgz#246d77d2871e7d9f5aeb1d54b9f52c71329ece67" - integrity sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A== +is-typed-array@^1.1.10, is-typed-array@^1.1.3: + version "1.1.10" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" + integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== dependencies: available-typed-arrays "^1.0.5" call-bind "^1.0.2" - es-abstract "^1.20.0" for-each "^0.3.3" + gopd "^1.0.1" has-tostringtag "^1.0.0" is-typedarray@^1.0.0, is-typedarray@~1.0.0: @@ -3173,13 +3059,6 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -3196,9 +3075,9 @@ isstream@~0.1.2: integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== js-sdsl@^4.1.4: - version "4.1.5" - resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.1.5.tgz#1ff1645e6b4d1b028cd3f862db88c9d887f26e2a" - integrity sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q== + version "4.2.0" + resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.2.0.tgz#278e98b7bea589b8baaf048c20aeb19eb7ad09d0" + integrity sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ== js-sha3@0.8.0, js-sha3@^0.8.0: version "0.8.0" @@ -3258,9 +3137,9 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== json5@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" - integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + version "2.2.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.2.tgz#64471c5bdcc564c18f7c1d4df2e2297f2457c5ab" + integrity sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ== jsonfile@^4.0.0: version "4.0.0" @@ -3288,10 +3167,10 @@ keccak@^3.0.0: node-gyp-build "^4.2.0" readable-stream "^3.6.0" -keyv@*, keyv@^4.0.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.0.tgz#dbce9ade79610b6e641a9a65f2f6499ba06b9bc6" - integrity sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA== +keyv@^4.0.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.2.tgz#0e310ce73bf7851ec702f2eaf46ec4e3805cce56" + integrity sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g== dependencies: json-buffer "3.0.1" @@ -3342,9 +3221,9 @@ log-symbols@4.1.0: is-unicode-supported "^0.1.0" loupe@^2.3.1: - version "2.3.4" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.4.tgz#7e0b9bffc76f148f9be769cb1321d3dcf3cb25f3" - integrity sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ== + version "2.3.6" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" + integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA== dependencies: get-func-name "^2.0.0" @@ -3358,6 +3237,13 @@ lowercase-keys@^3.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -3479,7 +3365,7 @@ minimatch@5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -3526,9 +3412,9 @@ mkdirp@^0.5.5: minimist "^1.2.6" mocha@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.1.0.tgz#dbf1114b7c3f9d0ca5de3133906aea3dfc89ef7a" - integrity sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg== + version "10.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" + integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== dependencies: ansi-colors "4.1.1" browser-stdout "1.3.1" @@ -3627,6 +3513,11 @@ nanoid@3.3.3: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -3674,10 +3565,10 @@ node-fetch@2.6.7: dependencies: whatwg-url "^5.0.0" -node-fetch@^3.2.10: - version "3.2.10" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.10.tgz#e8347f94b54ae18b57c9c049ef641cef398a85c8" - integrity sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA== +node-fetch@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.0.tgz#37e71db4ecc257057af828d523a7243d651d91e4" + integrity sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA== dependencies: data-uri-to-buffer "^4.0.0" fetch-blob "^3.1.4" @@ -3689,9 +3580,9 @@ node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== node-releases@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" - integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== + version "2.0.8" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.8.tgz#0f349cdc8fcfa39a92ac0be9bc48b7706292b9ae" + integrity sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -3721,26 +3612,11 @@ object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.12.2, object-inspect@^1.9.0: +object-inspect@^1.9.0: version "1.12.2" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - has-symbols "^1.0.3" - object-keys "^1.1.1" - oboe@2.1.5: version "2.1.5" resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.5.tgz#5554284c543a2266d7a38f17e073821fbde393cd" @@ -3823,9 +3699,9 @@ p-try@^2.0.0: integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== pako@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pako/-/pako-2.0.4.tgz#6cebc4bbb0b6c73b0d5b8d7e8476e2b2fbea576d" - integrity sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg== + version "2.1.0" + resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" + integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== parent-module@^1.0.0: version "1.0.1" @@ -4023,9 +3899,9 @@ quick-lru@^5.1.1: integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== rambda@^7.1.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/rambda/-/rambda-7.3.0.tgz#90e440ead53030a216093865d8d97997a80868ca" - integrity sha512-RFVofZYaG2TaVcxjnM0ejdVWf/59rFq1f57OGnjP3GT/bthzFw0GVr5rkP9PKbVlEuF/Y7bOVPLfiiYfxq/EWQ== + version "7.4.0" + resolved "https://registry.yarnpkg.com/rambda/-/rambda-7.4.0.tgz#61ec9de31d3dd6affe804de3bae04a5b818781e5" + integrity sha512-A9hihu7dUTLOUCM+I8E61V4kRXnN4DwYeK0DwCBydC1MqNI1PidyAtbtpsJlBBzK4icSctEcCQ1bGcLpBuETUQ== randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" @@ -4073,19 +3949,10 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -regenerator-runtime@^0.13.4: - version "0.13.10" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz#ed07b19616bcbec5da6274ebc75ae95634bfc2ee" - integrity sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw== - -regexp.prototype.flags@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" - integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - functions-have-names "^1.2.2" +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== regexpp@^3.2.0: version "3.2.0" @@ -4174,10 +4041,10 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^7.5.7: - version "7.5.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.7.tgz#2ec0d57fdc89ece220d2e702730ae8f1e49def39" - integrity sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA== +rxjs@^7.6.0: + version "7.8.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" + integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== dependencies: tslib "^2.1.0" @@ -4191,15 +4058,6 @@ safe-buffer@~5.1.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-regex-test@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" - integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - is-regex "^1.1.4" - "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -4408,24 +4266,6 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string.prototype.trimend@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" - integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.19.5" - -string.prototype.trimstart@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" - integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.19.5" - string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -4575,9 +4415,9 @@ tslib@^1.8.1: integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + version "2.4.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" + integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== tsutils@^3.21.0: version "3.21.0" @@ -4646,30 +4486,20 @@ typedarray-to-buffer@^3.1.5: is-typedarray "^1.0.0" typescript@^4.8.4: - version "4.8.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" - integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + version "4.9.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78" + integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg== uglify-js@^3.1.4: - version "3.17.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.3.tgz#f0feedf019c4510f164099e8d7e72ff2d7304377" - integrity sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg== + version "3.17.4" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" + integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -4733,16 +4563,16 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== - uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" @@ -4772,214 +4602,214 @@ web-streams-polyfill@^3.0.3: resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== -web3-bzz@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.8.0.tgz#2023676d7c17ea36512bf76eb310755a02a3d464" - integrity sha512-caDtdKeLi7+2Vb+y+cq2yyhkNjnxkFzVW0j1DtemarBg3dycG1iEl75CVQMLNO6Wkg+HH9tZtRnUyFIe5LIUeQ== +web3-bzz@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.8.1.tgz#81397be5ce262d03d82b92e9d8acc11f8a609ea1" + integrity sha512-dJJHS84nvpoxv6ijTMkdUSlRr5beCXNtx4UZcrFLHBva8dT63QEtKdLyDt2AyMJJdVzTCk78uir/6XtVWrdS6w== dependencies: "@types/node" "^12.12.6" got "12.1.0" swarm-js "^0.1.40" -web3-core-helpers@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.8.0.tgz#5dcfdda1a4ea277041d912003198f1334ca29d7c" - integrity sha512-nMAVwZB3rEp/khHI2BvFy0e/xCryf501p5NGjswmJtEM+Zrd3Biaw52JrB1qAZZIzCA8cmLKaOgdfamoDOpWdw== +web3-core-helpers@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.8.1.tgz#7904747b23fd0afa4f2c86ed98ea9418ccad7672" + integrity sha512-ClzNO6T1S1gifC+BThw0+GTfcsjLEY8T1qUp6Ly2+w4PntAdNtKahxWKApWJ0l9idqot/fFIDXwO3Euu7I0Xqw== dependencies: - web3-eth-iban "1.8.0" - web3-utils "1.8.0" + web3-eth-iban "1.8.1" + web3-utils "1.8.1" -web3-core-method@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.8.0.tgz#9c2da8896808917d1679c319f19e2174ba17086c" - integrity sha512-c94RAzo3gpXwf2rf8rL8C77jOzNWF4mXUoUfZYYsiY35cJFd46jQDPI00CB5+ZbICTiA5mlVzMj4e7jAsTqiLA== +web3-core-method@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.8.1.tgz#0fc5a433a9fc784c447522f141c0a8e0163c7790" + integrity sha512-oYGRodktfs86NrnFwaWTbv2S38JnpPslFwSSARwFv4W9cjbGUW3LDeA5MKD/dRY+ssZ5OaekeMsUCLoGhX68yA== dependencies: "@ethersproject/transactions" "^5.6.2" - web3-core-helpers "1.8.0" - web3-core-promievent "1.8.0" - web3-core-subscriptions "1.8.0" - web3-utils "1.8.0" + web3-core-helpers "1.8.1" + web3-core-promievent "1.8.1" + web3-core-subscriptions "1.8.1" + web3-utils "1.8.1" -web3-core-promievent@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.8.0.tgz#979765fd4d37ab0f158f0ee54037b279b737bd53" - integrity sha512-FGLyjAuOaAQ+ZhV6iuw9tg/9WvIkSZXKHQ4mdTyQ8MxVraOtFivOCbuLLsGgapfHYX+RPxsc1j1YzQjKoupagQ== +web3-core-promievent@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.8.1.tgz#f334c8b2ceac6c2228f06d2a515f6d103157f036" + integrity sha512-9mxqHlgB0MrZI4oUIRFkuoJMNj3E7btjrMv3sMer/Z9rYR1PfoSc1aAokw4rxKIcAh+ylVtd/acaB2HKB7aRPg== dependencies: eventemitter3 "4.0.4" -web3-core-requestmanager@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.8.0.tgz#06189df80cf52d24a195a7ef655031afe8192df3" - integrity sha512-2AoYCs3Owl5foWcf4uKPONyqFygSl9T54L8b581U16nsUirjhoTUGK/PBhMDVcLCmW4QQmcY5A8oPFpkQc1TTg== +web3-core-requestmanager@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.8.1.tgz#272ffa55b7b568ecbc8e4a257ca080355c31c60e" + integrity sha512-x+VC2YPPwZ1khvqA6TA69LvfFCOZXsoUVOxmTx/vIN22PrY9KzKhxcE7pBSiGhmab1jtmRYXUbcQSVpAXqL8cw== dependencies: util "^0.12.0" - web3-core-helpers "1.8.0" - web3-providers-http "1.8.0" - web3-providers-ipc "1.8.0" - web3-providers-ws "1.8.0" + web3-core-helpers "1.8.1" + web3-providers-http "1.8.1" + web3-providers-ipc "1.8.1" + web3-providers-ws "1.8.1" -web3-core-subscriptions@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.8.0.tgz#ff66ae4467c8cb4716367248bcefb1845c0f8b83" - integrity sha512-7lHVRzDdg0+Gcog55lG6Q3D8JV+jN+4Ly6F8cSn9xFUAwOkdbgdWsjknQG7t7CDWy21DQkvdiY2BJF8S68AqOA== +web3-core-subscriptions@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.8.1.tgz#f5ae1380e92746eadfab6475b8a70ef5a1be6bbf" + integrity sha512-bmCMq5OeA3E2vZUh8Js1HcJbhwtsE+yeMqGC4oIZB3XsL5SLqyKLB/pU+qUYqQ9o4GdcrFTDPhPg1bgvf7p1Pw== dependencies: eventemitter3 "4.0.4" - web3-core-helpers "1.8.0" + web3-core-helpers "1.8.1" -web3-core@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.8.0.tgz#90afce527ac1b1dff8cbed2acbc0336530b8aacf" - integrity sha512-9sCA+Z02ci6zoY2bAquFiDjujRwmSKHiSGi4B8IstML8okSytnzXk1izHYSynE7ahIkguhjWAuXFvX76F5rAbA== +web3-core@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.8.1.tgz#050b1c408d1f9b7ae539e90f7f7d1b7a7d10578b" + integrity sha512-LbRZlJH2N6nS3n3Eo9Y++25IvzMY7WvYnp4NM/Ajhh97dAdglYs6rToQ2DbL2RLvTYmTew4O/y9WmOk4nq9COw== dependencies: "@types/bn.js" "^5.1.0" "@types/node" "^12.12.6" bignumber.js "^9.0.0" - web3-core-helpers "1.8.0" - web3-core-method "1.8.0" - web3-core-requestmanager "1.8.0" - web3-utils "1.8.0" + web3-core-helpers "1.8.1" + web3-core-method "1.8.1" + web3-core-requestmanager "1.8.1" + web3-utils "1.8.1" -web3-eth-abi@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.8.0.tgz#47fdff00bfdfa72064c9c612ff6369986598196d" - integrity sha512-xPeMb2hS9YLQK/Q5YZpkcmzoRGM+/R8bogSrYHhNC3hjZSSU0YRH+1ZKK0f9YF4qDZaPMI8tKWIMSCDIpjG6fg== +web3-eth-abi@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.8.1.tgz#47455d6513217c4b0866fea6f97b1c4afa0b6535" + integrity sha512-0mZvCRTIG0UhDhJwNQJgJxu4b4DyIpuMA0GTfqxqeuqzX4Q/ZvmoNurw0ExTfXaGPP82UUmmdkRi6FdZOx+C6w== dependencies: "@ethersproject/abi" "^5.6.3" - web3-utils "1.8.0" + web3-utils "1.8.1" -web3-eth-accounts@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.8.0.tgz#960d947ee87a49d6c706dc6312334fbfbd6ff812" - integrity sha512-HQ/MDSv4bexwJLvnqsM6xpGE7c2NVOqyhzOZFyMUKXbIwIq85T3TaLnM9pCN7XqMpDcfxqiZ3q43JqQVkzHdmw== +web3-eth-accounts@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.8.1.tgz#1ce7387721f118aeb0376291e4d8bbe2ac323406" + integrity sha512-mgzxSYgN54/NsOFBO1Fq1KkXp1S5KlBvI/DlgvajU72rupoFMq6Cu6Yp9GUaZ/w2ij9PzEJuFJk174XwtfMCmg== dependencies: - "@ethereumjs/common" "^2.5.0" - "@ethereumjs/tx" "^3.3.2" + "@ethereumjs/common" "2.5.0" + "@ethereumjs/tx" "3.3.2" crypto-browserify "3.12.0" eth-lib "0.2.8" ethereumjs-util "^7.0.10" scrypt-js "^3.0.1" - uuid "3.3.2" - web3-core "1.8.0" - web3-core-helpers "1.8.0" - web3-core-method "1.8.0" - web3-utils "1.8.0" + uuid "^9.0.0" + web3-core "1.8.1" + web3-core-helpers "1.8.1" + web3-core-method "1.8.1" + web3-utils "1.8.1" -web3-eth-contract@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.8.0.tgz#58f4ce0bde74e5ce87663502e409a92abad7b2c5" - integrity sha512-6xeXhW2YoCrz2Ayf2Vm4srWiMOB6LawkvxWJDnUWJ8SMATg4Pgu42C/j8rz/enXbYWt2IKuj0kk8+QszxQbK+Q== +web3-eth-contract@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.8.1.tgz#bdf3e33bbcb79a1b6144dffd6a0deefd2e459272" + integrity sha512-1wphnl+/xwCE2io44JKnN+ti3oa47BKRiVzvWd42icwRbcpFfRxH9QH+aQX3u8VZIISNH7dAkTWpGIIJgGFTmg== dependencies: "@types/bn.js" "^5.1.0" - web3-core "1.8.0" - web3-core-helpers "1.8.0" - web3-core-method "1.8.0" - web3-core-promievent "1.8.0" - web3-core-subscriptions "1.8.0" - web3-eth-abi "1.8.0" - web3-utils "1.8.0" - -web3-eth-ens@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.8.0.tgz#f1937371eac54b087ebe2e871780c2710d39998d" - integrity sha512-/eFbQEwvsMOEiOhw9/iuRXCsPkqAmHHWuFOrThQkozRgcnSTRnvxkkRC/b6koiT5/HaKeUs4yQDg+/ixsIxZxA== + web3-core "1.8.1" + web3-core-helpers "1.8.1" + web3-core-method "1.8.1" + web3-core-promievent "1.8.1" + web3-core-subscriptions "1.8.1" + web3-eth-abi "1.8.1" + web3-utils "1.8.1" + +web3-eth-ens@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.8.1.tgz#e78a9651fea8282abe8565b001819e2d645e5929" + integrity sha512-FT8xTI9uN8RxeBQa/W8pLa2aoFh4+EE34w7W2271LICKzla1dtLyb6XSdn48vsUcPmhWsTVk9mO9RTU0l4LGQQ== dependencies: content-hash "^2.5.2" eth-ens-namehash "2.0.8" - web3-core "1.8.0" - web3-core-helpers "1.8.0" - web3-core-promievent "1.8.0" - web3-eth-abi "1.8.0" - web3-eth-contract "1.8.0" - web3-utils "1.8.0" - -web3-eth-iban@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.8.0.tgz#3af8a0c95b5f7b0b81ab0bcd2075c1e5dda31520" - integrity sha512-4RbvUxcMpo/e5811sE3a6inJ2H4+FFqUVmlRYs0RaXaxiHweahSRBNcpO0UWgmlePTolj0rXqPT2oEr0DuC8kg== + web3-core "1.8.1" + web3-core-helpers "1.8.1" + web3-core-promievent "1.8.1" + web3-eth-abi "1.8.1" + web3-eth-contract "1.8.1" + web3-utils "1.8.1" + +web3-eth-iban@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.8.1.tgz#c6484e5d68ca644aa78431301e7acd5df24598d1" + integrity sha512-DomoQBfvIdtM08RyMGkMVBOH0vpOIxSSQ+jukWk/EkMLGMWJtXw/K2c2uHAeq3L/VPWNB7zXV2DUEGV/lNE2Dg== dependencies: bn.js "^5.2.1" - web3-utils "1.8.0" + web3-utils "1.8.1" -web3-eth-personal@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.8.0.tgz#433c35e2e042844402a12d543c4126ea1494b478" - integrity sha512-L7FT4nR3HmsfZyIAhFpEctKkYGOjRC2h6iFKs9gnFCHZga8yLcYcGaYOBIoYtaKom99MuGBoosayWt/Twh7F5A== +web3-eth-personal@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.8.1.tgz#00b5ff1898b62044d25ed5fddd8486168d4827cf" + integrity sha512-myIYMvj7SDIoV9vE5BkVdon3pya1WinaXItugoii2VoTcQNPOtBxmYVH+XS5ErzCJlnxzphpQrkywyY64bbbCA== dependencies: "@types/node" "^12.12.6" - web3-core "1.8.0" - web3-core-helpers "1.8.0" - web3-core-method "1.8.0" - web3-net "1.8.0" - web3-utils "1.8.0" - -web3-eth@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.8.0.tgz#006974a5d5e30644d05814111f9e162a72e4a09c" - integrity sha512-hist52os3OT4TQFB/GxPSMxTh3995sz6LPvQpPvj7ktSbpg9RNSFaSsPlCT63wUAHA3PZb1FemkAIeQM5t72Lw== - dependencies: - web3-core "1.8.0" - web3-core-helpers "1.8.0" - web3-core-method "1.8.0" - web3-core-subscriptions "1.8.0" - web3-eth-abi "1.8.0" - web3-eth-accounts "1.8.0" - web3-eth-contract "1.8.0" - web3-eth-ens "1.8.0" - web3-eth-iban "1.8.0" - web3-eth-personal "1.8.0" - web3-net "1.8.0" - web3-utils "1.8.0" - -web3-net@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.8.0.tgz#9acff92d7c647d801bc68df0ff4416f104dbe789" - integrity sha512-kX6EAacK7QrOe7DOh0t5yHS5q2kxZmTCxPVwSz9io9xBeE4n4UhmzGJ/VfhP2eM3OPKYeypcR3LEO6zZ8xn2vw== - dependencies: - web3-core "1.8.0" - web3-core-method "1.8.0" - web3-utils "1.8.0" - -web3-providers-http@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.8.0.tgz#3fd1e569ead2095343fac17d53160a3bae674c23" - integrity sha512-/MqxwRzExohBWW97mqlCSW/+NHydGRyoEDUS1bAIF2YjfKFwyRtHgrEzOojzkC9JvB+8LofMvbXk9CcltpZapw== + web3-core "1.8.1" + web3-core-helpers "1.8.1" + web3-core-method "1.8.1" + web3-net "1.8.1" + web3-utils "1.8.1" + +web3-eth@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.8.1.tgz#395f6cd56edaac5dbb23e8cec9886c3fd32c430e" + integrity sha512-LgyzbhFqiFRd8M8sBXoFN4ztzOnkeckl3H/9lH5ek7AdoRMhBg7tYpYRP3E5qkhd/q+yiZmcUgy1AF6NHrC1wg== + dependencies: + web3-core "1.8.1" + web3-core-helpers "1.8.1" + web3-core-method "1.8.1" + web3-core-subscriptions "1.8.1" + web3-eth-abi "1.8.1" + web3-eth-accounts "1.8.1" + web3-eth-contract "1.8.1" + web3-eth-ens "1.8.1" + web3-eth-iban "1.8.1" + web3-eth-personal "1.8.1" + web3-net "1.8.1" + web3-utils "1.8.1" + +web3-net@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.8.1.tgz#2bed4d4b93166724129ec33d0e5dea98880285f4" + integrity sha512-LyEJAwogdFo0UAXZqoSJGFjopdt+kLw0P00FSZn2yszbgcoI7EwC+nXiOsEe12xz4LqpYLOtbR7+gxgiTVjjHQ== + dependencies: + web3-core "1.8.1" + web3-core-method "1.8.1" + web3-utils "1.8.1" + +web3-providers-http@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.8.1.tgz#8aa89c11a9272f11ddb74b871273c92225faa28d" + integrity sha512-1Zyts4O9W/UNEPkp+jyL19Jc3D15S4yp8xuLTjVhcUEAlHo24NDWEKxtZGUuHk4HrKL2gp8OlsDbJ7MM+ESDgg== dependencies: abortcontroller-polyfill "^1.7.3" cross-fetch "^3.1.4" es6-promise "^4.2.8" - web3-core-helpers "1.8.0" + web3-core-helpers "1.8.1" -web3-providers-ipc@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.8.0.tgz#d339a24c4d764e459e425d3ac868a551ac33e3ea" - integrity sha512-tAXHtVXNUOgehaBU8pzAlB3qhjn/PRpjdzEjzHNFqtRRTwzSEKOJxFeEhaUA4FzHnTlbnrs8ujHWUitcp1elfg== +web3-providers-ipc@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.8.1.tgz#6128a3a3a824d06bf0efcfe86325401f8691a5ca" + integrity sha512-nw/W5nclvi+P2z2dYkLWReKLnocStflWqFl+qjtv0xn3MrUTyXMzSF0+61i77+16xFsTgzo4wS/NWIOVkR0EFA== dependencies: oboe "2.1.5" - web3-core-helpers "1.8.0" + web3-core-helpers "1.8.1" -web3-providers-ws@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.8.0.tgz#a0a73e0606981ea32bed40d215000a64753899de" - integrity sha512-bcZtSifsqyJxwkfQYamfdIRp4nhj9eJd7cxHg1uUkfLJK125WP96wyJL1xbPt7qt0MpfnTFn8/UuIqIB6nFENg== +web3-providers-ws@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.8.1.tgz#5e5370e07eb8c615ed298ebc8602b283c7b7d649" + integrity sha512-TNefIDAMpdx57+YdWpYZ/xdofS0P+FfKaDYXhn24ie/tH9G+AB+UBSOKnjN0KSadcRSCMBwGPRiEmNHPavZdsA== dependencies: eventemitter3 "4.0.4" - web3-core-helpers "1.8.0" + web3-core-helpers "1.8.1" websocket "^1.0.32" -web3-shh@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.8.0.tgz#b4abbf4f59d097ce2f74360e61e2e5c0bd6507c7" - integrity sha512-DNRgSa9Jf9xYFUGKSMylrf+zt3MPjhI2qF+UWX07o0y3+uf8zalDGiJOWvIS4upAsdPiKKVJ7co+Neof47OMmg== +web3-shh@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.8.1.tgz#028a95cf9d3a36020380938b9a127610efbb9be7" + integrity sha512-sqHgarnfcY2Qt3PYS4R6YveHrDy7hmL09yeLLHHCI+RKirmjLVqV0rc5LJWUtlbYI+kDoa5gbgde489M9ZAC0g== dependencies: - web3-core "1.8.0" - web3-core-method "1.8.0" - web3-core-subscriptions "1.8.0" - web3-net "1.8.0" + web3-core "1.8.1" + web3-core-method "1.8.1" + web3-core-subscriptions "1.8.1" + web3-net "1.8.1" -web3-utils@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.8.0.tgz#0a506f8c6af9a2ad6ba79689892662769534fc03" - integrity sha512-7nUIl7UWpLVka2f09CMbKOSEvorvHnaugIabU4mj7zfMvm0tSByLcEu3eyV9qgS11qxxLuOkzBIwCstTflhmpQ== +web3-utils@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.8.1.tgz#f2f7ca7eb65e6feb9f3d61056d0de6bbd57125ff" + integrity sha512-LgnM9p6V7rHHUGfpMZod+NST8cRfGzJ1BTXAyNo7A9cJX9LczBfSRxJp+U/GInYe9mby40t3v22AJdlELibnsQ== dependencies: bn.js "^5.2.1" ethereum-bloom-filters "^1.0.6" @@ -4989,18 +4819,18 @@ web3-utils@1.8.0: randombytes "^2.1.0" utf8 "3.0.0" -web3@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/web3/-/web3-1.8.0.tgz#3ca5f0b32de6a1f626407740411219035b5fde64" - integrity sha512-sldr9stK/SALSJTgI/8qpnDuBJNMGjVR84hJ+AcdQ+MLBGLMGsCDNubCoyO6qgk1/Y9SQ7ignegOI/7BPLoiDA== +web3@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.8.1.tgz#8ea67215ef5f3a6f6d3381800b527242ea22885a" + integrity sha512-tAqFsQhGv340C9OgRJIuoScN7f7wa1tUvsnnDUMt9YE6J4gcm7TV2Uwv+KERnzvV+xgdeuULYpsioRRNKrUvoQ== dependencies: - web3-bzz "1.8.0" - web3-core "1.8.0" - web3-eth "1.8.0" - web3-eth-personal "1.8.0" - web3-net "1.8.0" - web3-shh "1.8.0" - web3-utils "1.8.0" + web3-bzz "1.8.1" + web3-core "1.8.1" + web3-eth "1.8.1" + web3-eth-personal "1.8.1" + web3-net "1.8.1" + web3-shh "1.8.1" + web3-utils "1.8.1" webidl-conversions@^3.0.0: version "3.0.1" @@ -5027,28 +4857,17 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - which-typed-array@^1.1.2: - version "1.1.8" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.8.tgz#0cfd53401a6f334d90ed1125754a42ed663eb01f" - integrity sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw== + version "1.1.9" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" + integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== dependencies: available-typed-arrays "^1.0.5" call-bind "^1.0.2" - es-abstract "^1.20.0" for-each "^0.3.3" + gopd "^1.0.1" has-tostringtag "^1.0.0" - is-typed-array "^1.1.9" + is-typed-array "^1.1.10" which@^2.0.1: version "2.0.2" @@ -5096,9 +4915,9 @@ ws@^3.0.0: ultron "~1.1.0" ws@^8.8.1: - version "8.9.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.9.0.tgz#2a994bb67144be1b53fe2d23c53c028adeb7f45e" - integrity sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg== + version "8.11.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" + integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== xhr-request-promise@^0.1.2: version "0.1.3" @@ -5145,7 +4964,7 @@ yaeti@^0.0.6: resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug== -yallist@^3.0.0, yallist@^3.1.1: +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== @@ -5165,7 +4984,7 @@ yargs-parser@^20.2.2: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-parser@^21.0.0: +yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== @@ -5193,10 +5012,10 @@ yargs@16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.6.0: - version "17.6.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.0.tgz#e134900fc1f218bc230192bdec06a0a5f973e46c" - integrity sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g== +yargs@^17.6.2: + version "17.6.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.2.tgz#2e23f2944e976339a1ee00f18c77fedee8332541" + integrity sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw== dependencies: cliui "^8.0.1" escalade "^3.1.1" @@ -5204,7 +5023,7 @@ yargs@^17.6.0: require-directory "^2.1.1" string-width "^4.2.3" y18n "^5.0.5" - yargs-parser "^21.0.0" + yargs-parser "^21.1.1" yn@3.1.1: version "3.1.1"