git.delta.rocks / unique-network / refs/commits / 5b368f35ddd7

difftreelog

Merge branch 'develop' into feature/types-repo

Igor Kozyrev2021-12-02parents: #cc72678 #767e0d8.patch.diff
in: master

102 files changed

modified.devcontainer/Dockerfilediffbeforeafterboth
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -13,8 +13,8 @@
     [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && \
     nvm install v16.2.0 && \
     npm install -g yarn && \
-    rustup toolchain install nightly-2021-06-28 && \
-    rustup default nightly-2021-06-28 && \
+    rustup toolchain install nightly-2021-11-11 && \
+    rustup default nightly-2021-11-11 && \
     rustup target add wasm32-unknown-unknown && \
     rustup component add rustfmt clippy && \
     cargo install cargo-expand cargo-edit cargo-contract
modified.envdiffbeforeafterboth
--- a/.env
+++ b/.env
@@ -1,4 +1,4 @@
-RUST_TOOLCHAIN=nightly-2021-06-28
+RUST_TOOLCHAIN=nightly-2021-11-11
 RUST_C=1.55.0-nightly
 POLKA_VERSION=v0.9.12
 UNIQUE_BRANCH=develop
modified.maintain/frame-weight-template.hbsdiffbeforeafterboth
--- a/.maintain/frame-weight-template.hbs
+++ b/.maintain/frame-weight-template.hbs
@@ -14,6 +14,7 @@
 #![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;
modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -117,9 +117,9 @@
 
 [[package]]
 name = "anyhow"
-version = "1.0.44"
+version = "1.0.48"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
+checksum = "62e1f47f7dc0422027a4e370dd4548d4d66b26782e513e98dca1e689e058a80e"
 
 [[package]]
 name = "approx"
@@ -259,9 +259,9 @@
 
 [[package]]
 name = "async-process"
-version = "1.2.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b21b63ab5a0db0369deb913540af2892750e42d949faacc7a61495ac418a1692"
+checksum = "83137067e3a2a6a06d67168e49e68a0957d215410473a740cea95a2425c0b7c6"
 dependencies = [
  "async-io",
  "blocking",
@@ -362,9 +362,9 @@
 
 [[package]]
 name = "atomic"
-version = "0.5.0"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3410529e8288c463bedb5930f82833bc0c90e5d2fe639a56582a4d09220b281"
+checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c"
 dependencies = [
  "autocfg",
 ]
@@ -460,7 +460,7 @@
 dependencies = [
  "beefy-primitives",
  "fnv",
- "futures 0.3.17",
+ "futures 0.3.18",
  "log",
  "parity-scale-codec",
  "parking_lot 0.11.2",
@@ -488,7 +488,7 @@
 dependencies = [
  "beefy-gadget",
  "beefy-primitives",
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpc-core",
  "jsonrpc-core-client",
  "jsonrpc-derive",
@@ -531,9 +531,9 @@
 
 [[package]]
 name = "bindgen"
-version = "0.59.1"
+version = "0.59.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "453c49e5950bb0eb63bb3df640e31618846c89d5b7faa54040d76e98e0134375"
+checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8"
 dependencies = [
  "bitflags",
  "cexpr",
@@ -556,24 +556,12 @@
 
 [[package]]
 name = "bitvec"
-version = "0.19.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321"
-dependencies = [
- "funty",
- "radium 0.5.3",
- "tap",
- "wyz",
-]
-
-[[package]]
-name = "bitvec"
 version = "0.20.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848"
 dependencies = [
  "funty",
- "radium 0.6.2",
+ "radium",
  "tap",
  "wyz",
 ]
@@ -675,9 +663,9 @@
 
 [[package]]
 name = "blocking"
-version = "1.0.2"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9"
+checksum = "046e47d4b2d391b1f6f8b407b1deb8dee56c1852ccd868becf2710f601b5f427"
 dependencies = [
  "async-channel",
  "async-task",
@@ -729,11 +717,11 @@
 version = "0.1.0"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "bitvec 0.20.4",
+ "bitvec",
  "bp-runtime",
  "frame-support",
  "frame-system",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "scale-info",
  "serde",
@@ -971,18 +959,18 @@
 
 [[package]]
 name = "cc"
-version = "1.0.71"
+version = "1.0.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd"
+checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
 dependencies = [
  "jobserver",
 ]
 
 [[package]]
 name = "cexpr"
-version = "0.5.0"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
 dependencies = [
  "nom",
 ]
@@ -1080,7 +1068,7 @@
 dependencies = [
  "glob",
  "libc",
- "libloading 0.7.1",
+ "libloading 0.7.2",
 ]
 
 [[package]]
@@ -1146,9 +1134,9 @@
 
 [[package]]
 name = "cpp_demangle"
-version = "0.3.3"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ea47428dc9d2237f3c6bc134472edfd63ebba0af932e783506dcfd66f10d18a"
+checksum = "931ab2a3e6330a07900b8e7ca4e106cdcbb93f2b9a52df55e54ee53d8305b55d"
 dependencies = [
  "cfg-if 1.0.0",
 ]
@@ -1263,9 +1251,9 @@
 
 [[package]]
 name = "crc32fast"
-version = "1.2.1"
+version = "1.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
+checksum = "3825b1e8580894917dc4468cb634a1b4e9745fddc854edad72d9c04644c0319f"
 dependencies = [
  "cfg-if 1.0.0",
 ]
@@ -1392,7 +1380,7 @@
 [[package]]
 name = "cumulus-client-cli"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "sc-cli",
  "sc-service",
@@ -1402,12 +1390,12 @@
 [[package]]
 name = "cumulus-client-collator"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "cumulus-client-consensus-common",
  "cumulus-client-network",
  "cumulus-primitives-core",
- "futures 0.3.17",
+ "futures 0.3.18",
  "parity-scale-codec",
  "parking_lot 0.10.2",
  "polkadot-node-primitives",
@@ -1425,12 +1413,12 @@
 [[package]]
 name = "cumulus-client-consensus-aura"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "async-trait",
  "cumulus-client-consensus-common",
  "cumulus-primitives-core",
- "futures 0.3.17",
+ "futures 0.3.18",
  "parity-scale-codec",
  "polkadot-client",
  "sc-client-api",
@@ -1455,11 +1443,11 @@
 [[package]]
 name = "cumulus-client-consensus-common"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "async-trait",
  "dyn-clone",
- "futures 0.3.17",
+ "futures 0.3.18",
  "parity-scale-codec",
  "polkadot-primitives",
  "sc-client-api",
@@ -1475,10 +1463,10 @@
 [[package]]
 name = "cumulus-client-network"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "parity-scale-codec",
  "parking_lot 0.10.2",
@@ -1498,10 +1486,10 @@
 [[package]]
 name = "cumulus-client-pov-recovery"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "cumulus-primitives-core",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "parity-scale-codec",
  "polkadot-node-primitives",
@@ -1521,7 +1509,7 @@
 [[package]]
 name = "cumulus-client-service"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "cumulus-client-collator",
  "cumulus-client-consensus-common",
@@ -1550,7 +1538,7 @@
 [[package]]
 name = "cumulus-pallet-aura-ext"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "frame-executive",
  "frame-support",
@@ -1568,7 +1556,7 @@
 [[package]]
 name = "cumulus-pallet-dmp-queue"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "cumulus-primitives-core",
  "frame-support",
@@ -1586,7 +1574,7 @@
 [[package]]
 name = "cumulus-pallet-parachain-system"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "cumulus-pallet-parachain-system-proc-macro",
  "cumulus-primitives-core",
@@ -1615,7 +1603,7 @@
 [[package]]
 name = "cumulus-pallet-parachain-system-proc-macro"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "proc-macro-crate 1.1.0",
  "proc-macro2",
@@ -1626,7 +1614,7 @@
 [[package]]
 name = "cumulus-pallet-xcm"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "cumulus-primitives-core",
  "frame-support",
@@ -1643,7 +1631,7 @@
 [[package]]
 name = "cumulus-pallet-xcmp-queue"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "cumulus-primitives-core",
  "frame-support",
@@ -1661,10 +1649,10 @@
 [[package]]
 name = "cumulus-primitives-core"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "frame-support",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "polkadot-core-primitives",
  "polkadot-parachain",
@@ -1678,7 +1666,7 @@
 [[package]]
 name = "cumulus-primitives-parachain-inherent"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "async-trait",
  "cumulus-primitives-core",
@@ -1700,7 +1688,7 @@
 [[package]]
 name = "cumulus-primitives-timestamp"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "cumulus-primitives-core",
  "sp-inherents",
@@ -1711,7 +1699,7 @@
 [[package]]
 name = "cumulus-primitives-utility"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "cumulus-primitives-core",
  "frame-support",
@@ -1728,7 +1716,7 @@
 [[package]]
 name = "cumulus-test-relay-sproof-builder"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "cumulus-primitives-core",
  "parity-scale-codec",
@@ -1953,9 +1941,9 @@
 
 [[package]]
 name = "ed25519"
-version = "1.2.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4620d40f6d2601794401d6dd95a5cf69b6c157852539470eeda433a99b3c0efc"
+checksum = "74e1069e39f1454367eb2de793ed062fac4c35c2934b76a81d90dd9abcd28816"
 dependencies = [
  "signature",
 ]
@@ -2111,8 +2099,9 @@
 
 [[package]]
 name = "ethereum"
-version = "0.9.0"
-source = "git+https://github.com/purestake/ethereum?branch=joshy-scale-info#2b98173bd88c05bfeefad421d260101b9008497b"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81fb916554a4dba293ea69c69ad5653e21d770a9d0c2496b5fa0a1f5a3946d87"
 dependencies = [
  "bytes 1.1.0",
  "ethereum-types",
@@ -2151,11 +2140,11 @@
 
 [[package]]
 name = "evm"
-version = "0.30.0"
-source = "git+https://github.com/uniquenetwork/evm.git?branch=precompile-output-parachain#bed08923a76339880e05df25a52c5334e9997bb2"
+version = "0.33.0"
+source = "git+https://github.com/uniquenetwork/evm.git?branch=unique-weights#3113ac1ced53bf27e9845107fd30901708824cc4"
 dependencies = [
  "environmental",
- "ethereum 0.9.0 (git+https://github.com/purestake/ethereum?branch=joshy-scale-info)",
+ "ethereum 0.10.0",
  "evm-core",
  "evm-gasometer",
  "evm-runtime",
@@ -2172,12 +2161,12 @@
 name = "evm-coder"
 version = "0.1.0"
 dependencies = [
- "ethereum 0.9.0 (git+https://github.com/purestake/ethereum?branch=joshy-scale-info)",
+ "ethereum 0.10.0",
  "evm-coder-macros",
  "evm-core",
  "hex",
  "hex-literal",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "primitive-types 0.10.1",
 ]
 
@@ -2196,8 +2185,8 @@
 
 [[package]]
 name = "evm-core"
-version = "0.30.0"
-source = "git+https://github.com/uniquenetwork/evm.git?branch=precompile-output-parachain#bed08923a76339880e05df25a52c5334e9997bb2"
+version = "0.33.0"
+source = "git+https://github.com/uniquenetwork/evm.git?branch=unique-weights#3113ac1ced53bf27e9845107fd30901708824cc4"
 dependencies = [
  "funty",
  "parity-scale-codec",
@@ -2208,8 +2197,8 @@
 
 [[package]]
 name = "evm-gasometer"
-version = "0.30.0"
-source = "git+https://github.com/uniquenetwork/evm.git?branch=precompile-output-parachain#bed08923a76339880e05df25a52c5334e9997bb2"
+version = "0.33.0"
+source = "git+https://github.com/uniquenetwork/evm.git?branch=unique-weights#3113ac1ced53bf27e9845107fd30901708824cc4"
 dependencies = [
  "environmental",
  "evm-core",
@@ -2219,8 +2208,8 @@
 
 [[package]]
 name = "evm-runtime"
-version = "0.30.0"
-source = "git+https://github.com/uniquenetwork/evm.git?branch=precompile-output-parachain#bed08923a76339880e05df25a52c5334e9997bb2"
+version = "0.33.0"
+source = "git+https://github.com/uniquenetwork/evm.git?branch=unique-weights#3113ac1ced53bf27e9845107fd30901708824cc4"
 dependencies = [
  "environmental",
  "evm-core",
@@ -2234,7 +2223,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
 ]
 
 [[package]]
@@ -2261,14 +2250,14 @@
 [[package]]
 name = "fc-consensus"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12#43ce3be6274eceaf47d9664ddc71cba68a990923"
+source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12-weights#0134806e399412bf896f881f1e3bc284916a1432"
 dependencies = [
  "async-trait",
  "derive_more",
  "fc-db",
  "fp-consensus",
  "fp-rpc",
- "futures 0.3.17",
+ "futures 0.3.18",
  "log",
  "parity-scale-codec",
  "sc-client-api",
@@ -2288,7 +2277,7 @@
 [[package]]
 name = "fc-db"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12#43ce3be6274eceaf47d9664ddc71cba68a990923"
+source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12-weights#0134806e399412bf896f881f1e3bc284916a1432"
 dependencies = [
  "fp-storage",
  "kvdb",
@@ -2304,13 +2293,13 @@
 [[package]]
 name = "fc-mapping-sync"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12#43ce3be6274eceaf47d9664ddc71cba68a990923"
+source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12-weights#0134806e399412bf896f881f1e3bc284916a1432"
 dependencies = [
  "fc-consensus",
  "fc-db",
  "fp-consensus",
  "fp-rpc",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "log",
  "sc-client-api",
@@ -2322,9 +2311,9 @@
 [[package]]
 name = "fc-rpc"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12#43ce3be6274eceaf47d9664ddc71cba68a990923"
+source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12-weights#0134806e399412bf896f881f1e3bc284916a1432"
 dependencies = [
- "ethereum 0.9.0 (git+https://github.com/purestake/ethereum?branch=joshy-scale-info)",
+ "ethereum 0.10.0",
  "ethereum-types",
  "evm",
  "fc-consensus",
@@ -2334,7 +2323,7 @@
  "fp-evm",
  "fp-rpc",
  "fp-storage",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-util",
  "jsonrpc-core",
  "jsonrpc-pubsub",
@@ -2366,7 +2355,7 @@
 [[package]]
 name = "fc-rpc-core"
 version = "1.1.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12#43ce3be6274eceaf47d9664ddc71cba68a990923"
+source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12-weights#0134806e399412bf896f881f1e3bc284916a1432"
 dependencies = [
  "ethereum-types",
  "jsonrpc-core",
@@ -2404,7 +2393,7 @@
 checksum = "e8ac3ff5224ef91f3c97e03eb1de2db82743427e91aaa5ac635f454f0b164f5a"
 dependencies = [
  "either",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "log",
  "num-traits",
@@ -2487,9 +2476,9 @@
 [[package]]
 name = "fp-consensus"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12#43ce3be6274eceaf47d9664ddc71cba68a990923"
+source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12-weights#0134806e399412bf896f881f1e3bc284916a1432"
 dependencies = [
- "ethereum 0.9.0 (git+https://github.com/purestake/ethereum?branch=joshy-scale-info)",
+ "ethereum 0.10.0",
  "parity-scale-codec",
  "rlp",
  "sha3 0.8.2",
@@ -2501,10 +2490,10 @@
 [[package]]
 name = "fp-evm"
 version = "3.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12#43ce3be6274eceaf47d9664ddc71cba68a990923"
+source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12-weights#0134806e399412bf896f881f1e3bc284916a1432"
 dependencies = [
  "evm",
- "impl-trait-for-tuples 0.1.3",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "scale-info",
  "serde",
@@ -2515,9 +2504,9 @@
 [[package]]
 name = "fp-rpc"
 version = "3.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12#43ce3be6274eceaf47d9664ddc71cba68a990923"
+source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12-weights#0134806e399412bf896f881f1e3bc284916a1432"
 dependencies = [
- "ethereum 0.9.0 (git+https://github.com/purestake/ethereum?branch=joshy-scale-info)",
+ "ethereum 0.10.0",
  "ethereum-types",
  "fp-evm",
  "parity-scale-codec",
@@ -2532,9 +2521,9 @@
 [[package]]
 name = "fp-self-contained"
 version = "1.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12#43ce3be6274eceaf47d9664ddc71cba68a990923"
+source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12-weights#0134806e399412bf896f881f1e3bc284916a1432"
 dependencies = [
- "ethereum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ethereum 0.9.0",
  "frame-support",
  "parity-scale-codec",
  "parity-util-mem",
@@ -2549,7 +2538,7 @@
 [[package]]
 name = "fp-storage"
 version = "2.0.0"
-source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12#43ce3be6274eceaf47d9664ddc71cba68a990923"
+source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12-weights#0134806e399412bf896f881f1e3bc284916a1432"
 
 [[package]]
 name = "frame-benchmarking"
@@ -2629,9 +2618,9 @@
 
 [[package]]
 name = "frame-metadata"
-version = "14.0.0"
+version = "14.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96616f82e069102b95a72c87de4c84d2f87ef7f0f20630e78ce3824436483110"
+checksum = "37ed5e5c346de62ca5c184b4325a6600d1eaca210666e4606fe4e449574978d0"
 dependencies = [
  "cfg-if 1.0.0",
  "parity-scale-codec",
@@ -2647,7 +2636,7 @@
  "bitflags",
  "frame-metadata",
  "frame-support-procedural",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "log",
  "once_cell",
  "parity-scale-codec",
@@ -2810,9 +2799,9 @@
 
 [[package]]
 name = "futures"
-version = "0.3.17"
+version = "0.3.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca"
+checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -2825,9 +2814,9 @@
 
 [[package]]
 name = "futures-channel"
-version = "0.3.17"
+version = "0.3.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
+checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -2835,15 +2824,15 @@
 
 [[package]]
 name = "futures-core"
-version = "0.3.17"
+version = "0.3.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
+checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.17"
+version = "0.3.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c"
+checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -2853,9 +2842,9 @@
 
 [[package]]
 name = "futures-io"
-version = "0.3.17"
+version = "0.3.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377"
+checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11"
 
 [[package]]
 name = "futures-lite"
@@ -2874,12 +2863,10 @@
 
 [[package]]
 name = "futures-macro"
-version = "0.3.17"
+version = "0.3.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb"
+checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd"
 dependencies = [
- "autocfg",
- "proc-macro-hack",
  "proc-macro2",
  "quote",
  "syn",
@@ -2898,15 +2885,15 @@
 
 [[package]]
 name = "futures-sink"
-version = "0.3.17"
+version = "0.3.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11"
+checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af"
 
 [[package]]
 name = "futures-task"
-version = "0.3.17"
+version = "0.3.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
+checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12"
 
 [[package]]
 name = "futures-timer"
@@ -2922,11 +2909,10 @@
 
 [[package]]
 name = "futures-util"
-version = "0.3.17"
+version = "0.3.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
+checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e"
 dependencies = [
- "autocfg",
  "futures 0.1.31",
  "futures-channel",
  "futures-core",
@@ -2937,8 +2923,6 @@
  "memchr",
  "pin-project-lite 0.2.7",
  "pin-utils",
- "proc-macro-hack",
- "proc-macro-nested",
  "slab",
 ]
 
@@ -3108,9 +3092,9 @@
 
 [[package]]
 name = "hex-literal"
-version = "0.3.3"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b"
+checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0"
 
 [[package]]
 name = "hex_fmt"
@@ -3211,9 +3195,9 @@
 
 [[package]]
 name = "httpdate"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440"
+checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
 
 [[package]]
 name = "humantime"
@@ -3232,9 +3216,9 @@
 
 [[package]]
 name = "hyper"
-version = "0.14.14"
+version = "0.14.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b91bb1f221b6ea1f1e4371216b70f40748774c2fb5971b450c07773fb92d26b"
+checksum = "436ec0091e4f20e655156a30a0df3770fe2900aa301e548e08446ec794b6953c"
 dependencies = [
  "bytes 1.1.0",
  "futures-channel",
@@ -3247,7 +3231,7 @@
  "itoa",
  "pin-project-lite 0.2.7",
  "socket2 0.4.2",
- "tokio 1.13.0",
+ "tokio 1.14.0",
  "tower-service",
  "tracing",
  "want",
@@ -3265,7 +3249,7 @@
  "log",
  "rustls",
  "rustls-native-certs",
- "tokio 1.13.0",
+ "tokio 1.14.0",
  "tokio-rustls",
  "webpki",
 ]
@@ -3300,9 +3284,9 @@
 
 [[package]]
 name = "if-addrs"
-version = "0.6.6"
+version = "0.6.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9a83ec4af652890ac713ffd8dc859e650420a5ef47f7b9be29b6664ab50fbc8"
+checksum = "2273e421f7c4f0fc99e1934fe4776f59d8df2972f4199d703fc0da9f2a9f73de"
 dependencies = [
  "if-addrs-sys",
  "libc",
@@ -3326,7 +3310,7 @@
 checksum = "ae8ab7f67bad3240049cb24fb9cb0b4c2c6af4c245840917fbbdededeee91179"
 dependencies = [
  "async-io",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-lite",
  "if-addrs",
  "ipnet",
@@ -3355,22 +3339,11 @@
 
 [[package]]
 name = "impl-serde"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b47ca4d2b6931707a55fce5cf66aff80e2178c8b63bbb4ecb5695cbc870ddf6f"
+checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c"
 dependencies = [
  "serde",
-]
-
-[[package]]
-name = "impl-trait-for-tuples"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ef5550a42e3740a0e71f909d4c861056a284060af885ae7aa6242820f920d9d"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
 ]
 
 [[package]]
@@ -3425,7 +3398,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "64fa110ec7b8f493f416eed552740d10e7030ad5f63b2308f82c9608ec2df275"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 2.0.2",
 ]
 
@@ -3440,9 +3413,9 @@
 
 [[package]]
 name = "ip_network"
-version = "0.4.0"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09b746553d2f4a1ca26fab939943ddfb217a091f34f53571620a8e3d30691303"
+checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1"
 
 [[package]]
 name = "ipconfig"
@@ -3502,7 +3475,7 @@
 checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a"
 dependencies = [
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpc-core",
  "jsonrpc-pubsub",
  "log",
@@ -3517,7 +3490,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-executor",
  "futures-util",
  "log",
@@ -3532,7 +3505,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpc-client-transports",
 ]
 
@@ -3554,7 +3527,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "hyper",
  "jsonrpc-core",
  "jsonrpc-server-utils",
@@ -3570,7 +3543,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "382bb0206323ca7cda3dcd7e245cea86d37d02457a02a975e3378fb149a48845"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpc-core",
  "jsonrpc-server-utils",
  "log",
@@ -3585,7 +3558,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpc-core",
  "lazy_static",
  "log",
@@ -3601,12 +3574,12 @@
 checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4"
 dependencies = [
  "bytes 1.1.0",
- "futures 0.3.17",
+ "futures 0.3.18",
  "globset",
  "jsonrpc-core",
  "lazy_static",
  "log",
- "tokio 1.13.0",
+ "tokio 1.14.0",
  "tokio-stream",
  "tokio-util",
  "unicase",
@@ -3618,7 +3591,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f892c7d766369475ab7b0669f417906302d7c0fb521285c0a0c92e52e7c8e946"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpc-core",
  "jsonrpc-server-utils",
  "log",
@@ -3667,7 +3640,7 @@
 dependencies = [
  "async-trait",
  "fnv",
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpsee-types",
  "log",
  "pin-project 1.0.8",
@@ -3677,7 +3650,7 @@
  "serde_json",
  "soketto 0.6.0",
  "thiserror",
- "tokio 1.13.0",
+ "tokio 1.14.0",
  "tokio-rustls",
  "tokio-util",
  "url 2.2.2",
@@ -3705,7 +3678,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "beefy-primitives",
- "bitvec 0.20.4",
+ "bitvec",
  "frame-benchmarking",
  "frame-election-provider-support",
  "frame-executive",
@@ -3847,9 +3820,9 @@
 
 [[package]]
 name = "libc"
-version = "0.2.106"
+version = "0.2.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673"
+checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
 
 [[package]]
 name = "libloading"
@@ -3863,9 +3836,9 @@
 
 [[package]]
 name = "libloading"
-version = "0.7.1"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0cf036d15402bea3c5d4de17b3fce76b3e4a56ebc1f577be0e7a72f7c607cf0"
+checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52"
 dependencies = [
  "cfg-if 1.0.0",
  "winapi 0.3.9",
@@ -3885,7 +3858,7 @@
 dependencies = [
  "atomic",
  "bytes 1.1.0",
- "futures 0.3.17",
+ "futures 0.3.18",
  "lazy_static",
  "libp2p-core",
  "libp2p-deflate",
@@ -3927,7 +3900,7 @@
  "ed25519-dalek",
  "either",
  "fnv",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "lazy_static",
  "libsecp256k1 0.5.0",
@@ -3945,7 +3918,7 @@
  "sha2 0.9.8",
  "smallvec",
  "thiserror",
- "unsigned-varint 0.7.0",
+ "unsigned-varint 0.7.1",
  "void",
  "zeroize",
 ]
@@ -3957,7 +3930,7 @@
 checksum = "66097fccc0b7f8579f90a03ea76ba6196332ea049fd07fd969490a06819dcdc8"
 dependencies = [
  "flate2",
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p-core",
 ]
 
@@ -3968,7 +3941,7 @@
 checksum = "58ff08b3196b85a17f202d80589e93b1660a574af67275706657fdc762e42c32"
 dependencies = [
  "async-std-resolver",
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p-core",
  "log",
  "smallvec",
@@ -3983,7 +3956,7 @@
 dependencies = [
  "cuckoofilter",
  "fnv",
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p-core",
  "libp2p-swarm",
  "log",
@@ -4004,7 +3977,7 @@
  "byteorder",
  "bytes 1.1.0",
  "fnv",
- "futures 0.3.17",
+ "futures 0.3.18",
  "hex_fmt",
  "libp2p-core",
  "libp2p-swarm",
@@ -4015,7 +3988,7 @@
  "regex",
  "sha2 0.9.8",
  "smallvec",
- "unsigned-varint 0.7.0",
+ "unsigned-varint 0.7.1",
  "wasm-timer",
 ]
 
@@ -4025,7 +3998,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a7b61f6cf07664fb97016c318c4d4512b3dd4cc07238607f3f0163245f99008e"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p-core",
  "libp2p-swarm",
  "log",
@@ -4046,7 +4019,7 @@
  "bytes 1.1.0",
  "either",
  "fnv",
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p-core",
  "libp2p-swarm",
  "log",
@@ -4056,7 +4029,7 @@
  "sha2 0.9.8",
  "smallvec",
  "uint",
- "unsigned-varint 0.7.0",
+ "unsigned-varint 0.7.1",
  "void",
  "wasm-timer",
 ]
@@ -4070,7 +4043,7 @@
  "async-io",
  "data-encoding",
  "dns-parser",
- "futures 0.3.17",
+ "futures 0.3.18",
  "if-watch",
  "lazy_static",
  "libp2p-core",
@@ -4090,14 +4063,14 @@
 dependencies = [
  "asynchronous-codec 0.6.0",
  "bytes 1.1.0",
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p-core",
  "log",
  "nohash-hasher",
  "parking_lot 0.11.2",
  "rand 0.7.3",
  "smallvec",
- "unsigned-varint 0.7.0",
+ "unsigned-varint 0.7.1",
 ]
 
 [[package]]
@@ -4108,7 +4081,7 @@
 dependencies = [
  "bytes 1.1.0",
  "curve25519-dalek 3.2.0",
- "futures 0.3.17",
+ "futures 0.3.18",
  "lazy_static",
  "libp2p-core",
  "log",
@@ -4128,7 +4101,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2482cfd9eb0b7a0baaf3e7b329dc4f2785181a161b1a47b7192f8d758f54a439"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p-core",
  "libp2p-swarm",
  "log",
@@ -4145,12 +4118,12 @@
 dependencies = [
  "asynchronous-codec 0.6.0",
  "bytes 1.1.0",
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p-core",
  "log",
  "prost",
  "prost-build",
- "unsigned-varint 0.7.0",
+ "unsigned-varint 0.7.1",
  "void",
 ]
 
@@ -4160,7 +4133,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "07cb4dd4b917e5b40ddefe49b96b07adcd8d342e0317011d175b7b2bb1dcc974"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "log",
  "pin-project 1.0.8",
  "rand 0.7.3",
@@ -4176,7 +4149,7 @@
 dependencies = [
  "asynchronous-codec 0.6.0",
  "bytes 1.1.0",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "libp2p-core",
  "libp2p-swarm",
@@ -4186,7 +4159,7 @@
  "prost-build",
  "rand 0.7.3",
  "smallvec",
- "unsigned-varint 0.7.0",
+ "unsigned-varint 0.7.1",
  "void",
  "wasm-timer",
 ]
@@ -4199,7 +4172,7 @@
 dependencies = [
  "async-trait",
  "bytes 1.1.0",
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p-core",
  "libp2p-swarm",
  "log",
@@ -4207,7 +4180,7 @@
  "minicbor",
  "rand 0.7.3",
  "smallvec",
- "unsigned-varint 0.7.0",
+ "unsigned-varint 0.7.1",
  "wasm-timer",
 ]
 
@@ -4218,7 +4191,7 @@
 checksum = "7083861341e1555467863b4cd802bea1e8c4787c0f7b5110097d0f1f3248f9a9"
 dependencies = [
  "either",
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p-core",
  "log",
  "rand 0.7.3",
@@ -4244,7 +4217,7 @@
 checksum = "79edd26b6b4bb5feee210dcda562dca186940dfecb0024b979c3f50824b3bf28"
 dependencies = [
  "async-io",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "if-watch",
  "ipnet",
@@ -4261,7 +4234,7 @@
 checksum = "280e793440dd4e9f273d714f4497325c72cddb0fe85a49f9a03c88f41dd20182"
 dependencies = [
  "async-std",
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p-core",
  "log",
 ]
@@ -4272,7 +4245,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f553b7140fad3d7a76f50497b0ea591e26737d9607428a75509fc191e4d1b1f6"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "js-sys",
  "libp2p-core",
  "parity-send-wrapper",
@@ -4287,7 +4260,7 @@
 checksum = "ddf99dcbf5063e9d59087f61b1e85c686ceab2f5abedb472d32288065c0e5e27"
 dependencies = [
  "either",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-rustls",
  "libp2p-core",
  "log",
@@ -4304,7 +4277,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "214cc0dd9c37cbed27f0bb1eba0c41bbafdb93a8be5e9d6ae1e6b4b42cd044bf"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p-core",
  "parking_lot 0.11.2",
  "thiserror",
@@ -4603,9 +4576,9 @@
 
 [[package]]
 name = "matrixmultiply"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a8a15b776d9dfaecd44b03c5828c2199cddff5247215858aac14624f8d6b741"
+checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84"
 dependencies = [
  "rawpointer",
 ]
@@ -4678,7 +4651,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "thiserror",
  "tracing",
@@ -4686,11 +4659,11 @@
 
 [[package]]
 name = "mick-jaeger"
-version = "0.1.4"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c023c3f16109e7f33aa451f773fd61070e265b4977d0b6e344a51049296dd7df"
+checksum = "eaa77fad8461bb1e0d01be11299e24c6e544007715ed442bfec29f165dc487ae"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "rand 0.7.3",
  "thrift",
 ]
@@ -4716,6 +4689,12 @@
 ]
 
 [[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
 name = "miniz_oxide"
 version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4792,9 +4771,9 @@
 
 [[package]]
 name = "more-asserts"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238"
+checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389"
 
 [[package]]
 name = "multiaddr"
@@ -4810,7 +4789,7 @@
  "percent-encoding 2.1.0",
  "serde",
  "static_assertions",
- "unsigned-varint 0.7.0",
+ "unsigned-varint 0.7.1",
  "url 2.2.2",
 ]
 
@@ -4852,7 +4831,7 @@
  "generic-array 0.14.4",
  "multihash-derive",
  "sha2 0.9.8",
- "unsigned-varint 0.7.0",
+ "unsigned-varint 0.7.1",
 ]
 
 [[package]]
@@ -4882,11 +4861,11 @@
 checksum = "56a336acba8bc87c8876f6425407dbbe6c417bf478b22015f8fb0994ef3bc0ab"
 dependencies = [
  "bytes 1.1.0",
- "futures 0.3.17",
+ "futures 0.3.18",
  "log",
  "pin-project 1.0.8",
  "smallvec",
- "unsigned-varint 0.7.0",
+ "unsigned-varint 0.7.1",
 ]
 
 [[package]]
@@ -4952,13 +4931,12 @@
 
 [[package]]
 name = "nom"
-version = "6.1.2"
+version = "7.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
+checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
 dependencies = [
- "bitvec 0.19.5",
- "funty",
  "memchr",
+ "minimal-lexical",
  "version_check",
 ]
 
@@ -5160,7 +5138,7 @@
 dependencies = [
  "frame-support",
  "frame-system",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "scale-info",
  "sp-authorship",
@@ -5330,7 +5308,7 @@
 version = "0.1.0"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "bitvec 0.20.4",
+ "bitvec",
  "bp-message-dispatch",
  "bp-messages",
  "bp-rialto",
@@ -5509,9 +5487,9 @@
 [[package]]
 name = "pallet-ethereum"
 version = "4.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12#43ce3be6274eceaf47d9664ddc71cba68a990923"
+source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12-weights#0134806e399412bf896f881f1e3bc284916a1432"
 dependencies = [
- "ethereum 0.9.0 (git+https://github.com/purestake/ethereum?branch=joshy-scale-info)",
+ "ethereum 0.10.0",
  "ethereum-types",
  "evm",
  "fp-consensus",
@@ -5538,7 +5516,7 @@
 [[package]]
 name = "pallet-evm"
 version = "6.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12#43ce3be6274eceaf47d9664ddc71cba68a990923"
+source = "git+https://github.com/uniquenetwork/frontier.git?branch=unique-polkadot-v0.9.12-weights#0134806e399412bf896f881f1e3bc284916a1432"
 dependencies = [
  "evm",
  "evm-gasometer",
@@ -5548,7 +5526,7 @@
  "frame-support",
  "frame-system",
  "hex",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "log",
  "pallet-balances",
  "pallet-timestamp",
@@ -5568,8 +5546,9 @@
 name = "pallet-evm-coder-substrate"
 version = "0.1.0"
 dependencies = [
- "ethereum 0.9.0 (git+https://github.com/purestake/ethereum?branch=joshy-scale-info)",
+ "ethereum 0.10.0",
  "evm-coder",
+ "frame-benchmarking",
  "frame-support",
  "frame-system",
  "pallet-ethereum",
@@ -5638,7 +5617,7 @@
 name = "pallet-fungible"
 version = "0.1.0"
 dependencies = [
- "ethereum 0.9.0 (git+https://github.com/purestake/ethereum?branch=joshy-scale-info)",
+ "ethereum 0.10.0",
  "evm-coder",
  "frame-benchmarking",
  "frame-support",
@@ -5864,7 +5843,7 @@
 name = "pallet-nonfungible"
 version = "0.1.0"
 dependencies = [
- "ethereum 0.9.0 (git+https://github.com/purestake/ethereum?branch=joshy-scale-info)",
+ "ethereum 0.10.0",
  "evm-coder",
  "frame-benchmarking",
  "frame-support",
@@ -6001,7 +5980,7 @@
 dependencies = [
  "frame-support",
  "frame-system",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "log",
  "pallet-timestamp",
  "parity-scale-codec",
@@ -6212,7 +6191,7 @@
  "frame-benchmarking",
  "frame-support",
  "frame-system",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "pallet-balances",
  "parity-scale-codec",
  "scale-info",
@@ -6225,7 +6204,7 @@
 name = "pallet-unique"
 version = "0.1.0"
 dependencies = [
- "ethereum 0.9.0 (git+https://github.com/purestake/ethereum?branch=joshy-scale-info)",
+ "ethereum 0.10.0",
  "evm-coder",
  "fp-evm",
  "frame-benchmarking",
@@ -6346,7 +6325,7 @@
 [[package]]
 name = "parachain-info"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#f5926c2f50df73bf36171b138241437131d76fff"
+source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.12#c02514d8cb66d6860e597f75d53ca07119dbbf32"
 dependencies = [
  "cumulus-primitives-core",
  "frame-support",
@@ -6358,9 +6337,9 @@
 
 [[package]]
 name = "parity-db"
-version = "0.3.3"
+version = "0.3.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7ccc4a8687027deb53d45c5434a1f1b330c9d1069a59cfe80a62aa9a1da25ae"
+checksum = "78a95abf24f1097c6e3181abbbbfc3630b3b5e681470940f719b69acb4911c7f"
 dependencies = [
  "blake2-rfc",
  "crc32fast",
@@ -6382,9 +6361,9 @@
 checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909"
 dependencies = [
  "arrayvec 0.7.2",
- "bitvec 0.20.4",
+ "bitvec",
  "byte-slice-cast",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec-derive",
  "serde",
 ]
@@ -6413,11 +6392,11 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "libc",
  "log",
  "rand 0.7.3",
- "tokio 1.13.0",
+ "tokio 1.14.0",
  "winapi 0.3.9",
 ]
 
@@ -6430,7 +6409,7 @@
  "cfg-if 1.0.0",
  "ethereum-types",
  "hashbrown",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "lru 0.6.6",
  "parity-util-mem-derive",
  "parking_lot 0.11.2",
@@ -6540,9 +6519,9 @@
 
 [[package]]
 name = "paste"
-version = "1.0.5"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58"
+checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5"
 
 [[package]]
 name = "pbkdf2"
@@ -6708,7 +6687,7 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "polkadot-node-network-protocol",
  "polkadot-node-primitives",
  "polkadot-node-subsystem",
@@ -6722,7 +6701,7 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "polkadot-node-network-protocol",
  "polkadot-node-subsystem",
  "polkadot-node-subsystem-util",
@@ -6736,7 +6715,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "lru 0.7.0",
  "parity-scale-codec",
  "polkadot-erasure-coding",
@@ -6757,7 +6736,7 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "lru 0.7.0",
  "parity-scale-codec",
  "polkadot-erasure-coding",
@@ -6778,7 +6757,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "frame-benchmarking-cli",
- "futures 0.3.17",
+ "futures 0.3.18",
  "log",
  "polkadot-node-core-pvf",
  "polkadot-service",
@@ -6829,7 +6808,7 @@
 dependencies = [
  "always-assert",
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "polkadot-node-network-protocol",
  "polkadot-node-primitives",
@@ -6862,7 +6841,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "lru 0.7.0",
  "parity-scale-codec",
  "polkadot-erasure-coding",
@@ -6897,7 +6876,7 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "polkadot-node-network-protocol",
  "polkadot-node-subsystem",
@@ -6918,7 +6897,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "async-trait",
- "futures 0.3.17",
+ "futures 0.3.18",
  "parity-scale-codec",
  "parking_lot 0.11.2",
  "polkadot-node-network-protocol",
@@ -6936,7 +6915,7 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "parity-scale-codec",
  "polkadot-erasure-coding",
  "polkadot-node-primitives",
@@ -6954,9 +6933,9 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "bitvec 0.20.4",
+ "bitvec",
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "kvdb",
  "lru 0.7.0",
@@ -6982,8 +6961,8 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "bitvec 0.20.4",
- "futures 0.3.17",
+ "bitvec",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "kvdb",
  "parity-scale-codec",
@@ -7002,8 +6981,8 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "bitvec 0.20.4",
- "futures 0.3.17",
+ "bitvec",
+ "futures 0.3.18",
  "polkadot-erasure-coding",
  "polkadot-node-primitives",
  "polkadot-node-subsystem",
@@ -7020,7 +6999,7 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "polkadot-node-subsystem",
  "polkadot-node-subsystem-util",
  "polkadot-primitives",
@@ -7036,7 +7015,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "async-trait",
- "futures 0.3.17",
+ "futures 0.3.18",
  "parity-scale-codec",
  "polkadot-node-core-pvf",
  "polkadot-node-primitives",
@@ -7053,7 +7032,7 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "polkadot-node-subsystem",
  "polkadot-node-subsystem-util",
  "polkadot-primitives",
@@ -7068,7 +7047,7 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "kvdb",
  "parity-scale-codec",
@@ -7085,9 +7064,9 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "bitvec 0.20.4",
+ "bitvec",
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "kvdb",
  "parity-scale-codec",
  "polkadot-node-primitives",
@@ -7104,7 +7083,7 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "polkadot-node-primitives",
  "polkadot-node-subsystem",
  "polkadot-primitives",
@@ -7118,7 +7097,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "async-trait",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "polkadot-node-subsystem",
  "polkadot-primitives",
@@ -7134,8 +7113,8 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "bitvec 0.20.4",
- "futures 0.3.17",
+ "bitvec",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "polkadot-node-subsystem",
  "polkadot-node-subsystem-util",
@@ -7153,7 +7132,7 @@
  "assert_matches",
  "async-process",
  "async-std",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "libc",
  "parity-scale-codec",
@@ -7180,7 +7159,7 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "memory-lru",
  "parity-util-mem",
  "polkadot-node-subsystem",
@@ -7216,7 +7195,7 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "metered-channel",
  "substrate-prometheus-endpoint",
@@ -7229,7 +7208,7 @@
 dependencies = [
  "async-trait",
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "parity-scale-codec",
  "polkadot-node-jaeger",
  "polkadot-node-primitives",
@@ -7246,7 +7225,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "bounded-vec",
- "futures 0.3.17",
+ "futures 0.3.18",
  "parity-scale-codec",
  "polkadot-parachain",
  "polkadot-primitives",
@@ -7278,7 +7257,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "polkadot-node-jaeger",
  "polkadot-node-network-protocol",
  "polkadot-node-primitives",
@@ -7298,7 +7277,7 @@
 dependencies = [
  "async-trait",
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "itertools",
  "lru 0.7.0",
  "metered-channel",
@@ -7323,7 +7302,7 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "lru 0.7.0",
  "parity-util-mem",
@@ -7345,7 +7324,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "async-trait",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "metered-channel",
  "pin-project 1.0.8",
@@ -7389,7 +7368,7 @@
 version = "0.9.12"
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
- "bitvec 0.20.4",
+ "bitvec",
  "frame-system",
  "hex-literal",
  "parity-scale-codec",
@@ -7451,7 +7430,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "beefy-primitives",
- "bitvec 0.20.4",
+ "bitvec",
  "frame-benchmarking",
  "frame-election-provider-support",
  "frame-executive",
@@ -7528,12 +7507,12 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "beefy-primitives",
- "bitvec 0.20.4",
+ "bitvec",
  "frame-benchmarking",
  "frame-election-provider-support",
  "frame-support",
  "frame-system",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "libsecp256k1 0.7.0",
  "log",
  "pallet-authorship",
@@ -7575,7 +7554,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "bitflags",
- "bitvec 0.20.4",
+ "bitvec",
  "derive_more",
  "frame-benchmarking",
  "frame-support",
@@ -7617,7 +7596,7 @@
  "beefy-gadget",
  "beefy-primitives",
  "frame-system-rpc-runtime-api",
- "futures 0.3.17",
+ "futures 0.3.18",
  "hex-literal",
  "kusama-runtime",
  "kvdb",
@@ -7713,7 +7692,7 @@
 dependencies = [
  "arrayvec 0.5.2",
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "indexmap",
  "parity-scale-codec",
  "polkadot-node-network-protocol",
@@ -7743,7 +7722,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "beefy-primitives",
- "bitvec 0.20.4",
+ "bitvec",
  "frame-election-provider-support",
  "frame-executive",
  "frame-support",
@@ -7806,7 +7785,7 @@
  "frame-benchmarking",
  "frame-system",
  "futures 0.1.31",
- "futures 0.3.17",
+ "futures 0.3.18",
  "hex",
  "pallet-balances",
  "pallet-staking",
@@ -7847,15 +7826,15 @@
  "sp-state-machine",
  "substrate-test-client",
  "tempfile",
- "tokio 1.13.0",
+ "tokio 1.14.0",
  "tracing",
 ]
 
 [[package]]
 name = "polling"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92341d779fa34ea8437ef4d82d440d5e1ce3f3ff7f824aa64424cd481f9a1f25"
+checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259"
 dependencies = [
  "cfg-if 1.0.0",
  "libc",
@@ -7987,20 +7966,8 @@
  "quote",
  "version_check",
 ]
-
-[[package]]
-name = "proc-macro-hack"
-version = "0.5.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
 
 [[package]]
-name = "proc-macro-nested"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
-
-[[package]]
 name = "proc-macro2"
 version = "1.0.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -8125,12 +8092,6 @@
 dependencies = [
  "proc-macro2",
 ]
-
-[[package]]
-name = "radium"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
 
 [[package]]
 name = "radium"
@@ -8617,7 +8578,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "pin-project 0.4.28",
  "static_assertions",
 ]
@@ -8673,7 +8634,7 @@
 dependencies = [
  "async-trait",
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "ip_network",
  "libp2p",
@@ -8698,7 +8659,7 @@
 version = "0.10.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "log",
  "parity-scale-codec",
@@ -8737,7 +8698,7 @@
 version = "4.0.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "sc-chain-spec-derive",
  "sc-network",
@@ -8766,7 +8727,7 @@
 dependencies = [
  "chrono",
  "fdlimit",
- "futures 0.3.17",
+ "futures 0.3.18",
  "hex",
  "libp2p",
  "log",
@@ -8794,7 +8755,7 @@
  "structopt",
  "thiserror",
  "tiny-bip39",
- "tokio 1.13.0",
+ "tokio 1.14.0",
 ]
 
 [[package]]
@@ -8803,7 +8764,7 @@
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
  "fnv",
- "futures 0.3.17",
+ "futures 0.3.18",
  "hash-db",
  "log",
  "parity-scale-codec",
@@ -8856,7 +8817,7 @@
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
  "async-trait",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "libp2p",
  "log",
@@ -8881,7 +8842,7 @@
 dependencies = [
  "async-trait",
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "log",
  "parity-scale-codec",
  "sc-block-builder",
@@ -8911,7 +8872,7 @@
  "async-trait",
  "derive_more",
  "fork-tree",
- "futures 0.3.17",
+ "futures 0.3.18",
  "log",
  "merlin",
  "num-bigint",
@@ -8952,7 +8913,7 @@
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpc-core",
  "jsonrpc-core-client",
  "jsonrpc-derive",
@@ -8989,7 +8950,7 @@
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
  "async-trait",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "log",
  "parity-scale-codec",
@@ -9108,7 +9069,7 @@
  "dyn-clone",
  "finality-grandpa",
  "fork-tree",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "log",
  "parity-scale-codec",
@@ -9142,7 +9103,7 @@
 dependencies = [
  "derive_more",
  "finality-grandpa",
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpc-core",
  "jsonrpc-core-client",
  "jsonrpc-derive",
@@ -9165,7 +9126,7 @@
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
  "ansi_term 0.12.1",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "log",
  "parity-util-mem",
@@ -9224,7 +9185,7 @@
  "either",
  "fnv",
  "fork-tree",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "hex",
  "ip_network",
@@ -9265,7 +9226,7 @@
 version = "0.10.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "libp2p",
  "log",
@@ -9283,7 +9244,7 @@
 dependencies = [
  "bytes 1.1.0",
  "fnv",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "hex",
  "hyper",
@@ -9308,7 +9269,7 @@
 version = "4.0.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p",
  "log",
  "sc-utils",
@@ -9330,7 +9291,7 @@
 version = "4.0.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "hash-db",
  "jsonrpc-core",
  "jsonrpc-pubsub",
@@ -9361,7 +9322,7 @@
 version = "0.10.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpc-core",
  "jsonrpc-core-client",
  "jsonrpc-derive",
@@ -9386,7 +9347,7 @@
 version = "4.0.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpc-core",
  "jsonrpc-http-server",
  "jsonrpc-ipc-server",
@@ -9395,7 +9356,7 @@
  "log",
  "serde_json",
  "substrate-prometheus-endpoint",
- "tokio 1.13.0",
+ "tokio 1.14.0",
 ]
 
 [[package]]
@@ -9406,7 +9367,7 @@
  "async-trait",
  "directories",
  "exit-future",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "hash-db",
  "jsonrpc-core",
@@ -9458,7 +9419,7 @@
  "substrate-prometheus-endpoint",
  "tempfile",
  "thiserror",
- "tokio 1.13.0",
+ "tokio 1.14.0",
  "tracing",
  "tracing-futures",
 ]
@@ -9505,7 +9466,7 @@
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
  "chrono",
- "futures 0.3.17",
+ "futures 0.3.18",
  "libp2p",
  "log",
  "parking_lot 0.11.2",
@@ -9563,7 +9524,7 @@
 version = "4.0.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "intervalier",
  "linked-hash-map",
  "log",
@@ -9591,7 +9552,7 @@
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "log",
  "serde",
  "sp-blockchain",
@@ -9604,7 +9565,7 @@
 version = "4.0.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "lazy_static",
  "prometheus",
@@ -9616,7 +9577,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5c55b744399c25532d63a0d2789b109df8d46fc93752d46b0782991a931a782f"
 dependencies = [
- "bitvec 0.20.4",
+ "bitvec",
  "cfg-if 1.0.0",
  "derive_more",
  "parity-scale-codec",
@@ -9783,9 +9744,9 @@
 
 [[package]]
 name = "serde_json"
-version = "1.0.68"
+version = "1.0.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
+checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527"
 dependencies = [
  "itoa",
  "ryu",
@@ -10006,7 +9967,7 @@
  "base64 0.12.3",
  "bytes 0.5.6",
  "flate2",
- "futures 0.3.17",
+ "futures 0.3.18",
  "httparse",
  "log",
  "rand 0.7.3",
@@ -10021,7 +9982,7 @@
 dependencies = [
  "base64 0.13.0",
  "bytes 1.1.0",
- "futures 0.3.17",
+ "futures 0.3.18",
  "httparse",
  "log",
  "rand 0.8.4",
@@ -10127,7 +10088,7 @@
 version = "4.0.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "log",
  "lru 0.6.6",
  "parity-scale-codec",
@@ -10146,7 +10107,7 @@
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
  "async-trait",
- "futures 0.3.17",
+ "futures 0.3.18",
  "futures-timer 3.0.2",
  "log",
  "parity-scale-codec",
@@ -10233,7 +10194,7 @@
  "byteorder",
  "dyn-clonable",
  "ed25519-dalek",
- "futures 0.3.17",
+ "futures 0.3.18",
  "hash-db",
  "hash256-std-hasher",
  "hex",
@@ -10323,7 +10284,7 @@
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
  "async-trait",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "sp-core",
  "sp-runtime",
@@ -10336,7 +10297,7 @@
 version = "4.0.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "hash-db",
  "libsecp256k1 0.6.0",
  "log",
@@ -10373,7 +10334,7 @@
 dependencies = [
  "async-trait",
  "derive_more",
- "futures 0.3.17",
+ "futures 0.3.18",
  "merlin",
  "parity-scale-codec",
  "parking_lot 0.11.2",
@@ -10452,7 +10413,7 @@
 dependencies = [
  "either",
  "hash256-std-hasher",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "log",
  "parity-scale-codec",
  "parity-util-mem",
@@ -10472,7 +10433,7 @@
 version = "4.0.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "primitive-types 0.10.1",
  "sp-externalities",
@@ -10698,7 +10659,7 @@
 version = "4.0.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "sp-std",
  "wasmi",
@@ -10712,9 +10673,9 @@
 
 [[package]]
 name = "ss58-registry"
-version = "1.2.0"
+version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb102b328df61c67f8ccf8471b29c31c7d6da646a867aff95fe8bff386fe7c4d"
+checksum = "78abb01d308934b82e34e9cf1f45846d31539246501745b129539176f4f3368d"
 dependencies = [
  "Inflector",
  "proc-macro2",
@@ -10897,7 +10858,7 @@
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
  "frame-system-rpc-runtime-api",
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpc-core",
  "jsonrpc-core-client",
  "jsonrpc-derive",
@@ -10924,7 +10885,7 @@
  "hyper",
  "log",
  "prometheus",
- "tokio 1.13.0",
+ "tokio 1.14.0",
 ]
 
 [[package]]
@@ -10933,7 +10894,7 @@
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
  "async-trait",
- "futures 0.3.17",
+ "futures 0.3.18",
  "hex",
  "parity-scale-codec",
  "sc-client-api",
@@ -10959,9 +10920,9 @@
 version = "4.0.0-dev"
 source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.12#d76f39995315ec36980908e4b99709bd14927044"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "substrate-test-utils-derive",
- "tokio 1.13.0",
+ "tokio 1.14.0",
 ]
 
 [[package]]
@@ -11004,9 +10965,9 @@
 
 [[package]]
 name = "syn"
-version = "1.0.81"
+version = "1.0.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
+checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -11172,9 +11133,9 @@
 
 [[package]]
 name = "tinyvec"
-version = "1.5.0"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7"
+checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
 dependencies = [
  "tinyvec_macros",
 ]
@@ -11199,9 +11160,9 @@
 
 [[package]]
 name = "tokio"
-version = "1.13.0"
+version = "1.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee"
+checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144"
 dependencies = [
  "autocfg",
  "bytes 1.1.0",
@@ -11212,7 +11173,7 @@
  "once_cell",
  "pin-project-lite 0.2.7",
  "signal-hook-registry",
- "tokio-macros 1.5.1",
+ "tokio-macros 1.6.0",
  "winapi 0.3.9",
 ]
 
@@ -11229,9 +11190,9 @@
 
 [[package]]
 name = "tokio-macros"
-version = "1.5.1"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "114383b041aa6212c579467afa0075fbbdd0718de036100bc0ba7961d8cb9095"
+checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -11245,7 +11206,7 @@
 checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6"
 dependencies = [
  "rustls",
- "tokio 1.13.0",
+ "tokio 1.14.0",
  "webpki",
 ]
 
@@ -11257,7 +11218,7 @@
 dependencies = [
  "futures-core",
  "pin-project-lite 0.2.7",
- "tokio 1.13.0",
+ "tokio 1.14.0",
 ]
 
 [[package]]
@@ -11272,7 +11233,7 @@
  "futures-sink",
  "log",
  "pin-project-lite 0.2.7",
- "tokio 1.13.0",
+ "tokio 1.14.0",
 ]
 
 [[package]]
@@ -11596,7 +11557,7 @@
  "fp-rpc",
  "frame-benchmarking",
  "frame-benchmarking-cli",
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpc-core",
  "jsonrpc-pubsub",
  "log",
@@ -11660,7 +11621,7 @@
  "fc-rpc",
  "fc-rpc-core",
  "fp-rpc",
- "futures 0.3.17",
+ "futures 0.3.18",
  "jsonrpc-core",
  "jsonrpc-pubsub",
  "pallet-ethereum",
@@ -11800,9 +11761,9 @@
 
 [[package]]
 name = "unsigned-varint"
-version = "0.7.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f8d425fafb8cd76bc3f22aace4af471d3156301d7508f2107e98fbeae10bc7f"
+checksum = "d86a8dc7f45e4c1b0d30e43038c38f274e77af056aa5f74b93c2cf9eb3c1c836"
 dependencies = [
  "asynchronous-codec 0.6.0",
  "bytes 1.1.0",
@@ -11857,7 +11818,7 @@
 version = "0.1.0"
 source = "git+https://github.com/UniqueNetwork/pallet-sponsoring#ab8b91e9350a31133f3a3e4f52a84c6de4108e95"
 dependencies = [
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
 ]
 
 [[package]]
@@ -12039,7 +12000,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "js-sys",
  "parking_lot 0.11.2",
  "pin-utils",
@@ -12279,7 +12240,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "beefy-primitives",
- "bitvec 0.20.4",
+ "bitvec",
  "frame-benchmarking",
  "frame-election-provider-support",
  "frame-executive",
@@ -12459,7 +12420,7 @@
 source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.12#5feed981cf0fe671447eabaa9c0d235a8dd0003e"
 dependencies = [
  "derivative",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "log",
  "parity-scale-codec",
  "scale-info",
@@ -12493,7 +12454,7 @@
 dependencies = [
  "frame-benchmarking",
  "frame-support",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "log",
  "parity-scale-codec",
  "sp-arithmetic",
@@ -12520,7 +12481,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e7d9028f208dd5e63c614be69f115c1b53cacc1111437d4c765185856666c107"
 dependencies = [
- "futures 0.3.17",
+ "futures 0.3.18",
  "log",
  "nohash-hasher",
  "parking_lot 0.11.2",
@@ -12536,18 +12497,18 @@
 
 [[package]]
 name = "zeroize"
-version = "1.4.2"
+version = "1.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970"
+checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619"
 dependencies = [
  "zeroize_derive",
 ]
 
 [[package]]
 name = "zeroize_derive"
-version = "1.2.0"
+version = "1.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdff2024a851a322b08f179173ae2ba620445aef1e838f0c196820eade4ae0c7"
+checksum = "65f1a51723ec88c66d5d1fe80c841f17f63587d6691901d66be9bec6c3b51f73"
 dependencies = [
  "proc-macro2",
  "quote",
modifiedDockerfile-parachaindiffbeforeafterboth
--- a/Dockerfile-parachain
+++ b/Dockerfile-parachain
@@ -2,7 +2,7 @@
 FROM phusion/baseimage:focal-1.0.0 as rust-builder
 LABEL maintainer="Unique.Network"
 
-ARG RUST_TOOLCHAIN=nightly-2021-06-28
+ARG RUST_TOOLCHAIN=nightly-2021-11-11
 #ARG RUST_C=1.55.0-nightly
 ARG POLKA_VERSION=v0.9.12
 ARG UNIQUE_BRANCH=develop
modifiedREADME.mddiffbeforeafterboth
--- a/README.md
+++ b/README.md
@@ -63,17 +63,17 @@
 
 2. Remove all installed toolchains with `rustup toolchain list` and `rustup toolchain uninstall <toolchain>`.
 
-3. Install install nightly 2021-06-28 and make it default:
+3. Install install nightly 2021-11-11 and make it default:
 
 ```bash
-rustup toolchain install nightly-2021-06-28
-rustup default nightly-2021-06-28
+rustup toolchain install nightly-2021-11-11
+rustup default nightly-2021-11-11
 ```
 
 4. Add wasm target for nightly toolchain:
 
 ```bash
-rustup target add wasm32-unknown-unknown --toolchain nightly-2021-06-28
+rustup target add wasm32-unknown-unknown --toolchain nightly-2021-11-11
 ```
 
 5. Build:
@@ -135,7 +135,7 @@
 
 ## Building and Running as Parachain locally
 
-Rust toolchain: nightly-2021-06-28
+Rust toolchain: nightly-2021-11-11
 Note: checkout this project and polkadot project (see below) in the sibling folders (both under the same folder)
 
 ### Build relay
@@ -208,12 +208,12 @@
 
 First of all, add rust toolchain and make it default.
 ```bash
-rustup target add wasm32-unknown-unknown --toolchain nightly-2021-06-28
+rustup target add wasm32-unknown-unknown --toolchain nightly-2021-11-11
 ```
 
 Then in "/node/src" run build command below
 ```bash
-cargo +nightly-2021-06-28 build --release --features runtime-benchmarks
+cargo +nightly-2021-11-11 build --release --features runtime-benchmarks
 ```
 
 Run benchmark
modifiedclient/rpc/Cargo.tomldiffbeforeafterboth
--- a/client/rpc/Cargo.toml
+++ b/client/rpc/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "uc-rpc"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 pallet-common = { default-features = false, path = '../../pallets/common' }
modifiedcrates/evm-coder-macros/Cargo.tomldiffbeforeafterboth
--- a/crates/evm-coder-macros/Cargo.toml
+++ b/crates/evm-coder-macros/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "evm-coder-macros"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 proc-macro = true
@@ -13,4 +13,4 @@
 syn = { version = "1.0", features = ["full"] }
 hex = "0.4.3"
 Inflector = "0.11.4"
-darling = "0.13.0"
\ No newline at end of file
+darling = "0.13.0"
modifiedcrates/evm-coder-macros/src/lib.rsdiffbeforeafterboth
--- a/crates/evm-coder-macros/src/lib.rs
+++ b/crates/evm-coder-macros/src/lib.rs
@@ -27,7 +27,7 @@
 /// Returns solidity function selector (first 4 bytes of hash) by its
 /// textual representation
 ///
-/// ```rs
+/// ```ignore
 /// use evm_coder_macros::fn_selector;
 ///
 /// assert_eq!(fn_selector!(transfer(address, uint256)), 0xa9059cbb);
@@ -55,7 +55,7 @@
 
 /// Returns solidity topic (hash) by its textual representation
 ///
-/// ```rs
+/// ```ignore
 /// use evm_coder_macros::event_topic;
 ///
 /// assert_eq!(
@@ -184,6 +184,58 @@
 	Ident::new(&name, ident.span())
 }
 
+/// Derives call enum implementing [`evm_coder::Callable`], [`evm_coder::Weighted`]
+/// and [`evm_coder::Call`] from impl block
+///
+/// ## Macro syntax
+///
+/// `#[solidity_interface(name, is, inline_is, events)]`
+/// - *name*: used in generated code, and for Call enum name
+/// - *is*: used to provide call inheritance, not found methods will be delegated to all contracts
+/// specified in is/inline_is
+/// - *inline_is*: same as is, but selectors for passed contracts will be used by derived ERC165
+/// implementation
+///
+/// `#[weight(value)]`
+/// Can be added to every method of impl block, used for deriving [`evm_coder::Weighted`], which
+/// is used by substrate bridge
+/// - *value*: expression, which evaluates to weight required to call this method.
+/// This expression can use call arguments to calculate non-constant execution time.
+/// This expression should evaluate faster than actual execution does, and may provide worser case
+/// than one is called
+///
+/// `#[solidity_interface(rename_selector)]`
+/// - *rename_selector*: by default, selector name will be generated by transforming method name
+/// from snake_case to camelCase. Use this option, if other naming convention is required.
+/// I.e: method `token_uri` will be automatically renamed to `tokenUri` in selector, but name
+/// required by ERC721 standard is `tokenURI`, thus we need to specify `rename_selector = "tokenURI"`
+/// explicitly
+///
+/// Also, any contract method may have doc comments, which will be automatically added to generated
+/// solidity interface definitions
+///
+/// ## Example
+///
+/// ```ignore
+/// struct SuperContract;
+/// struct InlineContract;
+/// struct Contract;
+///
+/// #[derive(ToLog)]
+/// enum ContractEvents {
+///     Event(#[indexed] uint32),
+/// }
+///
+/// #[solidity_interface(name = "MyContract", is(SuperContract), inline_is(InlineContract))]
+/// impl Contract {
+///     /// Multiply two numbers
+///     #[weight(200 + a + b)]
+///     #[solidity_interface(rename_selector = "mul")]
+///     fn mul(&mut self, a: uint32, b: uint32) -> Result<uint32> {
+///         Ok(a.checked_mul(b).ok_or("overflow")?)
+///     }
+/// }
+/// ```
 #[proc_macro_attribute]
 pub fn solidity_interface(args: TokenStream, stream: TokenStream) -> TokenStream {
 	let args = parse_macro_input!(args as AttributeArgs);
@@ -211,7 +263,15 @@
 pub fn solidity(_args: TokenStream, stream: TokenStream) -> TokenStream {
 	stream
 }
+#[proc_macro_attribute]
+pub fn weight(_args: TokenStream, stream: TokenStream) -> TokenStream {
+	stream
+}
 
+/// ## Syntax
+///
+/// `#[indexed]`
+/// Marks this field as indexed, so it will appear in [`ethereum::Log`] topics instead of data
 #[proc_macro_derive(ToLog, attributes(indexed))]
 pub fn to_log(value: TokenStream) -> TokenStream {
 	let input = parse_macro_input!(value as DeriveInput);
modifiedcrates/evm-coder-macros/src/solidity_interface.rsdiffbeforeafterboth
--- a/crates/evm-coder-macros/src/solidity_interface.rs
+++ b/crates/evm-coder-macros/src/solidity_interface.rs
@@ -6,7 +6,7 @@
 use std::fmt::Write;
 use syn::{
 	Expr, FnArg, GenericArgument, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Lit, Meta,
-	NestedMeta, PatType, Path, PathArguments, ReturnType, Type, spanned::Spanned,
+	MetaNameValue, NestedMeta, PatType, Path, PathArguments, ReturnType, Type, spanned::Spanned,
 };
 
 use crate::{
@@ -30,11 +30,11 @@
 		})
 	}
 
-	fn expand_call_def(&self) -> proc_macro2::TokenStream {
+	fn expand_call_def(&self, gen_ref: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
 		let name = &self.name;
 		let pascal_call_name = &self.pascal_call_name;
 		quote! {
-			#name(#pascal_call_name)
+			#name(#pascal_call_name #gen_ref)
 		}
 	}
 
@@ -45,18 +45,32 @@
 		}
 	}
 
-	fn expand_supports_interface(&self) -> proc_macro2::TokenStream {
+	fn expand_supports_interface(
+		&self,
+		generics: &proc_macro2::TokenStream,
+	) -> proc_macro2::TokenStream {
 		let pascal_call_name = &self.pascal_call_name;
 		quote! {
-			#pascal_call_name::supports_interface(interface_id)
+			<#pascal_call_name #generics>::supports_interface(interface_id)
 		}
 	}
 
-	fn expand_variant_call(&self) -> proc_macro2::TokenStream {
+	fn expand_variant_weight(&self) -> proc_macro2::TokenStream {
 		let name = &self.name;
+		quote! {
+			Self::#name(call) => call.weight()
+		}
+	}
+
+	fn expand_variant_call(
+		&self,
+		call_name: &proc_macro2::Ident,
+		generics: &proc_macro2::TokenStream,
+	) -> proc_macro2::TokenStream {
+		let name = &self.name;
 		let pascal_call_name = &self.pascal_call_name;
 		quote! {
-			InternalCall::#name(call) => return <Self as ::evm_coder::Callable<#pascal_call_name>>::call(self, Msg {
+			#call_name::#name(call) => return <Self as ::evm_coder::Callable<#pascal_call_name #generics>>::call(self, Msg {
 				call,
 				caller: c.caller,
 				value: c.value,
@@ -64,20 +78,20 @@
 		}
 	}
 
-	fn expand_parse(&self) -> proc_macro2::TokenStream {
+	fn expand_parse(&self, generics: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
 		let name = &self.name;
 		let pascal_call_name = &self.pascal_call_name;
 		quote! {
-			if let Some(parsed_call) = #pascal_call_name::parse(method_id, reader)? {
+			if let Some(parsed_call) = <#pascal_call_name #generics>::parse(method_id, reader)? {
 				return Ok(Some(Self::#name(parsed_call)))
 			}
 		}
 	}
 
-	fn expand_generator(&self) -> proc_macro2::TokenStream {
+	fn expand_generator(&self, generics: &proc_macro2::TokenStream) -> proc_macro2::TokenStream {
 		let pascal_call_name = &self.pascal_call_name;
 		quote! {
-			#pascal_call_name::generate_solidity_interface(tc, is_impl);
+			<#pascal_call_name #generics>::generate_solidity_interface(tc, is_impl);
 		}
 	}
 
@@ -212,16 +226,10 @@
 		}
 	}
 	fn is_value(&self) -> bool {
-		match self {
-			Self::Plain(v) if v == "value" => true,
-			_ => false,
-		}
+		matches!(self, Self::Plain(v) if v == "value")
 	}
 	fn is_caller(&self) -> bool {
-		match self {
-			Self::Plain(v) if v == "caller" => true,
-			_ => false,
-		}
+		matches!(self, Self::Plain(v) if v == "caller")
 	}
 	fn is_special(&self) -> bool {
 		self.is_caller() || self.is_value()
@@ -351,6 +359,25 @@
 	Pure,
 }
 
+pub struct WeightAttr(syn::Expr);
+
+mod keyword {
+	syn::custom_keyword!(weight);
+}
+
+impl syn::parse::Parse for WeightAttr {
+	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+		input.parse::<syn::Token![#]>()?;
+		let content;
+		syn::bracketed!(content in input);
+		content.parse::<keyword::weight>()?;
+
+		let weight_content;
+		syn::parenthesized!(weight_content in content);
+		Ok(WeightAttr(weight_content.parse::<syn::Expr>()?))
+	}
+}
+
 struct Method {
 	name: Ident,
 	camel_name: String,
@@ -362,19 +389,32 @@
 	has_normal_args: bool,
 	mutability: Mutability,
 	result: Type,
+	weight: Option<Expr>,
+	docs: Vec<String>,
 }
 impl Method {
 	fn try_from(value: &ImplItemMethod) -> syn::Result<Self> {
 		let mut info = MethodInfo {
 			rename_selector: None,
 		};
+		let mut docs = Vec::new();
+		let mut weight = None;
 		for attr in &value.attrs {
 			let ident = parse_ident_from_path(&attr.path, false)?;
 			if ident == "solidity" {
 				let args = attr.parse_meta().unwrap();
 				info = MethodInfo::from_meta(&args).unwrap();
 			} else if ident == "doc" {
-				// TODO: Add docs to evm interfaces
+				let args = attr.parse_meta().unwrap();
+				let value = match args {
+					Meta::NameValue(MetaNameValue {
+						lit: Lit::Str(str), ..
+					}) => str.value(),
+					_ => unreachable!(),
+				};
+				docs.push(value);
+			} else if ident == "weight" {
+				weight = Some(syn::parse2::<WeightAttr>(attr.to_token_stream())?.0);
 			}
 		}
 		let ident = &value.sig.ident;
@@ -457,6 +497,8 @@
 			has_normal_args,
 			mutability,
 			result: result.clone(),
+			weight,
+			docs,
 		})
 	}
 	fn expand_call_def(&self) -> proc_macro2::TokenStream {
@@ -518,7 +560,7 @@
 		}
 	}
 
-	fn expand_variant_call(&self) -> proc_macro2::TokenStream {
+	fn expand_variant_call(&self, call_name: &proc_macro2::Ident) -> proc_macro2::TokenStream {
 		let pascal_name = &self.pascal_name;
 		let name = &self.name;
 
@@ -545,13 +587,46 @@
 		let args = self.args.iter().map(|a| a.expand_call_arg());
 
 		quote! {
-			InternalCall::#pascal_name #matcher => {
+			#call_name::#pascal_name #matcher => {
 				let result = #receiver #name(
 					#(
 						#args,
 					)*
 				)?;
-				(&result).abi_write(&mut writer);
+				(&result).to_result()
+			}
+		}
+	}
+
+	fn expand_variant_weight(&self) -> proc_macro2::TokenStream {
+		let pascal_name = &self.pascal_name;
+		if let Some(weight) = &self.weight {
+			let matcher = if self.has_normal_args {
+				let names = self
+					.args
+					.iter()
+					.filter(|a| !a.is_special())
+					.map(|a| &a.name);
+
+				quote! {{
+					#(
+						#names,
+					)*
+				}}
+			} else {
+				quote! {}
+			};
+			quote! {
+				Self::#pascal_name #matcher => (#weight).into()
+			}
+		} else {
+			let matcher = if self.has_normal_args {
+				quote! {{..}}
+			} else {
+				quote! {}
+			};
+			quote! {
+				Self::#pascal_name #matcher => ().into()
 			}
 		}
 	}
@@ -570,10 +645,12 @@
 			.iter()
 			.filter(|a| !a.is_special())
 			.map(MethodArg::expand_solidity_argument);
+		let docs = self.docs.iter();
 		let selector = format!("{} {:0>8x}", self.selector_str, self.selector);
 
 		quote! {
 			SolidityFunction {
+				docs: &[#(#docs),*],
 				selector: #selector,
 				name: #camel_name,
 				mutability: #mutability,
@@ -588,6 +665,42 @@
 	}
 }
 
+fn generics_list(gen: &Generics) -> proc_macro2::TokenStream {
+	if gen.params.is_empty() {
+		return quote! {};
+	}
+	let params = gen.params.iter().map(|p| match p {
+		syn::GenericParam::Type(id) => {
+			let v = &id.ident;
+			quote! {#v}
+		}
+		syn::GenericParam::Lifetime(lt) => {
+			let v = &lt.lifetime;
+			quote! {#v}
+		}
+		syn::GenericParam::Const(c) => {
+			let i = &c.ident;
+			quote! {#i}
+		}
+	});
+	quote! { #(#params),* }
+}
+fn generics_reference(gen: &Generics) -> proc_macro2::TokenStream {
+	if gen.params.is_empty() {
+		return quote! {};
+	}
+	let list = generics_list(gen);
+	quote! { <#list> }
+}
+fn generics_data(gen: &Generics) -> proc_macro2::TokenStream {
+	let list = generics_list(gen);
+	if gen.params.len() == 1 {
+		quote! {#list}
+	} else {
+		quote! { (#list) }
+	}
+}
+
 pub struct SolidityInterface {
 	generics: Generics,
 	name: Box<syn::Type>,
@@ -616,6 +729,8 @@
 		let solidity_name = self.info.name.to_string();
 		let call_name = pascal_ident_to_call(&self.info.name);
 		let generics = self.generics;
+		let gen_ref = generics_reference(&generics);
+		let gen_data = generics_data(&generics);
 
 		let call_sub = self
 			.info
@@ -623,30 +738,46 @@
 			.0
 			.iter()
 			.chain(self.info.is.0.iter())
-			.map(Is::expand_call_def);
+			.map(|c| Is::expand_call_def(c, &gen_ref));
 		let call_parse = self
 			.info
 			.inline_is
 			.0
 			.iter()
 			.chain(self.info.is.0.iter())
-			.map(Is::expand_parse);
+			.map(|is| Is::expand_parse(is, &gen_ref));
 		let call_variants = self
 			.info
 			.inline_is
 			.0
 			.iter()
 			.chain(self.info.is.0.iter())
-			.map(Is::expand_variant_call);
+			.map(|c| Is::expand_variant_call(c, &call_name, &gen_ref));
+		let weight_variants = self
+			.info
+			.inline_is
+			.0
+			.iter()
+			.chain(self.info.is.0.iter())
+			.map(Is::expand_variant_weight);
 
 		let inline_interface_id = self.info.inline_is.0.iter().map(Is::expand_interface_id);
-		let supports_interface = self.info.is.0.iter().map(Is::expand_supports_interface);
+		let supports_interface = self
+			.info
+			.is
+			.0
+			.iter()
+			.map(|is| Is::expand_supports_interface(is, &gen_ref));
 
 		let calls = self.methods.iter().map(Method::expand_call_def);
 		let consts = self.methods.iter().map(Method::expand_const);
 		let interface_id = self.methods.iter().map(Method::expand_interface_id);
 		let parsers = self.methods.iter().map(Method::expand_parse);
-		let call_variants_this = self.methods.iter().map(Method::expand_variant_call);
+		let call_variants_this = self
+			.methods
+			.iter()
+			.map(|m| Method::expand_variant_call(m, &call_name));
+		let weight_variants_this = self.methods.iter().map(Method::expand_variant_weight);
 		let solidity_functions = self.methods.iter().map(Method::expand_solidity_function);
 
 		// TODO: Inline inline_is
@@ -664,15 +795,15 @@
 			.0
 			.iter()
 			.chain(self.info.inline_is.0.iter())
-			.map(Is::expand_generator);
+			.map(|is| Is::expand_generator(is, &gen_ref));
 		let solidity_event_generators = self.info.events.0.iter().map(Is::expand_event_generator);
 
 		// let methods = self.methods.iter().map(Method::solidity_def);
 
 		quote! {
 			#[derive(Debug)]
-			pub enum #call_name {
-				ERC165Call(::evm_coder::ERC165Call),
+			pub enum #call_name #gen_ref {
+				ERC165Call(::evm_coder::ERC165Call, ::core::marker::PhantomData<#gen_data>),
 				#(
 					#calls,
 				)*
@@ -680,11 +811,11 @@
 					#call_sub,
 				)*
 			}
-			impl #call_name {
+			impl #gen_ref #call_name #gen_ref {
 				#(
 					#consts
 				)*
-				pub const fn interface_id() -> u32 {
+				pub fn interface_id() -> u32 {
 					let mut interface_id = 0;
 					#(#interface_id)*
 					#(#inline_interface_id)*
@@ -704,6 +835,7 @@
 					use core::fmt::Write;
 					let interface = SolidityInterface {
 						name: #solidity_name,
+						selector: Self::interface_id(),
 						is: &["Dummy", "ERC165", #(
 							#solidity_is,
 						)* #(
@@ -735,11 +867,14 @@
 					tc.collect(out);
 				}
 			}
-			impl ::evm_coder::Call for #call_name {
+			impl #gen_ref ::evm_coder::Call for #call_name #gen_ref {
 				fn parse(method_id: u32, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {
 					use ::evm_coder::abi::AbiRead;
 					match method_id {
-						::evm_coder::ERC165Call::INTERFACE_ID => return Ok(::evm_coder::ERC165Call::parse(method_id, reader)?.map(Self::ERC165Call)),
+						::evm_coder::ERC165Call::INTERFACE_ID => return Ok(
+							::evm_coder::ERC165Call::parse(method_id, reader)?
+							.map(|c| Self::ERC165Call(c, ::core::marker::PhantomData))
+						),
 						#(
 							#parsers,
 						)*
@@ -751,19 +886,33 @@
 					return Ok(None);
 				}
 			}
-			impl #generics ::evm_coder::Callable<#call_name> for #name {
+			impl #generics ::evm_coder::Weighted for #call_name #gen_ref {
+				#[allow(unused_variables)]
+				fn weight(&self) -> ::evm_coder::execution::DispatchInfo {
+					match self {
+						#(
+							#weight_variants,
+						)*
+						// TODO: It should be very cheap, but not free
+						Self::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {..}, _) => 100u64.into(),
+						#(
+							#weight_variants_this,
+						)*
+					}
+				}
+			}
+			impl #generics ::evm_coder::Callable<#call_name #gen_ref> for #name {
 				#[allow(unreachable_code)] // In case of no inner calls
-				fn call(&mut self, c: Msg<#call_name>) -> Result<::evm_coder::abi::AbiWriter> {
+				fn call(&mut self, c: Msg<#call_name #gen_ref>) -> ::evm_coder::execution::ResultWithPostInfo<::evm_coder::abi::AbiWriter> {
 					use ::evm_coder::abi::AbiWrite;
-					type InternalCall = #call_name;
 					match c.call {
 						#(
 							#call_variants,
 						)*
-						InternalCall::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {interface_id}) => {
+						#call_name::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {interface_id}, _) => {
 							let mut writer = ::evm_coder::abi::AbiWriter::default();
-							writer.bool(&InternalCall::supports_interface(interface_id));
-							return Ok(writer);
+							writer.bool(&<#call_name #gen_ref>::supports_interface(interface_id));
+							return Ok(writer.into());
 						}
 						_ => {},
 					}
@@ -774,7 +923,6 @@
 						)*
 						_ => unreachable!()
 					}
-					Ok(writer)
 				}
 			}
 		}
modifiedcrates/evm-coder-macros/src/to_log.rsdiffbeforeafterboth
--- a/crates/evm-coder-macros/src/to_log.rs
+++ b/crates/evm-coder-macros/src/to_log.rs
@@ -183,6 +183,7 @@
 					use evm_coder::solidity::*;
 					use core::fmt::Write;
 					let interface = SolidityInterface {
+						selector: 0,
 						name: #solidity_name,
 						is: &[],
 						functions: (#(
modifiedcrates/evm-coder/Cargo.tomldiffbeforeafterboth
--- a/crates/evm-coder/Cargo.toml
+++ b/crates/evm-coder/Cargo.toml
@@ -1,14 +1,14 @@
 [package]
 name = "evm-coder"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 evm-coder-macros = { path = "../evm-coder-macros" }
 primitive-types = { version = "0.10.1", default-features = false }
 hex-literal = "0.3.3"
-ethereum = { version = "0.9", git = "https://github.com/purestake/ethereum", branch = "joshy-scale-info", default-features = false }
-evm-core = { default-features = false, git = "https://github.com/uniquenetwork/evm.git", branch="precompile-output-parachain" }
+ethereum = { version = "0.10.0", default-features = false }
+evm-core = { default-features = false, git = "https://github.com/uniquenetwork/evm.git", branch = "unique-weights" }
 impl-trait-for-tuples = "0.2.1"
 
 [dev-dependencies]
modifiedcrates/evm-coder/src/abi.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/abi.rs
+++ b/crates/evm-coder/src/abi.rs
@@ -11,7 +11,10 @@
 use evm_core::ExitError;
 use primitive_types::{H160, U256};
 
-use crate::{execution::Error, types::string};
+use crate::{
+	execution::{Error, ResultWithPostInfo, WithPostDispatchInfo},
+	types::string,
+};
 use crate::execution::Result;
 
 const ABI_ALIGNMENT: usize = 32;
@@ -244,6 +247,7 @@
 }
 
 impl_abi_readable!(u32, uint32);
+impl_abi_readable!(u64, uint64);
 impl_abi_readable!(u128, uint128);
 impl_abi_readable!(U256, uint256);
 impl_abi_readable!(H160, address);
@@ -306,6 +310,36 @@
 
 pub trait AbiWrite {
 	fn abi_write(&self, writer: &mut AbiWriter);
+	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {
+		let mut writer = AbiWriter::new();
+		self.abi_write(&mut writer);
+		Ok(writer.into())
+	}
+}
+
+impl<T: AbiWrite> AbiWrite for ResultWithPostInfo<T> {
+	// 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
+	fn abi_write(&self, _writer: &mut AbiWriter) {
+		debug_assert!(false, "shouldn't be called, see comment")
+	}
+	fn to_result(&self) -> ResultWithPostInfo<AbiWriter> {
+		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 {
modifiedcrates/evm-coder/src/execution.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/execution.rs
+++ b/crates/evm-coder/src/execution.rs
@@ -4,7 +4,9 @@
 #[cfg(feature = "std")]
 use std::string::{String, ToString};
 
-#[derive(Debug)]
+use crate::Weight;
+
+#[derive(Debug, Clone)]
 pub enum Error {
 	Revert(String),
 	Fatal(ExitFatal),
@@ -21,3 +23,55 @@
 }
 
 pub type Result<T> = core::result::Result<T, Error>;
+
+pub struct DispatchInfo {
+	pub weight: Weight,
+}
+
+impl From<Weight> for DispatchInfo {
+	fn from(weight: Weight) -> Self {
+		Self { weight }
+	}
+}
+impl From<()> for DispatchInfo {
+	fn from(_: ()) -> Self {
+		Self { weight: 0 }
+	}
+}
+
+#[derive(Default, Clone)]
+pub struct PostDispatchInfo {
+	actual_weight: Option<Weight>,
+}
+
+impl PostDispatchInfo {
+	pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight {
+		info.weight - self.calc_actual_weight(info)
+	}
+
+	pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight {
+		if let Some(actual_weight) = self.actual_weight {
+			actual_weight.min(info.weight)
+		} else {
+			info.weight
+		}
+	}
+}
+
+#[derive(Clone)]
+pub struct WithPostDispatchInfo<T> {
+	pub data: T,
+	pub post_info: PostDispatchInfo,
+}
+
+impl<T> From<T> for WithPostDispatchInfo<T> {
+	fn from(data: T) -> Self {
+		Self {
+			data,
+			post_info: Default::default(),
+		}
+	}
+}
+
+pub type ResultWithPostInfo<T> =
+	core::result::Result<WithPostDispatchInfo<T>, WithPostDispatchInfo<Error>>;
modifiedcrates/evm-coder/src/lib.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -3,10 +3,11 @@
 extern crate alloc;
 
 use abi::{AbiRead, AbiReader, AbiWriter};
-pub use evm_coder_macros::{event_topic, fn_selector, solidity_interface, solidity, ToLog};
+pub use evm_coder_macros::{event_topic, fn_selector, solidity_interface, solidity, weight, ToLog};
 pub mod abi;
 pub mod events;
 pub use events::ToLog;
+use execution::DispatchInfo;
 pub mod execution;
 pub mod solidity;
 
@@ -57,8 +58,14 @@
 	fn parse(selector: u32, input: &mut AbiReader) -> execution::Result<Option<Self>>;
 }
 
+pub type Weight = u64;
+
+pub trait Weighted: Call {
+	fn weight(&self) -> DispatchInfo;
+}
+
 pub trait Callable<C: Call> {
-	fn call(&mut self, call: types::Msg<C>) -> execution::Result<AbiWriter>;
+	fn call(&mut self, call: types::Msg<C>) -> execution::ResultWithPostInfo<AbiWriter>;
 }
 
 /// Implementation is implicitly provided for all interfaces
@@ -84,15 +91,20 @@
 	}
 }
 
+/// Generate "tests", which will generate solidity code on execution and print it to stdout
+/// Script at .maintain/scripts/generate_api.sh can split this output from test runtime
+///
+/// This macro receives type usage as second argument, but you can use anything as generics,
+/// because no bounds are implied
 #[macro_export]
 macro_rules! generate_stubgen {
-	($name:ident, $decl:ident, $is_impl:literal) => {
+	($name:ident, $decl:ty, $is_impl:literal) => {
 		#[test]
 		#[ignore]
 		fn $name() {
 			use evm_coder::solidity::TypeCollector;
 			let mut out = TypeCollector::new();
-			$decl::generate_solidity_interface(&mut out, $is_impl);
+			<$decl>::generate_solidity_interface(&mut out, $is_impl);
 			println!("=== SNIP START ===");
 			println!("// SPDX-License-Identifier: OTHER");
 			println!("// This code is automatically generated");
modifiedcrates/evm-coder/src/solidity.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/solidity.rs
+++ b/crates/evm-coder/src/solidity.rs
@@ -84,6 +84,7 @@
 solidity_type_name! {
 	uint8 => "uint8" true = "0",
 	uint32 => "uint32" true = "0",
+	uint64 => "uint64" true = "0",
 	uint128 => "uint128" true = "0",
 	uint256 => "uint256" true = "0",
 	address => "address" true = "0x0000000000000000000000000000000000000000",
@@ -376,6 +377,7 @@
 	Mutable,
 }
 pub struct SolidityFunction<A, R> {
+	pub docs: &'static [&'static str],
 	pub selector: &'static str,
 	pub name: &'static str,
 	pub args: A,
@@ -389,6 +391,12 @@
 		writer: &mut impl fmt::Write,
 		tc: &TypeCollector,
 	) -> fmt::Result {
+		for doc in self.docs {
+			writeln!(writer, "\t//{}", doc)?;
+		}
+		if !self.docs.is_empty() {
+			writeln!(writer, "\t//")?;
+		}
 		writeln!(writer, "\t// Selector: {}", self.selector)?;
 		write!(writer, "\tfunction {}(", self.name)?;
 		self.args.solidity_name(writer, tc)?;
@@ -449,6 +457,7 @@
 }
 
 pub struct SolidityInterface<F: SolidityFunctions> {
+	pub selector: u32,
 	pub name: &'static str,
 	pub is: &'static [&'static str],
 	pub functions: F,
@@ -461,6 +470,9 @@
 		out: &mut impl fmt::Write,
 		tc: &TypeCollector,
 	) -> fmt::Result {
+		if self.selector != 0 {
+			writeln!(out, "// Selector: {:0>8x}", self.selector)?;
+		}
 		if is_impl {
 			write!(out, "contract ")?;
 		} else {
deletedcrates/evm-coder/tests/a.rsdiffbeforeafterboth
--- a/crates/evm-coder/tests/a.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-#![allow(dead_code)] // This test only checks that macros is not panicking
-
-use evm_coder::{solidity_interface, types::*, ToLog, execution::Result};
-use evm_coder_macros::solidity;
-
-struct Impls;
-
-#[solidity_interface(name = "OurInterface")]
-impl Impls {
-	fn fn_a(&self, _input: uint256) -> Result<bool> {
-		todo!()
-	}
-}
-
-#[solidity_interface(name = "OurInterface1")]
-impl Impls {
-	fn fn_b(&self, _input: uint128) -> Result<uint32> {
-		todo!()
-	}
-}
-
-#[solidity_interface(
-	name = "OurInterface2",
-	is(OurInterface),
-	inline_is(OurInterface1),
-	events(ERC721Log)
-)]
-impl Impls {
-	#[solidity(rename_selector = "fnK")]
-	fn fn_c(&self, _input: uint32) -> Result<uint8> {
-		todo!()
-	}
-	fn fn_d(&self, _value: uint32) -> Result<uint32> {
-		todo!()
-	}
-
-	fn caller_sensitive(&self, _caller: caller) -> Result<uint8> {
-		todo!()
-	}
-	fn payable(&mut self, _value: value) -> Result<uint8> {
-		todo!()
-	}
-}
-
-#[derive(ToLog)]
-enum ERC721Log {
-	Transfer {
-		#[indexed]
-		from: address,
-		#[indexed]
-		to: address,
-		value: uint256,
-	},
-	Eee {
-		#[indexed]
-		aaa: address,
-		bbb: uint256,
-	},
-}
-
-struct ERC20;
-
-#[solidity_interface(name = "ERC20")]
-impl ERC20 {
-	fn decimals(&self) -> Result<uint8> {
-		todo!()
-	}
-	fn balance_of(&self, _owner: address) -> Result<uint256> {
-		todo!()
-	}
-	fn transfer(&mut self, _caller: caller, _to: address, _value: uint256) -> Result<bool> {
-		todo!()
-	}
-	fn transfer_from(
-		&mut self,
-		_caller: caller,
-		_from: address,
-		_to: address,
-		_value: uint256,
-	) -> Result<bool> {
-		todo!()
-	}
-	fn approve(&mut self, _caller: caller, _spender: address, _value: uint256) -> Result<bool> {
-		todo!()
-	}
-	fn allowance(&self, _owner: address, _spender: address) -> Result<uint256> {
-		todo!()
-	}
-}
addedcrates/evm-coder/tests/generics.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/tests/generics.rs
@@ -0,0 +1,20 @@
+use std::marker::PhantomData;
+use evm_coder::{execution::Result, generate_stubgen, solidity_interface, types::*};
+
+struct Generic<T>(PhantomData<T>);
+
+#[solidity_interface(name = "GenericIs")]
+impl<T> Generic<T> {
+	fn test_1(&self) -> Result<uint256> {
+		todo!()
+	}
+}
+
+#[solidity_interface(name = "Generic", is(GenericIs))]
+impl<T: Into<u32>> Generic<T> {
+	fn test_2(&self) -> Result<uint256> {
+		todo!()
+	}
+}
+
+generate_stubgen!(gen_iface, GenericCall<()>, false);
addedcrates/evm-coder/tests/log.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/tests/log.rs
@@ -0,0 +1,19 @@
+#![allow(dead_code)]
+
+use evm_coder::{ToLog, types::*};
+
+#[derive(ToLog)]
+enum ERC721Log {
+	Transfer {
+		#[indexed]
+		from: address,
+		#[indexed]
+		to: address,
+		value: uint256,
+	},
+	Eee {
+		#[indexed]
+		aaa: address,
+		bbb: uint256,
+	},
+}
addedcrates/evm-coder/tests/random.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/tests/random.rs
@@ -0,0 +1,65 @@
+#![allow(dead_code)] // This test only checks that macros is not panicking
+
+use evm_coder::{ToLog, execution::Result, solidity_interface, types::*};
+use evm_coder_macros::{solidity, weight};
+
+struct Impls;
+
+#[solidity_interface(name = "OurInterface")]
+impl Impls {
+	fn fn_a(&self, _input: uint256) -> Result<bool> {
+		todo!()
+	}
+}
+
+#[solidity_interface(name = "OurInterface1")]
+impl Impls {
+	fn fn_b(&self, _input: uint128) -> Result<uint32> {
+		todo!()
+	}
+}
+
+#[derive(ToLog)]
+enum OurEvents {
+	Event1 {
+		field1: uint32,
+	},
+	Event2 {
+		field1: uint32,
+		#[indexed]
+		field2: uint32,
+	},
+}
+
+#[solidity_interface(
+	name = "OurInterface2",
+	is(OurInterface),
+	inline_is(OurInterface1),
+	events(OurEvents)
+)]
+impl Impls {
+	#[solidity(rename_selector = "fnK")]
+	fn fn_c(&self, _input: uint32) -> Result<uint8> {
+		todo!()
+	}
+	fn fn_d(&self, _value: uint32) -> Result<uint32> {
+		todo!()
+	}
+
+	fn caller_sensitive(&self, _caller: caller) -> Result<uint8> {
+		todo!()
+	}
+	fn payable(&mut self, _value: value) -> Result<uint8> {
+		todo!()
+	}
+
+	#[weight(*_weight)]
+	fn with_weight(&self, _weight: uint64) -> Result<void> {
+		todo!()
+	}
+
+	/// Doccoment example
+	fn with_doc(&self) -> Result<void> {
+		todo!()
+	}
+}
addedcrates/evm-coder/tests/solidity_generation.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/tests/solidity_generation.rs
@@ -0,0 +1,35 @@
+use evm_coder::{execution::Result, generate_stubgen, solidity_interface, types::*};
+
+struct ERC20;
+
+#[solidity_interface(name = "ERC20")]
+impl ERC20 {
+	fn decimals(&self) -> Result<uint8> {
+		todo!()
+	}
+	/// Get balance of specified owner
+	fn balance_of(&self, _owner: address) -> Result<uint256> {
+		todo!()
+	}
+	fn transfer(&mut self, _caller: caller, _to: address, _value: uint256) -> Result<bool> {
+		todo!()
+	}
+	fn transfer_from(
+		&mut self,
+		_caller: caller,
+		_from: address,
+		_to: address,
+		_value: uint256,
+	) -> Result<bool> {
+		todo!()
+	}
+	fn approve(&mut self, _caller: caller, _spender: address, _value: uint256) -> Result<bool> {
+		todo!()
+	}
+	fn allowance(&self, _owner: address, _spender: address) -> Result<uint256> {
+		todo!()
+	}
+}
+
+generate_stubgen!(gen_impl, ERC20Call, true);
+generate_stubgen!(gen_iface, ERC20Call, false);
addedlaunch-config-westend.jsondiffbeforeafterboth
--- /dev/null
+++ b/launch-config-westend.json
@@ -0,0 +1,152 @@
+{
+    "relaychain": {
+        "bin": "../polkadot/target/release/polkadot",
+        "chain": "westend-local",
+        "nodes": [
+            {
+                "name": "alice",
+                "wsPort": 9844,
+                "rpcPort": 9843,
+                "port": 30444,
+                "flags": [
+                    "--rpc-port=9843",
+                    "-lparachain::candidate_validation=debug"
+                ]
+            },
+            {
+                "name": "bob",
+                "wsPort": 9855,
+                "rpcPort": 9854,
+                "port": 30555,
+                "flags": [
+                    "--rpc-port=9854",
+                    "-lparachain::candidate_validation=debug"
+                ]
+            },
+            {
+                "name": "charlie",
+                "wsPort": 9866,
+                "rpcPort": 9865,
+                "port": 30666,
+                "flags": [
+                    "--rpc-port=9865",
+                    "-lparachain::candidate_validation=debug"
+                ]
+            },
+            {
+                "name": "dave",
+                "wsPort": 9877,
+                "rpcPort": 9876,
+                "port": 30777,
+                "flags": [
+                    "--rpc-port=9876",
+                    "-lparachain::candidate_validation=debug"
+                ]
+            },
+            {
+                "name": "eve",
+                "wsPort": 9888,
+                "rpcPort": 9886,
+                "port": 30888,
+                "flags": [
+                    "--rpc-port=9886",
+                    "-lparachain::candidate_validation=debug"
+                ]
+            },
+            {
+                "name": "ferdie",
+                "wsPort": 9897,
+                "rpcPort": 9896,
+                "port": 30999,
+                "flags": [
+                    "--rpc-port=9896",
+                    "-lparachain::candidate_validation=debug"
+                ]
+            }
+        ],
+        "genesis": {
+            "runtime": {
+                "runtime_genesis_config": {
+                    "parachainsConfiguration": {
+                        "config": {
+                            "validation_upgrade_frequency": 1,
+                            "validation_upgrade_delay": 1
+                        }
+                    }
+                }
+            }
+        }
+    },
+    "parachains": [
+        {
+            "bin": "../unique-chain/target/release/unique-collator",
+            "chain": "westend-local",
+            "balance": "1000000000000000000000000",
+            "nodes": [
+                {
+                    "port": 31200,
+                    "wsPort": 9944,
+                    "rpcPort": 9933,
+                    "name": "alice",
+                    "flags": [
+                        "--rpc-cors=all",
+                        "--rpc-port=9933",
+                        "--unsafe-rpc-external",
+                        "--unsafe-ws-external"
+                    ]
+                },
+                {
+                    "port": 31201,
+                    "wsPort": 9945,
+                    "rpcPort": 9934,
+                    "name": "bob",
+                    "flags": [
+                        "--rpc-cors=all",
+                        "--rpc-port=9934",
+                        "--unsafe-rpc-external",
+                        "--unsafe-ws-external"
+                    ]
+                },
+                {
+                    "port": 31202,
+                    "wsPort": 9946,
+                    "rpcPort": 9935,
+                    "name": "charlie",
+                    "flags": [
+                        "--rpc-cors=all",
+                        "--rpc-port=9935",
+                        "--unsafe-rpc-external",
+                        "--unsafe-ws-external"
+                    ]
+                },
+                {
+                    "port": 31203,
+                    "wsPort": 9947,
+                    "rpcPort": 9936,
+                    "name": "dave",
+                    "flags": [
+                        "--rpc-cors=all",
+                        "--rpc-port=9936",
+                        "--unsafe-rpc-external",
+                        "--unsafe-ws-external"
+                    ]
+                },
+                {
+                    "port": 31204,
+                    "wsPort": 9948,
+                    "rpcPort": 9937,
+                    "name": "eve",
+                    "flags": [
+                        "--rpc-cors=all",
+                        "--rpc-port=9937",
+                        "--unsafe-rpc-external",
+                        "--unsafe-ws-external"
+                    ]
+                }
+            ]
+        }
+    ],
+    "simpleParachains": [],
+    "hrmpChannels": [],
+    "finalization": false
+}
modifiedlaunch-config.jsondiffbeforeafterboth
--- a/launch-config.json
+++ b/launch-config.json
@@ -57,7 +57,7 @@
         {
             "bin": "../unique-chain/target/release/unique-collator",
             "id": "2000",
-            "balance": "1000000000000000000000",
+            "balance": "1000000000000000000000000",
             "nodes": [
                 {
                     "port": 31200,
modifiednode/cli/Cargo.tomldiffbeforeafterboth
--- a/node/cli/Cargo.toml
+++ b/node/cli/Cargo.toml
@@ -268,13 +268,13 @@
 jsonrpc-core = '18.0.0'
 jsonrpc-pubsub = "18.0.0"
 
-fc-rpc-core = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-consensus = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-mapping-sync = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-db = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+fc-rpc-core = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-consensus = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-mapping-sync = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-db = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-rpc = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
 
 unique-rpc = { path = "../rpc" }
 
modifiednode/cli/src/chain_spec.rsdiffbeforeafterboth
--- a/node/cli/src/chain_spec.rs
+++ b/node/cli/src/chain_spec.rs
@@ -53,9 +53,9 @@
 
 pub fn development_config(id: ParaId) -> ChainSpec {
 	let mut properties = Map::new();
-	properties.insert("tokenSymbol".into(), "testUNQ".into());
+	properties.insert("tokenSymbol".into(), "OPL".into());
 	properties.insert("tokenDecimals".into(), 15.into());
-	properties.insert("ss58Format".into(), 42.into()); // Generic Substrate wildcard (SS58 checksum preimage)
+	properties.insert("ss58Format".into(), 42.into());
 
 	ChainSpec::from_genesis(
 		// Name
@@ -95,7 +95,7 @@
 	)
 }
 
-pub fn local_testnet_config(id: ParaId) -> ChainSpec {
+pub fn local_testnet_rococo_config(id: ParaId) -> ChainSpec {
 	ChainSpec::from_genesis(
 		// Name
 		"Local Testnet",
@@ -144,6 +144,58 @@
 	)
 }
 
+pub fn local_testnet_westend_config(id: ParaId) -> ChainSpec {
+	ChainSpec::from_genesis(
+		// Name
+		"Local Testnet",
+		// ID
+		"local_testnet",
+		ChainType::Local,
+		move || {
+			testnet_genesis(
+				// Sudo account
+				get_account_id_from_seed::<sr25519::Public>("Alice"),
+				vec![
+					get_from_seed::<AuraId>("Alice"),
+					get_from_seed::<AuraId>("Bob"),
+					get_from_seed::<AuraId>("Charlie"),
+					get_from_seed::<AuraId>("Dave"),
+					get_from_seed::<AuraId>("Eve"),
+				],
+				// Pre-funded accounts
+				vec![
+					get_account_id_from_seed::<sr25519::Public>("Alice"),
+					get_account_id_from_seed::<sr25519::Public>("Bob"),
+					get_account_id_from_seed::<sr25519::Public>("Charlie"),
+					get_account_id_from_seed::<sr25519::Public>("Dave"),
+					get_account_id_from_seed::<sr25519::Public>("Eve"),
+					get_account_id_from_seed::<sr25519::Public>("Ferdie"),
+					get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
+					get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
+					get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
+					get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
+					get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
+					get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
+				],
+				id,
+			)
+		},
+		// Bootnodes
+		vec![],
+		// Telemetry
+		None,
+		// Protocol ID
+		None,
+		// Properties
+		None,
+		// Extensions
+		Extensions {
+			relay_chain: "westend-local".into(),
+			para_id: id.into(),
+		},
+	)
+}
+
 fn testnet_genesis(
 	root_key: AccountId,
 	initial_authorities: Vec<AuraId>,
@@ -161,7 +213,8 @@
 			balances: endowed_accounts
 				.iter()
 				.cloned()
-				.map(|k| (k, 1 << 70))
+				// 1e13 UNQ
+				.map(|k| (k, 1 << 100))
 				.collect(),
 		},
 		treasury: Default::default(),
modifiednode/cli/src/command.rsdiffbeforeafterboth
--- a/node/cli/src/command.rs
+++ b/node/cli/src/command.rs
@@ -42,8 +42,9 @@
 	para_id: ParaId,
 ) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
 	Ok(match id {
+		"westend-local" => Box::new(chain_spec::local_testnet_westend_config(para_id)),
 		"dev" => Box::new(chain_spec::development_config(para_id)),
-		"" | "local" => Box::new(chain_spec::local_testnet_config(para_id)),
+		"" | "local" => Box::new(chain_spec::local_testnet_rococo_config(para_id)),
 		path => Box::new(chain_spec::ChainSpec::from_json_file(
 			std::path::PathBuf::from(path),
 		)?),
@@ -84,7 +85,7 @@
 	}
 
 	fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
-		load_spec(id, self.run.parachain_id.unwrap_or(200).into())
+		load_spec(id, self.run.parachain_id.unwrap_or(2000).into())
 	}
 
 	fn native_runtime_version(_: &Box<dyn ChainSpec>) -> &'static RuntimeVersion {
@@ -217,7 +218,7 @@
 
 			let block: Block = generate_genesis_block(&load_spec(
 				&params.chain.clone().unwrap_or_default(),
-				params.parachain_id.unwrap_or(200).into(),
+				params.parachain_id.unwrap_or(2000).into(),
 			)?)?;
 			let raw_header = block.header().encode();
 			let output_buf = if params.raw {
@@ -280,7 +281,7 @@
 						.chain(cli.relaychain_args.iter()),
 				);
 
-				let id = ParaId::from(cli.run.parachain_id.or(para_id).unwrap_or(200));
+				let id = ParaId::from(cli.run.parachain_id.or(para_id).unwrap_or(2000));
 
 				let parachain_account =
 					AccountIdConversion::<polkadot_primitives::v0::AccountId>::into_account(&id);
modifiednode/rpc/Cargo.tomldiffbeforeafterboth
--- a/node/rpc/Cargo.toml
+++ b/node/rpc/Cargo.toml
@@ -3,7 +3,7 @@
 version = "0.1.0"
 authors = ['Unique Network <support@uniquenetwork.io>']
 license = 'All Rights Reserved'
-edition = "2018"
+edition = "2021"
 description = "Unique chain rpc"
 
 [package.metadata.docs.rs]
@@ -41,12 +41,12 @@
 substrate-frame-rpc-system = { git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 tokio = { version = "0.2.25", features = ["macros", "sync"] }
 
-pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-db = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-db = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
 
 pallet-unique = { path = "../../pallets/unique" }
 uc-rpc = { path = "../../client/rpc" }
modifiednode/rpc/src/lib.rsdiffbeforeafterboth
--- a/node/rpc/src/lib.rs
+++ b/node/rpc/src/lib.rs
@@ -214,7 +214,7 @@
 			500_usize, // max stored filters
 			overrides.clone(),
 			max_past_logs,
-			block_data_cache.clone(),
+			block_data_cache,
 		)));
 	}
 
modifiedpallets/common/Cargo.tomldiffbeforeafterboth
--- a/pallets/common/Cargo.toml
+++ b/pallets/common/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "pallet-common"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies.codec]
 default-features = false
@@ -19,7 +19,7 @@
 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' }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
 serde = { version = "1.0.130", default-features = false }
 scale-info = { version = "1.0.0", default-features = false, features = [
     "derive",
modifiedpallets/common/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/common/src/benchmarking.rs
+++ b/pallets/common/src/benchmarking.rs
@@ -54,7 +54,6 @@
 		variable_on_chain_schema,
 		const_on_chain_schema,
 		meta_update_permission: Default::default(),
-		transfers_enabled: true,
 	})
 	.and_then(CollectionHandle::try_get)
 	.map(cast)
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -1,4 +1,5 @@
 pub use pallet_evm::PrecompileOutput;
+pub use pallet_evm::PrecompileResult;
 use sp_core::{H160, U256};
 
 /// Does not always represent a full collection, for RFT it is either
@@ -6,5 +7,5 @@
 pub trait CommonEvmHandler {
 	const CODE: &'static [u8];
 
-	fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileOutput>;
+	fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileResult>;
 }
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -1,6 +1,7 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 
 use core::ops::{Deref, DerefMut};
+use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
 use sp_std::vec::Vec;
 use account::CrossAccountId;
 use frame_support::{
@@ -8,6 +9,7 @@
 	ensure, fail,
 	traits::{Imbalance, Get, Currency},
 };
+use pallet_evm::GasWeightMapping;
 use up_data_structs::{
 	COLLECTION_NUMBER_LIMIT, Collection, CollectionId, CreateItemData, ExistenceRequirement,
 	MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_COLLECTION_NAME_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
@@ -27,52 +29,54 @@
 pub struct CollectionHandle<T: Config> {
 	pub id: CollectionId,
 	collection: Collection<T::AccountId>,
-	pub recorder: pallet_evm_coder_substrate::SubstrateRecorder<T>,
+	pub recorder: SubstrateRecorder<T>,
+}
+impl<T: Config> WithRecorder<T> for CollectionHandle<T> {
+	fn recorder(&self) -> &SubstrateRecorder<T> {
+		&self.recorder
+	}
+	fn into_recorder(self) -> SubstrateRecorder<T> {
+		self.recorder
+	}
 }
 impl<T: Config> CollectionHandle<T> {
 	pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {
 		<CollectionById<T>>::get(id).map(|collection| Self {
 			id,
 			collection,
-			recorder: pallet_evm_coder_substrate::SubstrateRecorder::new(
-				eth::collection_id_to_address(id),
-				gas_limit,
-			),
+			recorder: SubstrateRecorder::new(eth::collection_id_to_address(id), gas_limit),
 		})
 	}
 	pub fn new(id: CollectionId) -> Option<Self> {
 		Self::new_with_gas_limit(id, u64::MAX)
 	}
 	pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {
-		Ok(Self::new(id).ok_or_else(|| <Error<T>>::CollectionNotFound)?)
-	}
-	pub fn log(&self, log: impl evm_coder::ToLog) -> DispatchResult {
-		self.recorder.log_sub(log)
-	}
-	pub fn log_infallible(&self, log: impl evm_coder::ToLog) {
-		self.recorder.log_infallible(log)
+		Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)
 	}
-	#[allow(dead_code)]
-	fn consume_gas(&self, gas: u64) -> DispatchResult {
-		self.recorder.consume_gas_sub(gas)
-	}
-	pub fn consume_sload(&self) -> DispatchResult {
-		self.recorder.consume_sload_sub()
-	}
-	pub fn consume_sstores(&self, amount: usize) -> DispatchResult {
-		self.recorder.consume_sstores_sub(amount)
+	pub fn log(&self, log: impl evm_coder::ToLog) {
+		self.recorder.log(log)
 	}
-	pub fn consume_sstore(&self) -> DispatchResult {
-		self.recorder.consume_sstore_sub()
+	pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {
+		self.recorder
+			.consume_gas(T::GasWeightMapping::weight_to_gas(
+				<T as frame_system::Config>::DbWeight::get()
+					.read
+					.saturating_mul(reads),
+			))
 	}
-	pub fn consume_log(&self, topics: usize, data: usize) -> DispatchResult {
-		self.recorder.consume_log_sub(topics, data)
+	pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {
+		self.recorder
+			.consume_gas(T::GasWeightMapping::weight_to_gas(
+				<T as frame_system::Config>::DbWeight::get()
+					.write
+					.saturating_mul(writes),
+			))
 	}
-	pub fn submit_logs(self) -> DispatchResult {
+	pub fn submit_logs(self) {
 		self.recorder.submit_logs()
 	}
 	pub fn save(self) -> DispatchResult {
-		self.recorder.submit_logs()?;
+		self.recorder.submit_logs();
 		<CollectionById<T>>::insert(self.id, self.collection);
 		Ok(())
 	}
@@ -96,24 +100,20 @@
 		ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);
 		Ok(())
 	}
-	pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> Result<bool, DispatchError> {
-		self.consume_sload()?;
-
-		Ok(*subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject)))
+	pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool {
+		*subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))
 	}
 	pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {
-		ensure!(self.is_owner_or_admin(subject)?, <Error<T>>::NoPermission);
+		ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);
 		Ok(())
 	}
-	pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> Result<bool, DispatchError> {
-		Ok(self.limits.owner_can_transfer() && self.is_owner_or_admin(user)?)
+	pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {
+		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)
 	}
-	pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> Result<bool, DispatchError> {
-		Ok(self.limits.owner_can_transfer() && self.is_owner_or_admin(user)?)
+	pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {
+		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)
 	}
 	pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {
-		self.consume_sload()?;
-
 		ensure!(
 			<Allowlist<T>>::get((self.id, user)),
 			<Error<T>>::AddressNotInAllowlist
@@ -187,6 +187,13 @@
 		/// * account_id: Collection owner.
 		CollectionCreated(CollectionId, u8, T::AccountId),
 
+		/// New collection was destroyed
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique identifier of collection.
+		CollectionDestroyed(CollectionId),
+
 		/// New item was created.
 		///
 		/// # Arguments
@@ -410,7 +417,7 @@
 
 		// bound Total number of collections
 		ensure!(
-			created_count - destroyed_count < COLLECTION_NUMBER_LIMIT,
+			created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,
 			<Error<T>>::TotalCollectionsLimitExceeded
 		);
 
@@ -453,7 +460,7 @@
 			collection.limits.owner_can_destroy(),
 			<Error<T>>::NoPermission,
 		);
-		collection.check_is_owner(&sender)?;
+		collection.check_is_owner(sender)?;
 
 		let destroyed_collections = <DestroyedCollectionCount<T>>::get()
 			.0
@@ -467,6 +474,8 @@
 		<AdminAmount<T>>::remove(collection.id);
 		<IsAdmin<T>>::remove_prefix((collection.id,), None);
 		<Allowlist<T>>::remove_prefix((collection.id,), None);
+
+		<Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));
 		Ok(())
 	}
 
@@ -476,7 +485,7 @@
 		user: &T::CrossAccountId,
 		allowed: bool,
 	) -> DispatchResult {
-		collection.check_is_owner_or_admin(&sender)?;
+		collection.check_is_owner_or_admin(sender)?;
 
 		// =========
 
@@ -495,7 +504,7 @@
 		user: &T::CrossAccountId,
 		admin: bool,
 	) -> DispatchResult {
-		collection.check_is_owner_or_admin(&sender)?;
+		collection.check_is_owner_or_admin(sender)?;
 
 		let was_admin = <IsAdmin<T>>::get((collection.id, user));
 		if was_admin == admin {
modifiedpallets/contract-helpers/Cargo.tomldiffbeforeafterboth
--- a/pallets/contract-helpers/Cargo.toml
+++ b/pallets/contract-helpers/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "pallet-contract-helpers"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies.codec]
 default-features = false
@@ -16,7 +16,7 @@
 pallet-contracts = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
-up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/UniqueNetwork/pallet-sponsoring" } 
+up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/UniqueNetwork/pallet-sponsoring" }
 
 [features]
 default = ["std"]
modifiedpallets/evm-coder-substrate/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-coder-substrate/Cargo.toml
+++ b/pallets/evm-coder-substrate/Cargo.toml
@@ -1,18 +1,21 @@
 [package]
 name = "pallet-evm-coder-substrate"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
-scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
+scale-info = { version = "1.0.0", default-features = false, features = [
+    "derive",
+] }
 sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
-ethereum = { version = "0.9", git = "https://github.com/purestake/ethereum", branch = "joshy-scale-info", default-features = false }
+ethereum = { version = "0.10.0", default-features = false }
 evm-coder = { default-features = false, path = "../../crates/evm-coder" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
 frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
+frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 
 [dependencies.codec]
 default-features = false
@@ -31,4 +34,6 @@
     "pallet-evm/std",
     "frame-support/std",
     "frame-system/std",
+    'frame-benchmarking/std',
 ]
+runtime-benchmarks = ['frame-benchmarking']
addedpallets/evm-coder-substrate/src/benchmarking.rsdiffbeforeafterboth
--- /dev/null
+++ b/pallets/evm-coder-substrate/src/benchmarking.rs
@@ -0,0 +1,8 @@
+use super::*;
+
+use frame_benchmarking::benchmarks;
+
+benchmarks! {
+	// gas_per_second {
+	// }: (pallet_evm::)
+}
modifiedpallets/evm-coder-substrate/src/lib.rsdiffbeforeafterboth
--- a/pallets/evm-coder-substrate/src/lib.rs
+++ b/pallets/evm-coder-substrate/src/lib.rs
@@ -2,6 +2,8 @@
 
 #[cfg(not(feature = "std"))]
 extern crate alloc;
+// #[cfg(feature = "runtime-benchmarks")]
+// pub mod benchmarking;
 
 pub use pallet::*;
 
@@ -17,7 +19,11 @@
 		types::{Msg, value},
 	};
 	use frame_support::{ensure};
-	use pallet_evm::{ExitError, ExitReason, ExitRevert, ExitSucceed, PrecompileOutput};
+	use pallet_evm::{
+		ExitError, ExitRevert, ExitSucceed, GasWeightMapping, PrecompileFailure, PrecompileOutput,
+		PrecompileResult,
+	};
+	use frame_system::ensure_signed;
 	pub use frame_support::dispatch::DispatchResult;
 	use pallet_ethereum::EthereumTransactionSender;
 	use sp_std::cell::RefCell;
@@ -25,6 +31,7 @@
 	use sp_core::{H160, H256};
 	use ethereum::Log;
 	use frame_support::{pallet_prelude::*, traits::PalletInfo};
+	use frame_system::pallet_prelude::*;
 
 	/// DispatchError is opaque, but we need to somehow extract correct error in case of OutOfGas failure
 	/// So we have this pallet, which defines OutOfGas error, and knews its own id to check if DispatchError
@@ -40,26 +47,25 @@
 	#[pallet::config]
 	pub trait Config: frame_system::Config {
 		type EthereumTransactionSender: pallet_ethereum::EthereumTransactionSender;
+		type GasWeightMapping: pallet_evm::GasWeightMapping;
 	}
 
 	#[pallet::pallet]
 	pub struct Pallet<T>(_);
 
-	// FIXME: those items are defined as private in evm_gasometer::consts, and we can't directly use it
-	pub const G_LOG: u64 = 375;
-	pub const G_LOGDATA: u64 = 8;
-	pub const G_LOGTOPIC: u64 = 375;
+	#[pallet::call]
+	impl<T: Config> Pallet<T> {
+		#[pallet::weight(0)]
+		pub fn empty_call(origin: OriginFor<T>) -> DispatchResult {
+			let _sender = ensure_signed(origin)?;
+			Ok(())
+		}
+	}
 
 	// From instabul hardfork configuration: https://github.com/rust-blockchain/evm/blob/fd4fd6acc0ca3208d6770fdb3ba407c94cdf97c6/runtime/src/lib.rs#L284
 	pub const G_SLOAD_WORD: u64 = 800;
 	pub const G_SSTORE_WORD: u64 = 20000;
 
-	fn log_price(data: usize, topics: usize) -> u64 {
-		G_LOG
-			.saturating_add((data as u64).saturating_mul(G_LOGDATA))
-			.saturating_add((topics as u64).saturating_mul(G_LOGTOPIC))
-	}
-
 	pub fn generate_transaction() -> ethereum::TransactionV0 {
 		use ethereum::{TransactionV0, TransactionAction, TransactionSignature};
 		TransactionV0 {
@@ -97,17 +103,11 @@
 
 		pub fn is_empty(&self) -> bool {
 			self.logs.borrow().is_empty()
-		}
-		pub fn log_sub(&self, log: impl ToLog) -> DispatchResult {
-			self.log_raw_sub(log.to_log(self.contract))
 		}
-		pub fn log_raw_sub(&self, log: Log) -> DispatchResult {
-			self.consume_gas_sub(log_price(log.data.len(), log.topics.len()))?;
-			self.logs.borrow_mut().push(log);
-			Ok(())
-		}
+		// TODO: Replace with real storage in pallet-ethereum,
+		// same way as it is done with frame_system's Events
 		/// Doesn't consumes any gas, should be used after consume_log_sub
-		pub fn log_infallible(&self, log: impl ToLog) {
+		pub fn log(&self, log: impl ToLog) {
 			self.logs.borrow_mut().push(log.to_log(self.contract));
 		}
 		pub fn retrieve_logs(self) -> Vec<Log> {
@@ -125,9 +125,6 @@
 		}
 		pub fn consume_sstore_sub(&self) -> DispatchResult {
 			self.consume_gas_sub(G_SSTORE_WORD)
-		}
-		pub fn consume_log_sub(&self, topics: usize, data: usize) -> DispatchResult {
-			self.consume_gas_sub(log_price(data, topics))
 		}
 		pub fn consume_gas_sub(&self, gas: u64) -> DispatchResult {
 			ensure!(gas != u64::MAX, Error::<T>::OutOfGas);
@@ -154,39 +151,49 @@
 			*gas_limit -= gas;
 			Ok(())
 		}
+		pub fn return_gas(&self, gas: u64) {
+			let mut gas_limit = self.gas_limit.borrow_mut();
+			*gas_limit += gas;
+		}
 
 		pub fn evm_to_precompile_output(
 			self,
 			result: evm_coder::execution::Result<Option<AbiWriter>>,
-		) -> Option<PrecompileOutput> {
+		) -> Option<PrecompileResult> {
 			use evm_coder::execution::Error;
-			let (writer, reason) = match result {
-				Ok(Some(v)) => (v, ExitReason::Succeed(ExitSucceed::Returned)),
+			Some(match result {
+				Ok(Some(v)) => Ok(PrecompileOutput {
+					exit_status: ExitSucceed::Returned,
+					cost: self.initial_gas - self.gas_left(),
+					logs: self.retrieve_logs(),
+					output: v.finish(),
+				}),
 				Ok(None) => return None,
 				Err(Error::Revert(e)) => {
 					let mut writer = AbiWriter::new_call(evm_coder::fn_selector!(Error(string)));
 					(&e as &str).abi_write(&mut writer);
 
-					(writer, ExitReason::Revert(ExitRevert::Reverted))
+					Err(PrecompileFailure::Revert {
+						exit_status: ExitRevert::Reverted,
+						cost: self.initial_gas - self.gas_left(),
+						output: writer.finish(),
+					})
 				}
-				Err(Error::Fatal(f)) => (AbiWriter::new(), ExitReason::Fatal(f)),
-				Err(Error::Error(e)) => (AbiWriter::new(), ExitReason::Error(e)),
-			};
-
-			Some(PrecompileOutput {
-				cost: self.initial_gas - self.gas_left(),
-				exit_status: reason,
-				logs: self.retrieve_logs(),
-				output: writer.finish(),
+				Err(Error::Fatal(f)) => Err(f.into()),
+				Err(Error::Error(e)) => Err(e.into()),
 			})
 		}
 
-		pub fn submit_logs(self) -> DispatchResult {
+		pub fn submit_logs(self) {
 			let logs = self.retrieve_logs();
 			if logs.is_empty() {
-				return Ok(());
+				return;
 			}
-			T::EthereumTransactionSender::submit_logs_transaction(generate_transaction(), logs)
+			T::EthereumTransactionSender::submit_logs_transaction(
+				Default::default(),
+				generate_transaction(),
+				logs,
+			)
 		}
 	}
 
@@ -215,8 +222,32 @@
 		}
 	}
 
-	pub fn call_internal<C: evm_coder::Call, E: evm_coder::Callable<C>>(
+	pub trait WithRecorder<T: Config> {
+		fn recorder(&self) -> &SubstrateRecorder<T>;
+		fn into_recorder(self) -> SubstrateRecorder<T>;
+	}
+
+	/// Helper to simplify implementing bridge between evm-coder definitions and pallet-evm
+	pub fn call<
+		T: Config,
+		C: evm_coder::Call + evm_coder::Weighted,
+		E: evm_coder::Callable<C> + WithRecorder<T>,
+	>(
 		caller: H160,
+		mut e: E,
+		value: value,
+		input: &[u8],
+	) -> Option<PrecompileResult> {
+		let result = call_internal(caller, &mut e, value, input);
+		e.into_recorder().evm_to_precompile_output(result)
+	}
+
+	fn call_internal<
+		T: Config,
+		C: evm_coder::Call + evm_coder::Weighted,
+		E: evm_coder::Callable<C> + WithRecorder<T>,
+	>(
+		caller: H160,
 		e: &mut E,
 		value: value,
 		input: &[u8],
@@ -227,11 +258,28 @@
 			return Ok(None);
 		}
 		let call = call.unwrap();
-		e.call(Msg {
+
+		let dispatch_info = call.weight();
+		e.recorder()
+			.consume_gas(T::GasWeightMapping::weight_to_gas(dispatch_info.weight))?;
+
+		match e.call(Msg {
 			call,
 			caller,
 			value,
-		})
-		.map(Some)
+		}) {
+			Ok(v) => {
+				let unspent = v.post_info.calc_unspent(&dispatch_info);
+				e.recorder()
+					.return_gas(T::GasWeightMapping::weight_to_gas(unspent));
+				Ok(Some(v.data))
+			}
+			Err(v) => {
+				let unspent = v.post_info.calc_unspent(&dispatch_info);
+				e.recorder()
+					.return_gas(T::GasWeightMapping::weight_to_gas(unspent));
+				Err(v.data)
+			}
+		}
 	}
 }
modifiedpallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/Cargo.toml
+++ b/pallets/evm-contract-helpers/Cargo.toml
@@ -1,10 +1,12 @@
 [package]
 name = "pallet-evm-contract-helpers"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
-scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
+scale-info = { version = "1.0.0", default-features = false, features = [
+    "derive",
+] }
 frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
@@ -12,8 +14,8 @@
 sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 evm-coder = { default-features = false, path = '../../crates/evm-coder' }
 pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/UniqueNetwork/pallet-sponsoring" } 
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/UniqueNetwork/pallet-sponsoring" }
 log = "0.4.14"
 
 [dependencies.codec]
addedpallets/evm-contract-helpers/exp.rsdiffbeforeafterboth
--- /dev/null
+++ b/pallets/evm-contract-helpers/exp.rs
@@ -0,0 +1,1474 @@
+#![feature(prelude_import)]
+#[prelude_import]
+use std::prelude::rust_2018::*;
+#[macro_use]
+extern crate std;
+pub use pallet::*;
+pub use eth::*;
+pub mod eth {
+    use core::marker::PhantomData;
+    use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};
+    use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
+    use pallet_evm::{ExitReason, ExitRevert, OnCreate, OnMethodCall, PrecompileOutput};
+    use sp_core::H160;
+    use crate::{
+        AllowlistEnabled, Config, Owner, Pallet, SelfSponsoring, SponsorBasket, SponsoringRateLimit,
+    };
+    use frame_support::traits::Get;
+    use up_sponsorship::SponsorshipHandler;
+    use sp_std::{convert::TryInto, vec::Vec};
+    struct ContractHelpers<T: Config>(SubstrateRecorder<T>);
+    impl<T: Config> WithRecorder<T> for ContractHelpers<T> {
+        fn recorder(&self) -> &SubstrateRecorder<T> {
+            &self.0
+        }
+        fn into_recorder(self) -> SubstrateRecorder<T> {
+            self.0
+        }
+    }
+    impl<T: Config> ContractHelpers<T> {
+        fn contract_owner(&self, contract_address: address) -> Result<address> {
+            Ok(<Owner<T>>::get(contract_address))
+        }
+        fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {
+            Ok(<SelfSponsoring<T>>::get(contract_address))
+        }
+        fn toggle_sponsoring(
+            &mut self,
+            caller: caller,
+            contract_address: address,
+            enabled: bool,
+        ) -> Result<void> {
+            <Pallet<T>>::ensure_owner(contract_address, caller)?;
+            <Pallet<T>>::toggle_sponsoring(contract_address, enabled);
+            Ok(())
+        }
+        fn set_sponsoring_rate_limit(
+            &mut self,
+            caller: caller,
+            contract_address: address,
+            rate_limit: uint32,
+        ) -> Result<void> {
+            <Pallet<T>>::ensure_owner(contract_address, caller)?;
+            <Pallet<T>>::set_sponsoring_rate_limit(contract_address, rate_limit.into());
+            Ok(())
+        }
+        fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {
+            Ok(<SponsoringRateLimit<T>>::get(contract_address)
+                .try_into()
+                .map_err(|_| "rate limit > u32::MAX")?)
+        }
+        fn allowed(&self, contract_address: address, user: address) -> Result<bool> {
+            Ok(<Pallet<T>>::allowed(contract_address, user, true))
+        }
+        fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {
+            Ok(<AllowlistEnabled<T>>::get(contract_address))
+        }
+        fn toggle_allowlist(
+            &mut self,
+            caller: caller,
+            contract_address: address,
+            enabled: bool,
+        ) -> Result<void> {
+            <Pallet<T>>::ensure_owner(contract_address, caller)?;
+            <Pallet<T>>::toggle_allowlist(contract_address, enabled);
+            Ok(())
+        }
+        fn toggle_allowed(
+            &mut self,
+            caller: caller,
+            contract_address: address,
+            user: address,
+            allowed: bool,
+        ) -> Result<void> {
+            <Pallet<T>>::ensure_owner(contract_address, caller)?;
+            <Pallet<T>>::toggle_allowed(contract_address, user, allowed);
+            Ok(())
+        }
+    }
+    pub enum ContractHelpersCall<T: Config> {
+        ERC165Call(::evm_coder::ERC165Call, PhantomData<(T)>),
+        ContractOwner {
+            contract_address: address,
+        },
+        SponsoringEnabled {
+            contract_address: address,
+        },
+        ToggleSponsoring {
+            contract_address: address,
+            enabled: bool,
+        },
+        SetSponsoringRateLimit {
+            contract_address: address,
+            rate_limit: uint32,
+        },
+        GetSponsoringRateLimit {
+            contract_address: address,
+        },
+        Allowed {
+            contract_address: address,
+            user: address,
+        },
+        AllowlistEnabled {
+            contract_address: address,
+        },
+        ToggleAllowlist {
+            contract_address: address,
+            enabled: bool,
+        },
+        ToggleAllowed {
+            contract_address: address,
+            user: address,
+            allowed: bool,
+        },
+    }
+    #[automatically_derived]
+    #[allow(unused_qualifications)]
+    impl<T: ::core::fmt::Debug + Config> ::core::fmt::Debug for ContractHelpersCall<T> {
+        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+            match (&*self,) {
+                (&ContractHelpersCall::ERC165Call(ref __self_0, ref __self_1),) => {
+                    let debug_trait_builder =
+                        &mut ::core::fmt::Formatter::debug_tuple(f, "ERC165Call");
+                    let _ = ::core::fmt::DebugTuple::field(debug_trait_builder, &&(*__self_0));
+                    let _ = ::core::fmt::DebugTuple::field(debug_trait_builder, &&(*__self_1));
+                    ::core::fmt::DebugTuple::finish(debug_trait_builder)
+                }
+                (&ContractHelpersCall::ContractOwner {
+                    contract_address: ref __self_0,
+                },) => {
+                    let debug_trait_builder =
+                        &mut ::core::fmt::Formatter::debug_struct(f, "ContractOwner");
+                    let _ = ::core::fmt::DebugStruct::field(
+                        debug_trait_builder,
+                        "contract_address",
+                        &&(*__self_0),
+                    );
+                    ::core::fmt::DebugStruct::finish(debug_trait_builder)
+                }
+                (&ContractHelpersCall::SponsoringEnabled {
+                    contract_address: ref __self_0,
+                },) => {
+                    let debug_trait_builder =
+                        &mut ::core::fmt::Formatter::debug_struct(f, "SponsoringEnabled");
+                    let _ = ::core::fmt::DebugStruct::field(
+                        debug_trait_builder,
+                        "contract_address",
+                        &&(*__self_0),
+                    );
+                    ::core::fmt::DebugStruct::finish(debug_trait_builder)
+                }
+                (&ContractHelpersCall::ToggleSponsoring {
+                    contract_address: ref __self_0,
+                    enabled: ref __self_1,
+                },) => {
+                    let debug_trait_builder =
+                        &mut ::core::fmt::Formatter::debug_struct(f, "ToggleSponsoring");
+                    let _ = ::core::fmt::DebugStruct::field(
+                        debug_trait_builder,
+                        "contract_address",
+                        &&(*__self_0),
+                    );
+                    let _ = ::core::fmt::DebugStruct::field(
+                        debug_trait_builder,
+                        "enabled",
+                        &&(*__self_1),
+                    );
+                    ::core::fmt::DebugStruct::finish(debug_trait_builder)
+                }
+                (&ContractHelpersCall::SetSponsoringRateLimit {
+                    contract_address: ref __self_0,
+                    rate_limit: ref __self_1,
+                },) => {
+                    let debug_trait_builder =
+                        &mut ::core::fmt::Formatter::debug_struct(f, "SetSponsoringRateLimit");
+                    let _ = ::core::fmt::DebugStruct::field(
+                        debug_trait_builder,
+                        "contract_address",
+                        &&(*__self_0),
+                    );
+                    let _ = ::core::fmt::DebugStruct::field(
+                        debug_trait_builder,
+                        "rate_limit",
+                        &&(*__self_1),
+                    );
+                    ::core::fmt::DebugStruct::finish(debug_trait_builder)
+                }
+                (&ContractHelpersCall::GetSponsoringRateLimit {
+                    contract_address: ref __self_0,
+                },) => {
+                    let debug_trait_builder =
+                        &mut ::core::fmt::Formatter::debug_struct(f, "GetSponsoringRateLimit");
+                    let _ = ::core::fmt::DebugStruct::field(
+                        debug_trait_builder,
+                        "contract_address",
+                        &&(*__self_0),
+                    );
+                    ::core::fmt::DebugStruct::finish(debug_trait_builder)
+                }
+                (&ContractHelpersCall::Allowed {
+                    contract_address: ref __self_0,
+                    user: ref __self_1,
+                },) => {
+                    let debug_trait_builder =
+                        &mut ::core::fmt::Formatter::debug_struct(f, "Allowed");
+                    let _ = ::core::fmt::DebugStruct::field(
+                        debug_trait_builder,
+                        "contract_address",
+                        &&(*__self_0),
+                    );
+                    let _ =
+                        ::core::fmt::DebugStruct::field(debug_trait_builder, "user", &&(*__self_1));
+                    ::core::fmt::DebugStruct::finish(debug_trait_builder)
+                }
+                (&ContractHelpersCall::AllowlistEnabled {
+                    contract_address: ref __self_0,
+                },) => {
+                    let debug_trait_builder =
+                        &mut ::core::fmt::Formatter::debug_struct(f, "AllowlistEnabled");
+                    let _ = ::core::fmt::DebugStruct::field(
+                        debug_trait_builder,
+                        "contract_address",
+                        &&(*__self_0),
+                    );
+                    ::core::fmt::DebugStruct::finish(debug_trait_builder)
+                }
+                (&ContractHelpersCall::ToggleAllowlist {
+                    contract_address: ref __self_0,
+                    enabled: ref __self_1,
+                },) => {
+                    let debug_trait_builder =
+                        &mut ::core::fmt::Formatter::debug_struct(f, "ToggleAllowlist");
+                    let _ = ::core::fmt::DebugStruct::field(
+                        debug_trait_builder,
+                        "contract_address",
+                        &&(*__self_0),
+                    );
+                    let _ = ::core::fmt::DebugStruct::field(
+                        debug_trait_builder,
+                        "enabled",
+                        &&(*__self_1),
+                    );
+                    ::core::fmt::DebugStruct::finish(debug_trait_builder)
+                }
+                (&ContractHelpersCall::ToggleAllowed {
+                    contract_address: ref __self_0,
+                    user: ref __self_1,
+                    allowed: ref __self_2,
+                },) => {
+                    let debug_trait_builder =
+                        &mut ::core::fmt::Formatter::debug_struct(f, "ToggleAllowed");
+                    let _ = ::core::fmt::DebugStruct::field(
+                        debug_trait_builder,
+                        "contract_address",
+                        &&(*__self_0),
+                    );
+                    let _ =
+                        ::core::fmt::DebugStruct::field(debug_trait_builder, "user", &&(*__self_1));
+                    let _ = ::core::fmt::DebugStruct::field(
+                        debug_trait_builder,
+                        "allowed",
+                        &&(*__self_2),
+                    );
+                    ::core::fmt::DebugStruct::finish(debug_trait_builder)
+                }
+            }
+        }
+    }
+    impl<T: Config> ContractHelpersCall<T> {
+        #[doc = "contractOwner(address)"]
+        const CONTRACT_OWNER: u32 = 1364373836u32;
+        #[doc = "sponsoringEnabled(address)"]
+        const SPONSORING_ENABLED: u32 = 1613225057u32;
+        #[doc = "toggleSponsoring(address,bool)"]
+        const TOGGLE_SPONSORING: u32 = 4239158662u32;
+        #[doc = "setSponsoringRateLimit(address,uint32)"]
+        const SET_SPONSORING_RATE_LIMIT: u32 = 2008467720u32;
+        #[doc = "getSponsoringRateLimit(address)"]
+        const GET_SPONSORING_RATE_LIMIT: u32 = 1628240573u32;
+        #[doc = "allowed(address,address)"]
+        const ALLOWED: u32 = 1550156133u32;
+        #[doc = "allowlistEnabled(address)"]
+        const ALLOWLIST_ENABLED: u32 = 3346198380u32;
+        #[doc = "toggleAllowlist(address,bool)"]
+        const TOGGLE_ALLOWLIST: u32 = 920527093u32;
+        #[doc = "toggleAllowed(address,address,bool)"]
+        const TOGGLE_ALLOWED: u32 = 1191627804u32;
+        pub const fn interface_id() -> u32 {
+            let mut interface_id = 0;
+            interface_id ^= Self::CONTRACT_OWNER;
+            interface_id ^= Self::SPONSORING_ENABLED;
+            interface_id ^= Self::TOGGLE_SPONSORING;
+            interface_id ^= Self::SET_SPONSORING_RATE_LIMIT;
+            interface_id ^= Self::GET_SPONSORING_RATE_LIMIT;
+            interface_id ^= Self::ALLOWED;
+            interface_id ^= Self::ALLOWLIST_ENABLED;
+            interface_id ^= Self::TOGGLE_ALLOWLIST;
+            interface_id ^= Self::TOGGLE_ALLOWED;
+            interface_id
+        }
+        pub fn supports_interface(interface_id: u32) -> bool {
+            interface_id != 0xffffff
+                && (interface_id == ::evm_coder::ERC165Call::INTERFACE_ID
+                    || interface_id == Self::interface_id())
+        }
+        pub fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector, is_impl: bool) {
+            use evm_coder::solidity::*;
+            use core::fmt::Write;
+            let interface = SolidityInterface {
+                name: "ContractHelpers",
+                selector: Self::interface_id(),
+                is: &["Dummy", "ERC165"],
+                functions: (
+                    SolidityFunction {
+                        docs: &[],
+                        selector: "contractOwner(address) 5152b14c",
+                        name: "contractOwner",
+                        mutability: SolidityMutability::View,
+                        args: (<NamedArgument<address>>::new("contractAddress"),),
+                        result: <UnnamedArgument<address>>::default(),
+                    },
+                    SolidityFunction {
+                        docs: &[],
+                        selector: "sponsoringEnabled(address) 6027dc61",
+                        name: "sponsoringEnabled",
+                        mutability: SolidityMutability::View,
+                        args: (<NamedArgument<address>>::new("contractAddress"),),
+                        result: <UnnamedArgument<bool>>::default(),
+                    },
+                    SolidityFunction {
+                        docs: &[],
+                        selector: "toggleSponsoring(address,bool) fcac6d86",
+                        name: "toggleSponsoring",
+                        mutability: SolidityMutability::Mutable,
+                        args: (
+                            <NamedArgument<address>>::new("contractAddress"),
+                            <NamedArgument<bool>>::new("enabled"),
+                        ),
+                        result: <UnnamedArgument<void>>::default(),
+                    },
+                    SolidityFunction {
+                        docs: &[],
+                        selector: "setSponsoringRateLimit(address,uint32) 77b6c908",
+                        name: "setSponsoringRateLimit",
+                        mutability: SolidityMutability::Mutable,
+                        args: (
+                            <NamedArgument<address>>::new("contractAddress"),
+                            <NamedArgument<uint32>>::new("rateLimit"),
+                        ),
+                        result: <UnnamedArgument<void>>::default(),
+                    },
+                    SolidityFunction {
+                        docs: &[],
+                        selector: "getSponsoringRateLimit(address) 610cfabd",
+                        name: "getSponsoringRateLimit",
+                        mutability: SolidityMutability::View,
+                        args: (<NamedArgument<address>>::new("contractAddress"),),
+                        result: <UnnamedArgument<uint32>>::default(),
+                    },
+                    SolidityFunction {
+                        docs: &[],
+                        selector: "allowed(address,address) 5c658165",
+                        name: "allowed",
+                        mutability: SolidityMutability::View,
+                        args: (
+                            <NamedArgument<address>>::new("contractAddress"),
+                            <NamedArgument<address>>::new("user"),
+                        ),
+                        result: <UnnamedArgument<bool>>::default(),
+                    },
+                    SolidityFunction {
+                        docs: &[],
+                        selector: "allowlistEnabled(address) c772ef6c",
+                        name: "allowlistEnabled",
+                        mutability: SolidityMutability::View,
+                        args: (<NamedArgument<address>>::new("contractAddress"),),
+                        result: <UnnamedArgument<bool>>::default(),
+                    },
+                    SolidityFunction {
+                        docs: &[],
+                        selector: "toggleAllowlist(address,bool) 36de20f5",
+                        name: "toggleAllowlist",
+                        mutability: SolidityMutability::Mutable,
+                        args: (
+                            <NamedArgument<address>>::new("contractAddress"),
+                            <NamedArgument<bool>>::new("enabled"),
+                        ),
+                        result: <UnnamedArgument<void>>::default(),
+                    },
+                    SolidityFunction {
+                        docs: &[],
+                        selector: "toggleAllowed(address,address,bool) 4706cc1c",
+                        name: "toggleAllowed",
+                        mutability: SolidityMutability::Mutable,
+                        args: (
+                            <NamedArgument<address>>::new("contractAddress"),
+                            <NamedArgument<address>>::new("user"),
+                            <NamedArgument<bool>>::new("allowed"),
+                        ),
+                        result: <UnnamedArgument<void>>::default(),
+                    },
+                ),
+            };
+            if is_impl {
+                tc . collect ("// Common stubs holder\ncontract Dummy {\n\tuint8 dummy;\n\tstring stub_error = \"this contract is implemented in native\";\n}\ncontract ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool) {\n\t\trequire(false, stub_error);\n\t\tinterfaceID;\n\t\treturn true;\n\t}\n}\n" . into ()) ;
+            } else {
+                tc . collect ("// Common stubs holder\ninterface Dummy {\n}\ninterface ERC165 is Dummy {\n\tfunction supportsInterface(bytes4 interfaceID) external view returns (bool);\n}\n" . into ()) ;
+            }
+            let mut out = string::new();
+            if "ContractHelpers".starts_with("Inline") {
+                out.push_str("// Inline\n");
+            }
+            let _ = interface.format(is_impl, &mut out, tc);
+            tc.collect(out);
+        }
+    }
+    impl<T: Config> ::evm_coder::Call for ContractHelpersCall<T> {
+        fn parse(
+            method_id: u32,
+            reader: &mut ::evm_coder::abi::AbiReader,
+        ) -> ::evm_coder::execution::Result<Option<Self>> {
+            use ::evm_coder::abi::AbiRead;
+            match method_id {
+                ::evm_coder::ERC165Call::INTERFACE_ID => {
+                    return Ok(
+                        ::evm_coder::ERC165Call::parse(method_id, reader)?.map(Self::ERC165Call)
+                    )
+                }
+                Self::CONTRACT_OWNER => {
+                    return Ok(Some(Self::ContractOwner {
+                        contract_address: reader.abi_read()?,
+                    }))
+                }
+                Self::SPONSORING_ENABLED => {
+                    return Ok(Some(Self::SponsoringEnabled {
+                        contract_address: reader.abi_read()?,
+                    }))
+                }
+                Self::TOGGLE_SPONSORING => {
+                    return Ok(Some(Self::ToggleSponsoring {
+                        contract_address: reader.abi_read()?,
+                        enabled: reader.abi_read()?,
+                    }))
+                }
+                Self::SET_SPONSORING_RATE_LIMIT => {
+                    return Ok(Some(Self::SetSponsoringRateLimit {
+                        contract_address: reader.abi_read()?,
+                        rate_limit: reader.abi_read()?,
+                    }))
+                }
+                Self::GET_SPONSORING_RATE_LIMIT => {
+                    return Ok(Some(Self::GetSponsoringRateLimit {
+                        contract_address: reader.abi_read()?,
+                    }))
+                }
+                Self::ALLOWED => {
+                    return Ok(Some(Self::Allowed {
+                        contract_address: reader.abi_read()?,
+                        user: reader.abi_read()?,
+                    }))
+                }
+                Self::ALLOWLIST_ENABLED => {
+                    return Ok(Some(Self::AllowlistEnabled {
+                        contract_address: reader.abi_read()?,
+                    }))
+                }
+                Self::TOGGLE_ALLOWLIST => {
+                    return Ok(Some(Self::ToggleAllowlist {
+                        contract_address: reader.abi_read()?,
+                        enabled: reader.abi_read()?,
+                    }))
+                }
+                Self::TOGGLE_ALLOWED => {
+                    return Ok(Some(Self::ToggleAllowed {
+                        contract_address: reader.abi_read()?,
+                        user: reader.abi_read()?,
+                        allowed: reader.abi_read()?,
+                    }))
+                }
+                _ => {}
+            }
+            return Ok(None);
+        }
+    }
+    impl<T: Config> ::evm_coder::Weighted for ContractHelpersCall<T> {
+        fn weight(&self) -> ::evm_coder::execution::DispatchInfo {
+            type InternalCall = ContractHelpersCall;
+            match self {
+                InternalCall::ERC165Call(::evm_coder::ERC165Call::SupportsInterface { .. }) => {
+                    100u64.into()
+                }
+                InternalCall::ContractOwner { .. } => ().into(),
+                InternalCall::SponsoringEnabled { .. } => ().into(),
+                InternalCall::ToggleSponsoring { .. } => ().into(),
+                InternalCall::SetSponsoringRateLimit { .. } => ().into(),
+                InternalCall::GetSponsoringRateLimit { .. } => ().into(),
+                InternalCall::Allowed { .. } => ().into(),
+                InternalCall::AllowlistEnabled { .. } => ().into(),
+                InternalCall::ToggleAllowlist { .. } => ().into(),
+                InternalCall::ToggleAllowed { .. } => ().into(),
+            }
+        }
+    }
+    impl<T: Config> ::evm_coder::Callable<ContractHelpersCall<T>> for ContractHelpers<T> {
+        #[allow(unreachable_code)]
+        fn call(
+            &mut self,
+            c: Msg<ContractHelpersCall>,
+        ) -> ::evm_coder::execution::ResultWithPostInfo<::evm_coder::abi::AbiWriter> {
+            use ::evm_coder::abi::AbiWrite;
+            type InternalCall = ContractHelpersCall;
+            match c.call {
+                InternalCall::ERC165Call(::evm_coder::ERC165Call::SupportsInterface {
+                    interface_id,
+                }) => {
+                    let mut writer = ::evm_coder::abi::AbiWriter::default();
+                    writer.bool(&InternalCall::supports_interface(interface_id));
+                    return Ok(writer.into());
+                }
+                _ => {}
+            }
+            let mut writer = ::evm_coder::abi::AbiWriter::default();
+            match c.call {
+                InternalCall::ContractOwner { contract_address } => {
+                    let result = self.contract_owner(contract_address)?;
+                    (&result).to_result()
+                }
+                InternalCall::SponsoringEnabled { contract_address } => {
+                    let result = self.sponsoring_enabled(contract_address)?;
+                    (&result).to_result()
+                }
+                InternalCall::ToggleSponsoring {
+                    contract_address,
+                    enabled,
+                } => {
+                    let result =
+                        self.toggle_sponsoring(c.caller.clone(), contract_address, enabled)?;
+                    (&result).to_result()
+                }
+                InternalCall::SetSponsoringRateLimit {
+                    contract_address,
+                    rate_limit,
+                } => {
+                    let result = self.set_sponsoring_rate_limit(
+                        c.caller.clone(),
+                        contract_address,
+                        rate_limit,
+                    )?;
+                    (&result).to_result()
+                }
+                InternalCall::GetSponsoringRateLimit { contract_address } => {
+                    let result = self.get_sponsoring_rate_limit(contract_address)?;
+                    (&result).to_result()
+                }
+                InternalCall::Allowed {
+                    contract_address,
+                    user,
+                } => {
+                    let result = self.allowed(contract_address, user)?;
+                    (&result).to_result()
+                }
+                InternalCall::AllowlistEnabled { contract_address } => {
+                    let result = self.allowlist_enabled(contract_address)?;
+                    (&result).to_result()
+                }
+                InternalCall::ToggleAllowlist {
+                    contract_address,
+                    enabled,
+                } => {
+                    let result =
+                        self.toggle_allowlist(c.caller.clone(), contract_address, enabled)?;
+                    (&result).to_result()
+                }
+                InternalCall::ToggleAllowed {
+                    contract_address,
+                    user,
+                    allowed,
+                } => {
+                    let result =
+                        self.toggle_allowed(c.caller.clone(), contract_address, user, allowed)?;
+                    (&result).to_result()
+                }
+                _ => ::core::panicking::panic("internal error: entered unreachable code"),
+            }
+        }
+    }
+    pub struct HelpersOnMethodCall<T: Config>(PhantomData<*const T>);
+    impl<T: Config> OnMethodCall<T> for HelpersOnMethodCall<T> {
+        fn is_reserved(contract: &sp_core::H160) -> bool {
+            contract == &T::ContractAddress::get()
+        }
+        fn is_used(contract: &sp_core::H160) -> bool {
+            contract == &T::ContractAddress::get()
+        }
+        fn call(
+            source: &sp_core::H160,
+            target: &sp_core::H160,
+            gas_left: u64,
+            input: &[u8],
+            value: sp_core::U256,
+        ) -> Option<PrecompileOutput> {
+            if !<Pallet<T>>::allowed(*target, *source, true) {
+                return Some(PrecompileOutput {
+                    exit_status: ExitReason::Revert(ExitRevert::Reverted),
+                    cost: 0,
+                    output: {
+                        let mut writer = AbiWriter::new_call(147028384u32);
+                        writer.string("Target contract is allowlisted");
+                        writer.finish()
+                    },
+                    logs: ::alloc::vec::Vec::new(),
+                });
+            }
+            if target != &T::ContractAddress::get() {
+                return None;
+            }
+            let helpers = ContractHelpers::<T>(SubstrateRecorder::<T>::new(*target, gas_left));
+            pallet_evm_coder_substrate::call(*source, helpers, value, input)
+        }
+        fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {
+            (contract == & T :: ContractAddress :: get ()) . then (| | b"`\xe0`@R`&`\x80\x81\x81R\x90a\x04\xf4`\xa09\x80Qa\x00&\x91`\x01\x91` \x90\x91\x01\x90a\x009V[P4\x80\x15a\x003W`\x00\x80\xfd[Pa\x01\rV[\x82\x80Ta\x00E\x90a\x00\xd2V[\x90`\x00R` `\x00 \x90`\x1f\x01` \x90\x04\x81\x01\x92\x82a\x00gW`\x00\x85Ua\x00\xadV[\x82`\x1f\x10a\x00\x80W\x80Q`\xff\x19\x16\x83\x80\x01\x17\x85Ua\x00\xadV[\x82\x80\x01`\x01\x01\x85U\x82\x15a\x00\xadW\x91\x82\x01[\x82\x81\x11\x15a\x00\xadW\x82Q\x82U\x91` \x01\x91\x90`\x01\x01\x90a\x00\x92V[Pa\x00\xb9\x92\x91Pa\x00\xbdV[P\x90V[[\x80\x82\x11\x15a\x00\xb9W`\x00\x81U`\x01\x01a\x00\xbeV[`\x01\x81\x81\x1c\x90\x82\x16\x80a\x00\xe6W`\x7f\x82\x16\x91P[` \x82\x10\x81\x14\x15a\x01\x07WcNH{q`\xe0\x1b`\x00R`\"`\x04R`$`\x00\xfd[P\x91\x90PV[a\x03\xd8\x80a\x01\x1c`\x009`\x00\xf3\xfe`\x80`@R4\x80\x15a\x00\x10W`\x00\x80\xfd[P`\x046\x10a\x00\x9eW`\x005`\xe0\x1c\x80c`\'\xdca\x11a\x00fW\x80c`\'\xdca\x14a\x01\"W\x80ca\x0c\xfa\xbd\x14a\x010W\x80cw\xb6\xc9\x08\x14a\x01SW\x80c\xc7r\xefl\x14a\x01\"W\x80c\xfc\xacm\x86\x14a\x00\xcbW`\x00\x80\xfd[\x80c\x01\xff\xc9\xa7\x14a\x00\xa3W\x80c6\xde \xf5\x14a\x00\xcbW\x80cG\x06\xcc\x1c\x14a\x00\xe0W\x80cQR\xb1L\x14a\x00\xeeW\x80c\\e\x81e\x14a\x01\x14W[`\x00\x80\xfd[a\x00\xb6a\x00\xb16`\x04a\x01\xa2V[a\x01aV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xf3[a\x00\xdea\x00\xd96`\x04a\x01\xffV[a\x01\x87V[\x00[a\x00\xdea\x00\xd96`\x04a\x022V[a\x00\xfca\x00\xb16`\x04a\x02uV[`@Q`\x01`\x01`\xa0\x1b\x03\x90\x91\x16\x81R` \x01a\x00\xc2V[a\x00\xb6a\x00\xb16`\x04a\x02\x90V[a\x00\xb6a\x00\xb16`\x04a\x02uV[a\x01>a\x00\xb16`\x04a\x02uV[`@Qc\xff\xff\xff\xff\x90\x91\x16\x81R` \x01a\x00\xc2V[a\x00\xdea\x00\xd96`\x04a\x02\xbaV[`\x00`\x01`@QbF\x1b\xcd`\xe5\x1b\x81R`\x04\x01a\x01~\x91\x90a\x02\xfaV[`@Q\x80\x91\x03\x90\xfd[`\x01`@QbF\x1b\xcd`\xe5\x1b\x81R`\x04\x01a\x01~\x91\x90a\x02\xfaV[`\x00` \x82\x84\x03\x12\x15a\x01\xb4W`\x00\x80\xfd[\x815`\x01`\x01`\xe0\x1b\x03\x19\x81\x16\x81\x14a\x01\xccW`\x00\x80\xfd[\x93\x92PPPV[\x805`\x01`\x01`\xa0\x1b\x03\x81\x16\x81\x14a\x01\xeaW`\x00\x80\xfd[\x91\x90PV[\x805\x80\x15\x15\x81\x14a\x01\xeaW`\x00\x80\xfd[`\x00\x80`@\x83\x85\x03\x12\x15a\x02\x12W`\x00\x80\xfd[a\x02\x1b\x83a\x01\xd3V[\x91Pa\x02)` \x84\x01a\x01\xefV[\x90P\x92P\x92\x90PV[`\x00\x80`\x00``\x84\x86\x03\x12\x15a\x02GW`\x00\x80\xfd[a\x02P\x84a\x01\xd3V[\x92Pa\x02^` \x85\x01a\x01\xd3V[\x91Pa\x02l`@\x85\x01a\x01\xefV[\x90P\x92P\x92P\x92V[`\x00` \x82\x84\x03\x12\x15a\x02\x87W`\x00\x80\xfd[a\x01\xcc\x82a\x01\xd3V[`\x00\x80`@\x83\x85\x03\x12\x15a\x02\xa3W`\x00\x80\xfd[a\x02\xac\x83a\x01\xd3V[\x91Pa\x02)` \x84\x01a\x01\xd3V[`\x00\x80`@\x83\x85\x03\x12\x15a\x02\xcdW`\x00\x80\xfd[a\x02\xd6\x83a\x01\xd3V[\x91P` \x83\x015c\xff\xff\xff\xff\x81\x16\x81\x14a\x02\xefW`\x00\x80\xfd[\x80\x91PP\x92P\x92\x90PV[`\x00` \x80\x83R`\x00\x84T\x81`\x01\x82\x81\x1c\x91P\x80\x83\x16\x80a\x03\x1cW`\x7f\x83\x16\x92P[\x85\x83\x10\x81\x14\x15a\x03:WcNH{q`\xe0\x1b\x85R`\"`\x04R`$\x85\xfd[\x87\x86\x01\x83\x81R` \x01\x81\x80\x15a\x03WW`\x01\x81\x14a\x03hWa\x03\x93V[`\xff\x19\x86\x16\x82R\x87\x82\x01\x96Pa\x03\x93V[`\x00\x8b\x81R` \x90 `\x00[\x86\x81\x10\x15a\x03\x8dW\x81T\x84\x82\x01R\x90\x85\x01\x90\x89\x01a\x03tV[\x83\x01\x97PP[P\x94\x99\x98PPPPPPPPPV\xfe\xa2dipfsX\"\x12 \xde\xe1\xb0gnP\xa0\xbb\xa7\xaf\xbek+\xe6S6\n\xcd?\x0c+\x81\xebEq\x8c\xe3\xab\xaaC6UdsolcC\x00\x08\t\x003this contract is implemented in native" . to_vec ())
+        }
+    }
+    pub struct HelpersOnCreate<T: Config>(PhantomData<*const T>);
+    impl<T: Config> OnCreate<T> for HelpersOnCreate<T> {
+        fn on_create(owner: H160, contract: H160) {
+            <Owner<T>>::insert(contract, owner);
+        }
+    }
+    pub struct HelpersContractSponsoring<T: Config>(PhantomData<*const T>);
+    impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for HelpersContractSponsoring<T> {
+        fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {
+            if <SelfSponsoring<T>>::get(&call.0) && <Pallet<T>>::allowed(call.0, *who, false) {
+                let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+                if let Some(last_tx_block) = <SponsorBasket<T>>::get(&call.0, who) {
+                    let rate_limit = <SponsoringRateLimit<T>>::get(&call.0);
+                    let limit_time = last_tx_block + rate_limit;
+                    if block_number > limit_time {
+                        <SponsorBasket<T>>::insert(&call.0, who, block_number);
+                        return Some(call.0);
+                    }
+                } else {
+                    <SponsorBasket<T>>::insert(&call.0, who, block_number);
+                    return Some(call.0);
+                }
+            }
+            None
+        }
+    }
+}
+#[doc = r"
+			The module that hosts all the
+			[FRAME](https://docs.substrate.io/v3/runtime/frame)
+			types needed to add this pallet to a
+			runtime.
+			"]
+pub mod pallet {
+    use evm_coder::execution::Result;
+    use frame_support::pallet_prelude::*;
+    use sp_core::H160;
+    #[doc = r"
+			Configuration trait of this pallet.
+
+			Implement this type for a runtime in order to customize this pallet.
+			"]
+    pub trait Config: frame_system::Config + pallet_evm_coder_substrate::Config {
+        type ContractAddress: Get<H160>;
+        type DefaultSponsoringRateLimit: Get<Self::BlockNumber>;
+    }
+    #[scale_info(skip_type_params(T), capture_docs = "always")]
+    #[doc = r"
+			Custom [dispatch errors](https://docs.substrate.io/v3/runtime/events-and-errors)
+			of this pallet.
+			"]
+    pub enum Error<T> {
+        #[doc(hidden)]
+        #[codec(skip)]
+        __Ignore(
+            frame_support::sp_std::marker::PhantomData<(T)>,
+            frame_support::Never,
+        ),
+        #[doc = " This method is only executable by owner"]
+        NoPermission,
+    }
+    #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
+    const _: () = {
+        impl<T> ::scale_info::TypeInfo for Error<T>
+        where
+            frame_support::sp_std::marker::PhantomData<(T)>: ::scale_info::TypeInfo + 'static,
+            T: 'static,
+        {
+            type Identity = Self;
+            fn type_info() -> ::scale_info::Type {
+                :: scale_info :: Type :: builder () . path (:: scale_info :: Path :: new ("Error" , "pallet_evm_contract_helpers::pallet")) . type_params (< [_] > :: into_vec (box [:: scale_info :: TypeParameter :: new ("T" , :: core :: option :: Option :: None)])) . docs_always (& ["\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/v3/runtime/events-and-errors)\n\t\t\tof this pallet.\n\t\t\t"]) . variant (:: scale_info :: build :: Variants :: new () . variant ("NoPermission" , | v | v . index (0usize as :: core :: primitive :: u8) . docs_always (& ["This method is only executable by owner"])))
+            }
+        };
+    };
+    #[doc = r"
+			The [pallet](https://docs.substrate.io/v3/runtime/frame#pallets) implementing
+			the on-chain logic.
+			"]
+    pub struct Pallet<T>(frame_support::sp_std::marker::PhantomData<(T)>);
+    const _: () = {
+        impl<T> core::clone::Clone for Pallet<T> {
+            fn clone(&self) -> Self {
+                Self(core::clone::Clone::clone(&self.0))
+            }
+        }
+    };
+    const _: () = {
+        impl<T> core::cmp::Eq for Pallet<T> {}
+    };
+    const _: () = {
+        impl<T> core::cmp::PartialEq for Pallet<T> {
+            fn eq(&self, other: &Self) -> bool {
+                true && self.0 == other.0
+            }
+        }
+    };
+    const _: () = {
+        impl<T> core::fmt::Debug for Pallet<T> {
+            fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
+                fmt.debug_tuple("Pallet").field(&self.0).finish()
+            }
+        }
+    };
+    #[allow(type_alias_bounds)]
+    pub(super) type Owner<T: Config> = StorageMap<
+        _GeneratedPrefixForStorageOwner<T>,
+        Twox128,
+        H160,
+        H160,
+        ValueQuery,
+        frame_support::traits::GetDefault,
+        frame_support::traits::GetDefault,
+    >;
+    #[allow(type_alias_bounds)]
+    pub(super) type SelfSponsoring<T: Config> = StorageMap<
+        _GeneratedPrefixForStorageSelfSponsoring<T>,
+        Twox128,
+        H160,
+        bool,
+        ValueQuery,
+        frame_support::traits::GetDefault,
+        frame_support::traits::GetDefault,
+    >;
+    #[allow(type_alias_bounds)]
+    pub(super) type SponsoringRateLimit<T: Config> = StorageMap<
+        _GeneratedPrefixForStorageSponsoringRateLimit<T>,
+        Twox128,
+        H160,
+        T::BlockNumber,
+        ValueQuery,
+        T::DefaultSponsoringRateLimit,
+        frame_support::traits::GetDefault,
+    >;
+    #[allow(type_alias_bounds)]
+    pub(super) type SponsorBasket<T: Config> = StorageDoubleMap<
+        _GeneratedPrefixForStorageSponsorBasket<T>,
+        Twox128,
+        H160,
+        Twox128,
+        H160,
+        T::BlockNumber,
+        OptionQuery,
+        frame_support::traits::GetDefault,
+        frame_support::traits::GetDefault,
+    >;
+    #[allow(type_alias_bounds)]
+    pub(super) type AllowlistEnabled<T: Config> = StorageMap<
+        _GeneratedPrefixForStorageAllowlistEnabled<T>,
+        Twox128,
+        H160,
+        bool,
+        ValueQuery,
+        frame_support::traits::GetDefault,
+        frame_support::traits::GetDefault,
+    >;
+    #[allow(type_alias_bounds)]
+    pub(super) type Allowlist<T: Config> = StorageDoubleMap<
+        _GeneratedPrefixForStorageAllowlist<T>,
+        Twox128,
+        H160,
+        Twox128,
+        H160,
+        bool,
+        ValueQuery,
+        frame_support::traits::GetDefault,
+        frame_support::traits::GetDefault,
+    >;
+    impl<T: Config> Pallet<T> {
+        pub fn toggle_sponsoring(contract: H160, enabled: bool) {
+            <SelfSponsoring<T>>::insert(contract, enabled);
+        }
+        pub fn set_sponsoring_rate_limit(contract: H160, rate_limit: T::BlockNumber) {
+            <SponsoringRateLimit<T>>::insert(contract, rate_limit);
+        }
+        #[doc = " Default is returned if allowlist is disabled"]
+        pub fn allowed(contract: H160, user: H160, default: bool) -> bool {
+            if !<AllowlistEnabled<T>>::get(contract) {
+                return default;
+            }
+            <Allowlist<T>>::get(&contract, &user) || <Owner<T>>::get(&contract) == user
+        }
+        pub fn toggle_allowlist(contract: H160, enabled: bool) {
+            <AllowlistEnabled<T>>::insert(contract, enabled)
+        }
+        pub fn toggle_allowed(contract: H160, user: H160, allowed: bool) {
+            <Allowlist<T>>::insert(contract, user, allowed);
+        }
+        pub fn ensure_owner(contract: H160, user: H160) -> Result<()> {
+            {
+                if !(<Owner<T>>::get(&contract) == user) {
+                    {
+                        return Err("no permission".into());
+                    };
+                }
+            };
+            Ok(())
+        }
+    }
+    impl<T: Config> Pallet<T> {
+        #[doc(hidden)]
+        pub fn pallet_constants_metadata(
+        ) -> frame_support::sp_std::vec::Vec<frame_support::metadata::PalletConstantMetadata>
+        {
+            ::alloc::vec::Vec::new()
+        }
+    }
+    impl<T: Config> Pallet<T> {
+        pub fn error_metadata() -> Option<frame_support::metadata::PalletErrorMetadata> {
+            Some(frame_support::metadata::PalletErrorMetadata {
+                ty: frame_support::scale_info::meta_type::<Error<T>>(),
+            })
+        }
+    }
+    #[doc = r" Type alias to `Pallet`, to be used by `construct_runtime`."]
+    #[doc = r""]
+    #[doc = r" Generated by `pallet` attribute macro."]
+    #[deprecated(note = "use `Pallet` instead")]
+    #[allow(dead_code)]
+    pub type Module<T> = Pallet<T>;
+    impl<T: Config> frame_support::traits::GetStorageVersion for Pallet<T> {
+        fn current_storage_version() -> frame_support::traits::StorageVersion {
+            frame_support::traits::StorageVersion::default()
+        }
+        fn on_chain_storage_version() -> frame_support::traits::StorageVersion {
+            frame_support::traits::StorageVersion::get::<Self>()
+        }
+    }
+    impl<T: Config> frame_support::traits::OnGenesis for Pallet<T> {
+        fn on_genesis() {
+            let storage_version = frame_support::traits::StorageVersion::default();
+            storage_version.put::<Self>();
+        }
+    }
+    impl<T: Config> frame_support::traits::PalletInfoAccess for Pallet<T> {
+        fn index() -> usize {
+            <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::index::<
+                Self,
+            >()
+            .expect(
+                "Pallet is part of the runtime because pallet `Config` trait is \
+						implemented by the runtime",
+            )
+        }
+        fn name() -> &'static str {
+            <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+                Self,
+            >()
+            .expect(
+                "Pallet is part of the runtime because pallet `Config` trait is \
+						implemented by the runtime",
+            )
+        }
+        fn module_name() -> &'static str {
+            < < T as frame_system :: Config > :: PalletInfo as frame_support :: traits :: PalletInfo > :: module_name :: < Self > () . expect ("Pallet is part of the runtime because pallet `Config` trait is \
+						implemented by the runtime")
+        }
+        fn crate_version() -> frame_support::traits::CrateVersion {
+            frame_support::traits::CrateVersion {
+                major: 0u16,
+                minor: 1u8,
+                patch: 0u8,
+            }
+        }
+    }
+    impl<T: Config> frame_support::traits::StorageInfoTrait for Pallet<T> {
+        fn storage_info() -> frame_support::sp_std::vec::Vec<frame_support::traits::StorageInfo> {
+            #[allow(unused_mut)]
+            let mut res = ::alloc::vec::Vec::new();
+            {
+                let mut storage_info = < Owner < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ;
+                res.append(&mut storage_info);
+            }
+            {
+                let mut storage_info = < SelfSponsoring < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ;
+                res.append(&mut storage_info);
+            }
+            {
+                let mut storage_info = < SponsoringRateLimit < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ;
+                res.append(&mut storage_info);
+            }
+            {
+                let mut storage_info = < SponsorBasket < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ;
+                res.append(&mut storage_info);
+            }
+            {
+                let mut storage_info = < AllowlistEnabled < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ;
+                res.append(&mut storage_info);
+            }
+            {
+                let mut storage_info = < Allowlist < T > as frame_support :: traits :: PartialStorageInfoTrait > :: partial_storage_info () ;
+                res.append(&mut storage_info);
+            }
+            res
+        }
+    }
+    #[doc(hidden)]
+    pub mod __substrate_call_check {
+        #[doc(hidden)]
+        pub use __is_call_part_defined_0 as is_call_part_defined;
+    }
+    #[doc = r"Contains one variant per dispatchable that can be called by an extrinsic."]
+    #[codec(encode_bound())]
+    #[codec(decode_bound())]
+    #[scale_info(skip_type_params(T), capture_docs = "always")]
+    #[allow(non_camel_case_types)]
+    pub enum Call<T: Config> {
+        #[doc(hidden)]
+        #[codec(skip)]
+        __Ignore(
+            frame_support::sp_std::marker::PhantomData<(T,)>,
+            frame_support::Never,
+        ),
+    }
+    const _: () = {
+        impl<T: Config> core::fmt::Debug for Call<T> {
+            fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
+                match *self {
+                    Self::__Ignore(ref _0, ref _1) => fmt
+                        .debug_tuple("Call::__Ignore")
+                        .field(&_0)
+                        .field(&_1)
+                        .finish(),
+                }
+            }
+        }
+    };
+    const _: () = {
+        impl<T: Config> core::clone::Clone for Call<T> {
+            fn clone(&self) -> Self {
+                match self {
+                    Self::__Ignore(ref _0, ref _1) => {
+                        Self::__Ignore(core::clone::Clone::clone(_0), core::clone::Clone::clone(_1))
+                    }
+                }
+            }
+        }
+    };
+    const _: () = {
+        impl<T: Config> core::cmp::Eq for Call<T> {}
+    };
+    const _: () = {
+        impl<T: Config> core::cmp::PartialEq for Call<T> {
+            fn eq(&self, other: &Self) -> bool {
+                match (self, other) {
+                    (Self::__Ignore(_0, _1), Self::__Ignore(_0_other, _1_other)) => {
+                        true && _0 == _0_other && _1 == _1_other
+                    }
+                }
+            }
+        }
+    };
+    const _: () = {
+        #[allow(non_camel_case_types)]
+        impl<T: Config> ::codec::Encode for Call<T> {}
+        impl<T: Config> ::codec::EncodeLike for Call<T> {}
+    };
+    const _: () = {
+        #[allow(non_camel_case_types)]
+        impl<T: Config> ::codec::Decode for Call<T> {
+            fn decode<__CodecInputEdqy: ::codec::Input>(
+                __codec_input_edqy: &mut __CodecInputEdqy,
+            ) -> ::core::result::Result<Self, ::codec::Error> {
+                match __codec_input_edqy
+                    .read_byte()
+                    .map_err(|e| e.chain("Could not decode `Call`, failed to read variant byte"))?
+                {
+                    _ => ::core::result::Result::Err(<_ as ::core::convert::Into<_>>::into(
+                        "Could not decode `Call`, variant doesn\'t exist",
+                    )),
+                }
+            }
+        }
+    };
+    #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
+    const _: () = {
+        impl<T: Config> ::scale_info::TypeInfo for Call<T>
+        where
+            frame_support::sp_std::marker::PhantomData<(T,)>: ::scale_info::TypeInfo + 'static,
+            T: Config + 'static,
+        {
+            type Identity = Self;
+            fn type_info() -> ::scale_info::Type {
+                ::scale_info::Type::builder()
+                    .path(::scale_info::Path::new(
+                        "Call",
+                        "pallet_evm_contract_helpers::pallet",
+                    ))
+                    .type_params(<[_]>::into_vec(box [::scale_info::TypeParameter::new(
+                        "T",
+                        ::core::option::Option::None,
+                    )]))
+                    .docs_always(&[
+                        "Contains one variant per dispatchable that can be called by an extrinsic.",
+                    ])
+                    .variant(::scale_info::build::Variants::new())
+            }
+        };
+    };
+    impl<T: Config> Call<T> {}
+    impl<T: Config> frame_support::dispatch::GetDispatchInfo for Call<T> {
+        fn get_dispatch_info(&self) -> frame_support::dispatch::DispatchInfo {
+            match *self {
+                Self::__Ignore(_, _) => {
+                    ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1(
+                        &["internal error: entered unreachable code: "],
+                        &match (&"__Ignore cannot be used",) {
+                            (arg0,) => [::core::fmt::ArgumentV1::new(
+                                arg0,
+                                ::core::fmt::Display::fmt,
+                            )],
+                        },
+                    ))
+                }
+            }
+        }
+    }
+    impl<T: Config> frame_support::dispatch::GetCallName for Call<T> {
+        fn get_call_name(&self) -> &'static str {
+            match *self {
+                Self::__Ignore(_, _) => {
+                    ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1(
+                        &["internal error: entered unreachable code: "],
+                        &match (&"__PhantomItem cannot be used.",) {
+                            (arg0,) => [::core::fmt::ArgumentV1::new(
+                                arg0,
+                                ::core::fmt::Display::fmt,
+                            )],
+                        },
+                    ))
+                }
+            }
+        }
+        fn get_call_names() -> &'static [&'static str] {
+            &[]
+        }
+    }
+    impl<T: Config> frame_support::traits::UnfilteredDispatchable for Call<T> {
+        type Origin = frame_system::pallet_prelude::OriginFor<T>;
+        fn dispatch_bypass_filter(
+            self,
+            origin: Self::Origin,
+        ) -> frame_support::dispatch::DispatchResultWithPostInfo {
+            match self {
+                Self::__Ignore(_, _) => {
+                    let _ = origin;
+                    {
+                        {
+                            ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1(
+                                &["internal error: entered unreachable code: "],
+                                &match (&"__PhantomItem cannot be used.",) {
+                                    (arg0,) => [::core::fmt::ArgumentV1::new(
+                                        arg0,
+                                        ::core::fmt::Display::fmt,
+                                    )],
+                                },
+                            ))
+                        }
+                    };
+                }
+            }
+        }
+    }
+    impl<T: Config> frame_support::dispatch::Callable<T> for Pallet<T> {
+        type Call = Call<T>;
+    }
+    impl<T: Config> Pallet<T> {
+        #[doc(hidden)]
+        pub fn call_functions() -> frame_support::metadata::PalletCallMetadata {
+            frame_support::scale_info::meta_type::<Call<T>>().into()
+        }
+    }
+    impl<T: Config> frame_support::sp_std::fmt::Debug for Error<T> {
+        fn fmt(
+            &self,
+            f: &mut frame_support::sp_std::fmt::Formatter<'_>,
+        ) -> frame_support::sp_std::fmt::Result {
+            f.write_str(self.as_str())
+        }
+    }
+    impl<T: Config> Error<T> {
+        pub fn as_u8(&self) -> u8 {
+            match &self {
+                Self::__Ignore(_, _) => {
+                    ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1(
+                        &["internal error: entered unreachable code: "],
+                        &match (&"`__Ignore` can never be constructed",) {
+                            (arg0,) => [::core::fmt::ArgumentV1::new(
+                                arg0,
+                                ::core::fmt::Display::fmt,
+                            )],
+                        },
+                    ))
+                }
+                Self::NoPermission => 0usize as u8,
+            }
+        }
+        pub fn as_str(&self) -> &'static str {
+            match &self {
+                Self::__Ignore(_, _) => {
+                    ::core::panicking::panic_fmt(::core::fmt::Arguments::new_v1(
+                        &["internal error: entered unreachable code: "],
+                        &match (&"`__Ignore` can never be constructed",) {
+                            (arg0,) => [::core::fmt::ArgumentV1::new(
+                                arg0,
+                                ::core::fmt::Display::fmt,
+                            )],
+                        },
+                    ))
+                }
+                Self::NoPermission => "NoPermission",
+            }
+        }
+    }
+    impl<T: Config> From<Error<T>> for &'static str {
+        fn from(err: Error<T>) -> &'static str {
+            err.as_str()
+        }
+    }
+    impl<T: Config> From<Error<T>> for frame_support::sp_runtime::DispatchError {
+        fn from(err: Error<T>) -> Self {
+            let index = < < T as frame_system :: Config > :: PalletInfo as frame_support :: traits :: PalletInfo > :: index :: < Pallet < T > > () . expect ("Every active module has an index in the runtime; qed") as u8 ;
+            frame_support::sp_runtime::DispatchError::Module {
+                index,
+                error: err.as_u8(),
+                message: Some(err.as_str()),
+            }
+        }
+    }
+    #[doc(hidden)]
+    pub mod __substrate_event_check {
+        #[doc(hidden)]
+        pub use __is_event_part_defined_1 as is_event_part_defined;
+    }
+    impl<T: Config> Pallet<T> {
+        #[doc(hidden)]
+        pub fn storage_metadata() -> frame_support::metadata::PalletStorageMetadata {
+            frame_support :: metadata :: PalletStorageMetadata { prefix : < < T as frame_system :: Config > :: PalletInfo as frame_support :: traits :: PalletInfo > :: name :: < Pallet < T > > () . expect ("Every active pallet has a name in the runtime; qed") , entries : { # [allow (unused_mut)] let mut entries = :: alloc :: vec :: Vec :: new () ; { < Owner < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < SelfSponsoring < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < SponsoringRateLimit < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < SponsorBasket < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < AllowlistEnabled < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } { < Allowlist < T > as frame_support :: storage :: StorageEntryMetadataBuilder > :: build_metadata (:: alloc :: vec :: Vec :: new () , & mut entries) ; } entries } , }
+        }
+    }
+    pub(super) struct _GeneratedPrefixForStorageOwner<T>(core::marker::PhantomData<(T,)>);
+    impl<T: Config> frame_support::traits::StorageInstance for _GeneratedPrefixForStorageOwner<T> {
+        fn pallet_prefix() -> &'static str {
+            <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+                Pallet<T>,
+            >()
+            .expect("Every active pallet has a name in the runtime; qed")
+        }
+        const STORAGE_PREFIX: &'static str = "Owner";
+    }
+    pub(super) struct _GeneratedPrefixForStorageSelfSponsoring<T>(core::marker::PhantomData<(T,)>);
+    impl<T: Config> frame_support::traits::StorageInstance
+        for _GeneratedPrefixForStorageSelfSponsoring<T>
+    {
+        fn pallet_prefix() -> &'static str {
+            <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+                Pallet<T>,
+            >()
+            .expect("Every active pallet has a name in the runtime; qed")
+        }
+        const STORAGE_PREFIX: &'static str = "SelfSponsoring";
+    }
+    pub(super) struct _GeneratedPrefixForStorageSponsoringRateLimit<T>(
+        core::marker::PhantomData<(T,)>,
+    );
+    impl<T: Config> frame_support::traits::StorageInstance
+        for _GeneratedPrefixForStorageSponsoringRateLimit<T>
+    {
+        fn pallet_prefix() -> &'static str {
+            <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+                Pallet<T>,
+            >()
+            .expect("Every active pallet has a name in the runtime; qed")
+        }
+        const STORAGE_PREFIX: &'static str = "SponsoringRateLimit";
+    }
+    pub(super) struct _GeneratedPrefixForStorageSponsorBasket<T>(core::marker::PhantomData<(T,)>);
+    impl<T: Config> frame_support::traits::StorageInstance
+        for _GeneratedPrefixForStorageSponsorBasket<T>
+    {
+        fn pallet_prefix() -> &'static str {
+            <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+                Pallet<T>,
+            >()
+            .expect("Every active pallet has a name in the runtime; qed")
+        }
+        const STORAGE_PREFIX: &'static str = "SponsorBasket";
+    }
+    pub(super) struct _GeneratedPrefixForStorageAllowlistEnabled<T>(
+        core::marker::PhantomData<(T,)>,
+    );
+    impl<T: Config> frame_support::traits::StorageInstance
+        for _GeneratedPrefixForStorageAllowlistEnabled<T>
+    {
+        fn pallet_prefix() -> &'static str {
+            <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+                Pallet<T>,
+            >()
+            .expect("Every active pallet has a name in the runtime; qed")
+        }
+        const STORAGE_PREFIX: &'static str = "AllowlistEnabled";
+    }
+    pub(super) struct _GeneratedPrefixForStorageAllowlist<T>(core::marker::PhantomData<(T,)>);
+    impl<T: Config> frame_support::traits::StorageInstance for _GeneratedPrefixForStorageAllowlist<T> {
+        fn pallet_prefix() -> &'static str {
+            <<T as frame_system::Config>::PalletInfo as frame_support::traits::PalletInfo>::name::<
+                Pallet<T>,
+            >()
+            .expect("Every active pallet has a name in the runtime; qed")
+        }
+        const STORAGE_PREFIX: &'static str = "Allowlist";
+    }
+    #[doc(hidden)]
+    pub mod __substrate_inherent_check {
+        #[doc(hidden)]
+        pub use __is_inherent_part_defined_2 as is_inherent_part_defined;
+    }
+    #[doc = r" Hidden instance generated to be internally used when module is used without"]
+    #[doc = r" instance."]
+    #[doc(hidden)]
+    pub type __InherentHiddenInstance = ();
+    pub(super) trait Store {
+        type Owner;
+        type SelfSponsoring;
+        type SponsoringRateLimit;
+        type SponsorBasket;
+        type AllowlistEnabled;
+        type Allowlist;
+    }
+    impl<T: Config> Store for Pallet<T> {
+        type Owner = Owner<T>;
+        type SelfSponsoring = SelfSponsoring<T>;
+        type SponsoringRateLimit = SponsoringRateLimit<T>;
+        type SponsorBasket = SponsorBasket<T>;
+        type AllowlistEnabled = AllowlistEnabled<T>;
+        type Allowlist = Allowlist<T>;
+    }
+    impl<T: Config> frame_support::traits::Hooks<<T as frame_system::Config>::BlockNumber>
+        for Pallet<T>
+    {
+    }
+    impl<T: Config> frame_support::traits::OnFinalize<<T as frame_system::Config>::BlockNumber>
+        for Pallet<T>
+    {
+        fn on_finalize(n: <T as frame_system::Config>::BlockNumber) {
+            let __within_span__ = {
+                use ::tracing::__macro_support::Callsite as _;
+                static CALLSITE: ::tracing::__macro_support::MacroCallsite = {
+                    use ::tracing::__macro_support::MacroCallsite;
+                    static META: ::tracing::Metadata<'static> = {
+                        ::tracing_core::metadata::Metadata::new(
+                            "on_finalize",
+                            "pallet_evm_contract_helpers::pallet",
+                            ::tracing::Level::TRACE,
+                            Some("pallets/evm-contract-helpers/src/lib.rs"),
+                            Some(7u32),
+                            Some("pallet_evm_contract_helpers::pallet"),
+                            ::tracing_core::field::FieldSet::new(
+                                &[],
+                                ::tracing_core::callsite::Identifier(&CALLSITE),
+                            ),
+                            ::tracing::metadata::Kind::SPAN,
+                        )
+                    };
+                    MacroCallsite::new(&META)
+                };
+                let mut interest = ::tracing::subscriber::Interest::never();
+                if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
+                    && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current()
+                    && {
+                        interest = CALLSITE.interest();
+                        !interest.is_never()
+                    }
+                    && CALLSITE.is_enabled(interest)
+                {
+                    let meta = CALLSITE.metadata();
+                    ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) })
+                } else {
+                    let span = CALLSITE.disabled_span();
+                    {};
+                    span
+                }
+            };
+            let __tracing_guard__ = __within_span__.enter();
+            < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: on_finalize (n)
+        }
+    }
+    impl<T: Config> frame_support::traits::OnIdle<<T as frame_system::Config>::BlockNumber>
+        for Pallet<T>
+    {
+        fn on_idle(
+            n: <T as frame_system::Config>::BlockNumber,
+            remaining_weight: frame_support::weights::Weight,
+        ) -> frame_support::weights::Weight {
+            < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: on_idle (n , remaining_weight)
+        }
+    }
+    impl<T: Config> frame_support::traits::OnInitialize<<T as frame_system::Config>::BlockNumber>
+        for Pallet<T>
+    {
+        fn on_initialize(
+            n: <T as frame_system::Config>::BlockNumber,
+        ) -> frame_support::weights::Weight {
+            let __within_span__ = {
+                use ::tracing::__macro_support::Callsite as _;
+                static CALLSITE: ::tracing::__macro_support::MacroCallsite = {
+                    use ::tracing::__macro_support::MacroCallsite;
+                    static META: ::tracing::Metadata<'static> = {
+                        ::tracing_core::metadata::Metadata::new(
+                            "on_initialize",
+                            "pallet_evm_contract_helpers::pallet",
+                            ::tracing::Level::TRACE,
+                            Some("pallets/evm-contract-helpers/src/lib.rs"),
+                            Some(7u32),
+                            Some("pallet_evm_contract_helpers::pallet"),
+                            ::tracing_core::field::FieldSet::new(
+                                &[],
+                                ::tracing_core::callsite::Identifier(&CALLSITE),
+                            ),
+                            ::tracing::metadata::Kind::SPAN,
+                        )
+                    };
+                    MacroCallsite::new(&META)
+                };
+                let mut interest = ::tracing::subscriber::Interest::never();
+                if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
+                    && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current()
+                    && {
+                        interest = CALLSITE.interest();
+                        !interest.is_never()
+                    }
+                    && CALLSITE.is_enabled(interest)
+                {
+                    let meta = CALLSITE.metadata();
+                    ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) })
+                } else {
+                    let span = CALLSITE.disabled_span();
+                    {};
+                    span
+                }
+            };
+            let __tracing_guard__ = __within_span__.enter();
+            < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: on_initialize (n)
+        }
+    }
+    impl<T: Config> frame_support::traits::OnRuntimeUpgrade for Pallet<T> {
+        fn on_runtime_upgrade() -> frame_support::weights::Weight {
+            let __within_span__ = {
+                use ::tracing::__macro_support::Callsite as _;
+                static CALLSITE: ::tracing::__macro_support::MacroCallsite = {
+                    use ::tracing::__macro_support::MacroCallsite;
+                    static META: ::tracing::Metadata<'static> = {
+                        ::tracing_core::metadata::Metadata::new(
+                            "on_runtime_update",
+                            "pallet_evm_contract_helpers::pallet",
+                            ::tracing::Level::TRACE,
+                            Some("pallets/evm-contract-helpers/src/lib.rs"),
+                            Some(7u32),
+                            Some("pallet_evm_contract_helpers::pallet"),
+                            ::tracing_core::field::FieldSet::new(
+                                &[],
+                                ::tracing_core::callsite::Identifier(&CALLSITE),
+                            ),
+                            ::tracing::metadata::Kind::SPAN,
+                        )
+                    };
+                    MacroCallsite::new(&META)
+                };
+                let mut interest = ::tracing::subscriber::Interest::never();
+                if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
+                    && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current()
+                    && {
+                        interest = CALLSITE.interest();
+                        !interest.is_never()
+                    }
+                    && CALLSITE.is_enabled(interest)
+                {
+                    let meta = CALLSITE.metadata();
+                    ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) })
+                } else {
+                    let span = CALLSITE.disabled_span();
+                    {};
+                    span
+                }
+            };
+            let __tracing_guard__ = __within_span__.enter();
+            let pallet_name = < < T as frame_system :: Config > :: PalletInfo as frame_support :: traits :: PalletInfo > :: name :: < Self > () . unwrap_or ("<unknown pallet name>") ;
+            {
+                let lvl = ::log::Level::Info;
+                if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() {
+                    ::log::__private_api_log(
+                        ::core::fmt::Arguments::new_v1(
+                            &["\u{2705} no migration for "],
+                            &match (&pallet_name,) {
+                                (arg0,) => [::core::fmt::ArgumentV1::new(
+                                    arg0,
+                                    ::core::fmt::Display::fmt,
+                                )],
+                            },
+                        ),
+                        lvl,
+                        &(
+                            frame_support::LOG_TARGET,
+                            "pallet_evm_contract_helpers::pallet",
+                            "pallets/evm-contract-helpers/src/lib.rs",
+                            7u32,
+                        ),
+                    );
+                }
+            };
+            < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: on_runtime_upgrade ()
+        }
+    }
+    impl<T: Config> frame_support::traits::OffchainWorker<<T as frame_system::Config>::BlockNumber>
+        for Pallet<T>
+    {
+        fn offchain_worker(n: <T as frame_system::Config>::BlockNumber) {
+            < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: offchain_worker (n)
+        }
+    }
+    impl<T: Config> frame_support::traits::IntegrityTest for Pallet<T> {
+        fn integrity_test() {
+            < Self as frame_support :: traits :: Hooks < < T as frame_system :: Config > :: BlockNumber > > :: integrity_test ()
+        }
+    }
+    #[doc(hidden)]
+    pub mod __substrate_genesis_config_check {
+        #[doc(hidden)]
+        pub use __is_genesis_config_defined_3 as is_genesis_config_defined;
+        #[doc(hidden)]
+        pub use __is_std_enabled_for_genesis_3 as is_std_enabled_for_genesis;
+    }
+    #[doc(hidden)]
+    pub mod __substrate_origin_check {
+        #[doc(hidden)]
+        pub use __is_origin_part_defined_4 as is_origin_part_defined;
+    }
+    #[doc(hidden)]
+    pub mod __substrate_validate_unsigned_check {
+        #[doc(hidden)]
+        pub use __is_validate_unsigned_part_defined_5 as is_validate_unsigned_part_defined;
+    }
+}
modifiedpallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -1,7 +1,7 @@
 use core::marker::PhantomData;
 use evm_coder::{abi::AbiWriter, execution::Result, generate_stubgen, solidity_interface, types::*};
-use pallet_evm_coder_substrate::SubstrateRecorder;
-use pallet_evm::{ExitReason, ExitRevert, OnCreate, OnMethodCall, PrecompileOutput};
+use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
+use pallet_evm::{ExitRevert, OnCreate, OnMethodCall, PrecompileResult, PrecompileFailure};
 use sp_core::H160;
 use crate::{
 	AllowlistEnabled, Config, Owner, Pallet, SelfSponsoring, SponsorBasket, SponsoringRateLimit,
@@ -11,16 +11,23 @@
 use sp_std::{convert::TryInto, vec::Vec};
 
 struct ContractHelpers<T: Config>(SubstrateRecorder<T>);
+impl<T: Config> WithRecorder<T> for ContractHelpers<T> {
+	fn recorder(&self) -> &SubstrateRecorder<T> {
+		&self.0
+	}
 
+	fn into_recorder(self) -> SubstrateRecorder<T> {
+		self.0
+	}
+}
+
 #[solidity_interface(name = "ContractHelpers")]
 impl<T: Config> ContractHelpers<T> {
 	fn contract_owner(&self, contract_address: address) -> Result<address> {
-		self.0.consume_sload()?;
 		Ok(<Owner<T>>::get(contract_address))
 	}
 
 	fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {
-		self.0.consume_sload()?;
 		Ok(<SelfSponsoring<T>>::get(contract_address))
 	}
 
@@ -30,9 +37,7 @@
 		contract_address: address,
 		enabled: bool,
 	) -> Result<void> {
-		self.0.consume_sload()?;
 		<Pallet<T>>::ensure_owner(contract_address, caller)?;
-		self.0.consume_sstore()?;
 		<Pallet<T>>::toggle_sponsoring(contract_address, enabled);
 		Ok(())
 	}
@@ -43,15 +48,12 @@
 		contract_address: address,
 		rate_limit: uint32,
 	) -> Result<void> {
-		self.0.consume_sload()?;
 		<Pallet<T>>::ensure_owner(contract_address, caller)?;
-		self.0.consume_sstore()?;
 		<Pallet<T>>::set_sponsoring_rate_limit(contract_address, rate_limit.into());
 		Ok(())
 	}
 
 	fn get_sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {
-		self.0.consume_sload()?;
 		Ok(<SponsoringRateLimit<T>>::get(contract_address)
 			.try_into()
 			.map_err(|_| "rate limit > u32::MAX")?)
@@ -64,7 +66,6 @@
 	}
 
 	fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {
-		self.0.consume_sload()?;
 		Ok(<AllowlistEnabled<T>>::get(contract_address))
 	}
 
@@ -74,9 +75,7 @@
 		contract_address: address,
 		enabled: bool,
 	) -> Result<void> {
-		self.0.consume_sload()?;
 		<Pallet<T>>::ensure_owner(contract_address, caller)?;
-		self.0.consume_sstore()?;
 		<Pallet<T>>::toggle_allowlist(contract_address, enabled);
 		Ok(())
 	}
@@ -88,9 +87,7 @@
 		user: address,
 		allowed: bool,
 	) -> Result<void> {
-		self.0.consume_sload()?;
 		<Pallet<T>>::ensure_owner(contract_address, caller)?;
-		self.0.consume_sstore()?;
 		<Pallet<T>>::toggle_allowed(contract_address, user, allowed);
 		Ok(())
 	}
@@ -112,28 +109,26 @@
 		gas_left: u64,
 		input: &[u8],
 		value: sp_core::U256,
-	) -> Option<PrecompileOutput> {
+	) -> Option<PrecompileResult> {
 		// TODO: Extract to another OnMethodCall handler
 		if <AllowlistEnabled<T>>::get(target) && !<Pallet<T>>::allowed(*target, *source) {
-			return Some(PrecompileOutput {
-				exit_status: ExitReason::Revert(ExitRevert::Reverted),
+			return Some(Err(PrecompileFailure::Revert {
+				exit_status: ExitRevert::Reverted,
 				cost: 0,
 				output: {
 					let mut writer = AbiWriter::new_call(evm_coder::fn_selector!(Error(string)));
 					writer.string("Target contract is allowlisted");
 					writer.finish()
 				},
-				logs: sp_std::vec![],
-			});
+			}));
 		}
 
 		if target != &T::ContractAddress::get() {
 			return None;
 		}
 
-		let mut helpers = ContractHelpers::<T>(SubstrateRecorder::<T>::new(*target, gas_left));
-		let result = pallet_evm_coder_substrate::call_internal(*source, &mut helpers, value, input);
-		helpers.0.evm_to_precompile_output(result)
+		let helpers = ContractHelpers::<T>(SubstrateRecorder::<T>::new(*target, gas_left));
+		pallet_evm_coder_substrate::call(*source, helpers, value, input)
 	}
 
 	fn get_code(contract: &sp_core::H160) -> Option<Vec<u8>> {
@@ -163,7 +158,7 @@
 		if let Some(last_tx_block) = <SponsorBasket<T>>::get(&call.0, who) {
 			let limit = <SponsoringRateLimit<T>>::get(&call.0);
 
-			let timeout = last_tx_block + limit.into();
+			let timeout = last_tx_block + limit;
 			if block_number < timeout {
 				return None;
 			}
@@ -175,5 +170,5 @@
 	}
 }
 
-generate_stubgen!(contract_helpers_impl, ContractHelpersCall, true);
-generate_stubgen!(contract_helpers_iface, ContractHelpersCall, false);
+generate_stubgen!(contract_helpers_impl, ContractHelpersCall<()>, true);
+generate_stubgen!(contract_helpers_iface, ContractHelpersCall<()>, false);
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
+++ b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
@@ -21,6 +21,7 @@
 	}
 }
 
+// Selector: 31acb1fe
 contract ContractHelpers is Dummy, ERC165 {
 	// Selector: contractOwner(address) 5152b14c
 	function contractOwner(address contractAddress)
modifiedpallets/evm-migration/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-migration/Cargo.toml
+++ b/pallets/evm-migration/Cargo.toml
@@ -1,10 +1,12 @@
 [package]
 name = "pallet-evm-migration"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
-scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
+scale-info = { version = "1.0.0", default-features = false, features = [
+    "derive",
+] }
 frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
@@ -12,8 +14,8 @@
 sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 sp-io = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
 
 [dependencies.codec]
 default-features = false
modifiedpallets/evm-migration/src/lib.rsdiffbeforeafterboth
--- a/pallets/evm-migration/src/lib.rs
+++ b/pallets/evm-migration/src/lib.rs
@@ -98,7 +98,7 @@
 			_gas_left: u64,
 			_input: &[u8],
 			_value: sp_core::U256,
-		) -> Option<pallet_evm::PrecompileOutput> {
+		) -> Option<pallet_evm::PrecompileResult> {
 			None
 		}
 
modifiedpallets/evm-migration/src/weights.rsdiffbeforeafterboth
--- a/pallets/evm-migration/src/weights.rs
+++ b/pallets/evm-migration/src/weights.rs
@@ -25,6 +25,7 @@
 #![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;
modifiedpallets/evm-transaction-payment/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-transaction-payment/Cargo.toml
+++ b/pallets/evm-transaction-payment/Cargo.toml
@@ -1,20 +1,22 @@
 [package]
 name = "pallet-evm-transaction-payment"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
-scale-info = { version = "1.0.0", default-features = false, features = ["derive"] }
+scale-info = { version = "1.0.0", default-features = false, features = [
+    "derive",
+] }
 frame-support = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 frame-system = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 sp-runtime = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 sp-std = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 sp-io = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/UniqueNetwork/pallet-sponsoring" } 
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/UniqueNetwork/pallet-sponsoring" }
 up-evm-mapping = { default-features = false, path = "../../primitives/evm-mapping" }
 
 [dependencies.codec]
modifiedpallets/evm-transaction-payment/src/lib.rsdiffbeforeafterboth
--- a/pallets/evm-transaction-payment/src/lib.rs
+++ b/pallets/evm-transaction-payment/src/lib.rs
@@ -128,7 +128,7 @@
 				let sponsor = frame_support::storage::with_transaction(|| {
 					TransactionOutcome::Rollback(T::EvmSponsorshipHandler::get_sponsor(
 						&who,
-						&(target.clone(), input.clone()),
+						&(*target, input.clone()),
 					))
 				})?;
 				let sponsor = T::EvmAddressMapping::into_account_id(sponsor);
modifiedpallets/fungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/fungible/Cargo.toml
+++ b/pallets/fungible/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "pallet-fungible"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies.codec]
 default-features = false
@@ -19,7 +19,7 @@
 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 = { git = "https://github.com/purestake/ethereum", branch = "joshy-scale-info", default-features = false }
+ethereum = { version = "0.10.0", default-features = false }
 frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 scale-info = { version = "1.0.0", default-features = false, features = [
     "derive",
modifiedpallets/fungible/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/fungible/src/benchmarking.rs
+++ b/pallets/fungible/src/benchmarking.rs
@@ -58,4 +58,13 @@
 		<Pallet<T>>::create_item(&collection, &owner, (sender.clone(), 200))?;
 		<Pallet<T>>::set_allowance(&collection, &sender, &spender, 200)?;
 	}: {<Pallet<T>>::transfer_from(&collection, &spender, &sender, &receiver, 100)?}
+
+	burn_from {
+		bench_init!{
+			owner: sub; collection: collection(owner);
+			owner: cross_from_sub; sender: cross_sub; burner: cross_sub;
+		};
+		<Pallet<T>>::create_item(&collection, &owner, (sender.clone(), 200))?;
+		<Pallet<T>>::set_allowance(&collection, &sender, &burner, 200)?;
+	}: {<Pallet<T>>::burn_from(&collection, &burner, &sender, 100)?}
 }
modifiedpallets/fungible/src/common.rsdiffbeforeafterboth
--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -37,7 +37,7 @@
 	}
 
 	fn burn_from() -> Weight {
-		0
+		<SelfWeightOf<T>>::burn_from()
 	}
 
 	fn set_variable_metadata(_bytes: u32) -> Weight {
@@ -116,7 +116,7 @@
 		);
 
 		with_weight(
-			<Pallet<T>>::transfer(&self, &from, &to, amount),
+			<Pallet<T>>::transfer(self, &from, &to, amount),
 			<CommonWeights<T>>::transfer(),
 		)
 	}
@@ -134,7 +134,7 @@
 		);
 
 		with_weight(
-			<Pallet<T>>::set_allowance(&self, &sender, &spender, amount),
+			<Pallet<T>>::set_allowance(self, &sender, &spender, amount),
 			<CommonWeights<T>>::approve(),
 		)
 	}
@@ -153,7 +153,7 @@
 		);
 
 		with_weight(
-			<Pallet<T>>::transfer_from(&self, &sender, &from, &to, amount),
+			<Pallet<T>>::transfer_from(self, &sender, &from, &to, amount),
 			<CommonWeights<T>>::transfer_from(),
 		)
 	}
@@ -171,7 +171,7 @@
 		);
 
 		with_weight(
-			<Pallet<T>>::burn_from(&self, &sender, &from, amount),
+			<Pallet<T>>::burn_from(self, &sender, &from, amount),
 			<CommonWeights<T>>::burn_from(),
 		)
 	}
modifiedpallets/fungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -1,15 +1,17 @@
 use core::char::{REPLACEMENT_CHARACTER, decode_utf16};
 use core::convert::TryInto;
-use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*};
+use evm_coder::{ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight};
 use up_data_structs::CollectionMode;
-use pallet_common::erc::CommonEvmHandler;
+use pallet_common::erc::{CommonEvmHandler, PrecompileResult};
 use sp_core::{H160, U256};
 use sp_std::vec::Vec;
 use pallet_common::account::CrossAccountId;
-use pallet_common::erc::PrecompileOutput;
-use pallet_evm_coder_substrate::{call_internal, dispatch_to_evm};
+use pallet_evm_coder_substrate::{call, dispatch_to_evm};
 
-use crate::{Allowance, Balance, Config, FungibleHandle, Pallet, TotalSupply};
+use crate::{
+	Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,
+	weights::WeightInfo,
+};
 
 #[derive(ToLog)]
 pub enum ERC20Events {
@@ -40,6 +42,7 @@
 		Ok(string::from_utf8_lossy(&self.token_prefix).into())
 	}
 	fn total_supply(&self) -> Result<uint256> {
+		self.consume_store_reads(1)?;
 		Ok(<TotalSupply<T>>::get(self.id).into())
 	}
 
@@ -51,10 +54,12 @@
 		})
 	}
 	fn balance_of(&self, owner: address) -> Result<uint256> {
+		self.consume_store_reads(1)?;
 		let owner = T::CrossAccountId::from_eth(owner);
 		let balance = <Balance<T>>::get((self.id, owner));
 		Ok(balance.into())
 	}
+	#[weight(<SelfWeightOf<T>>::transfer())]
 	fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
@@ -63,6 +68,7 @@
 		<Pallet<T>>::transfer(self, &caller, &to, amount).map_err(|_| "transfer error")?;
 		Ok(true)
 	}
+	#[weight(<SelfWeightOf<T>>::transfer_from())]
 	fn transfer_from(
 		&mut self,
 		caller: caller,
@@ -79,6 +85,7 @@
 			.map_err(dispatch_to_evm::<T>)?;
 		Ok(true)
 	}
+	#[weight(<SelfWeightOf<T>>::approve())]
 	fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let spender = T::CrossAccountId::from_eth(spender);
@@ -89,6 +96,7 @@
 		Ok(true)
 	}
 	fn allowance(&self, owner: address, spender: address) -> Result<uint256> {
+		self.consume_store_reads(1)?;
 		let owner = T::CrossAccountId::from_eth(owner);
 		let spender = T::CrossAccountId::from_eth(spender);
 
@@ -98,6 +106,7 @@
 
 #[solidity_interface(name = "ERC20UniqueExtensions")]
 impl<T: Config> FungibleHandle<T> {
+	#[weight(<SelfWeightOf<T>>::burn_from())]
 	fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = T::CrossAccountId::from_eth(from);
@@ -111,14 +120,13 @@
 #[solidity_interface(name = "UniqueFungible", is(ERC20))]
 impl<T: Config> FungibleHandle<T> {}
 
-generate_stubgen!(gen_impl, UniqueFungibleCall, true);
-generate_stubgen!(gen_iface, UniqueFungibleCall, false);
+generate_stubgen!(gen_impl, UniqueFungibleCall<()>, true);
+generate_stubgen!(gen_iface, UniqueFungibleCall<()>, false);
 
 impl<T: Config> CommonEvmHandler for FungibleHandle<T> {
 	const CODE: &'static [u8] = include_bytes!("./stubs/UniqueFungible.raw");
 
-	fn call(mut self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileOutput> {
-		let result = call_internal::<UniqueFungibleCall, _>(*source, &mut self, value, input);
-		self.0.recorder.evm_to_precompile_output(result)
+	fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileResult> {
+		call::<T, UniqueFungibleCall<T>, _>(*source, self, value, input)
 	}
 }
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -6,6 +6,7 @@
 use pallet_common::{
 	Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, account::CrossAccountId,
 };
+use pallet_evm_coder_substrate::WithRecorder;
 use sp_core::H160;
 use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
 use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
@@ -82,6 +83,14 @@
 		self.0
 	}
 }
+impl<T: Config> WithRecorder<T> for FungibleHandle<T> {
+	fn recorder(&self) -> &pallet_evm_coder_substrate::SubstrateRecorder<T> {
+		self.0.recorder()
+	}
+	fn into_recorder(self) -> pallet_evm_coder_substrate::SubstrateRecorder<T> {
+		self.0.into_recorder()
+	}
+}
 impl<T: Config> Deref for FungibleHandle<T> {
 	type Target = pallet_common::CollectionHandle<T>;
 
@@ -136,7 +145,7 @@
 		}
 		<TotalSupply<T>>::insert(collection.id, total_supply);
 
-		collection.log_infallible(ERC20Events::Transfer {
+		collection.log(ERC20Events::Transfer {
 			from: *owner.as_eth(),
 			to: H160::default(),
 			value: amount.into(),
@@ -180,11 +189,6 @@
 			None
 		};
 
-		collection.consume_sstore()?;
-		collection.consume_sstore()?;
-		collection.consume_log(2, 32)?;
-		collection.consume_sstore()?;
-
 		// =========
 
 		if let Some(balance_to) = balance_to {
@@ -197,7 +201,7 @@
 			<Balance<T>>::insert((collection.id, to), balance_to);
 		}
 
-		collection.log_infallible(ERC20Events::Transfer {
+		collection.log(ERC20Events::Transfer {
 			from: *from.as_eth(),
 			to: *to.as_eth(),
 			value: amount.into(),
@@ -217,8 +221,7 @@
 		sender: &T::CrossAccountId,
 		data: Vec<CreateItemData<T>>,
 	) -> DispatchResult {
-		let unrestricted_minting = collection.is_owner_or_admin(sender)?;
-		if !unrestricted_minting {
+		if !collection.is_owner_or_admin(sender) {
 			ensure!(
 				collection.mint_mode,
 				<CommonError<T>>::PublicMintingNotAllowed
@@ -241,7 +244,6 @@
 			.ok_or(ArithmeticError::Overflow)?;
 
 		for (user, amount) in data.into_iter() {
-			collection.consume_sload()?;
 			let balance = balances
 				.entry(user.clone())
 				.or_insert_with(|| <Balance<T>>::get((collection.id, user)));
@@ -250,20 +252,13 @@
 				.ok_or(ArithmeticError::Overflow)?;
 		}
 
-		collection.consume_sstore()?;
-		for _ in &balances {
-			collection.consume_sstore()?;
-			collection.consume_log(2, 32)?;
-			collection.consume_sstore()?;
-		}
-
 		// =========
 
 		<TotalSupply<T>>::insert(collection.id, total_supply);
 		for (user, amount) in balances {
 			<Balance<T>>::insert((collection.id, &user), amount);
 
-			collection.log_infallible(ERC20Events::Transfer {
+			collection.log(ERC20Events::Transfer {
 				from: H160::default(),
 				to: *user.as_eth(),
 				value: amount.into(),
@@ -291,7 +286,7 @@
 			<Allowance<T>>::insert((collection.id, owner, spender), amount);
 		}
 
-		collection.log_infallible(ERC20Events::Approval {
+		collection.log(ERC20Events::Approval {
 			owner: *owner.as_eth(),
 			spender: *spender.as_eth(),
 			value: amount.into(),
@@ -312,13 +307,13 @@
 		amount: u128,
 	) -> DispatchResult {
 		if collection.access == AccessMode::AllowList {
-			collection.check_allowlist(&owner)?;
-			collection.check_allowlist(&spender)?;
+			collection.check_allowlist(owner)?;
+			collection.check_allowlist(spender)?;
 		}
 
 		if <Balance<T>>::get((collection.id, owner)) < amount {
 			ensure!(
-				collection.ignores_owned_amount(owner)?,
+				collection.ignores_owned_amount(owner),
 				<CommonError<T>>::CantApproveMoreThanOwned
 			);
 		}
@@ -347,7 +342,7 @@
 		let allowance = <Allowance<T>>::get((collection.id, from, spender)).checked_sub(amount);
 		if allowance.is_none() {
 			ensure!(
-				collection.ignores_allowance(spender)?,
+				collection.ignores_allowance(spender),
 				<CommonError<T>>::TokenValueNotEnough
 			);
 		}
@@ -378,7 +373,7 @@
 		let allowance = <Allowance<T>>::get((collection.id, from, spender)).checked_sub(amount);
 		if allowance.is_none() {
 			ensure!(
-				collection.ignores_allowance(spender)?,
+				collection.ignores_allowance(spender),
 				<CommonError<T>>::TokenValueNotEnough
 			);
 		}
modifiedpallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth
--- a/pallets/fungible/src/stubs/UniqueFungible.sol
+++ b/pallets/fungible/src/stubs/UniqueFungible.sol
@@ -31,6 +31,7 @@
 	);
 }
 
+// Selector: 942e8b22
 contract ERC20 is Dummy, ERC165, ERC20Events {
 	// Selector: name() 06fdde03
 	function name() public view returns (string memory) {
modifiedpallets/fungible/src/weights.rsdiffbeforeafterboth
--- a/pallets/fungible/src/weights.rs
+++ b/pallets/fungible/src/weights.rs
@@ -25,6 +25,7 @@
 #![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;
@@ -36,6 +37,7 @@
 	fn transfer() -> Weight;
 	fn approve() -> Weight;
 	fn transfer_from() -> Weight;
+	fn burn_from() -> Weight;
 }
 
 /// Weights for pallet_fungible using the Substrate node and recommended hardware.
@@ -75,6 +77,14 @@
 			.saturating_add(T::DbWeight::get().reads(3 as Weight))
 			.saturating_add(T::DbWeight::get().writes(3 as Weight))
 	}
+	// Storage: Fungible Allowance (r:1 w:1)
+	// Storage: Fungible TotalSupply (r:1 w:1)
+	// Storage: Fungible Balance (r:1 w:1)
+	fn burn_from() -> Weight {
+		(55_874_000 as Weight)
+			.saturating_add(T::DbWeight::get().reads(3 as Weight))
+			.saturating_add(T::DbWeight::get().writes(3 as Weight))
+	}
 }
 
 // For backwards compatibility and tests
@@ -113,4 +123,12 @@
 			.saturating_add(RocksDbWeight::get().reads(3 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(3 as Weight))
 	}
+	// Storage: Fungible Allowance (r:1 w:1)
+	// Storage: Fungible TotalSupply (r:1 w:1)
+	// Storage: Fungible Balance (r:1 w:1)
+	fn burn_from() -> Weight {
+		(55_874_000 as Weight)
+			.saturating_add(RocksDbWeight::get().reads(3 as Weight))
+			.saturating_add(RocksDbWeight::get().writes(3 as Weight))
+	}
 }
modifiedpallets/nonfungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/nonfungible/Cargo.toml
+++ b/pallets/nonfungible/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "pallet-nonfungible"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies.codec]
 default-features = false
@@ -19,7 +19,7 @@
 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 = { git = "https://github.com/purestake/ethereum", branch = "joshy-scale-info", default-features = false }
+ethereum = { version = "0.10.0", default-features = false }
 frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 scale-info = { version = "1.0.0", default-features = false, features = [
     "derive",
modifiedpallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/benchmarking.rs
+++ b/pallets/nonfungible/src/benchmarking.rs
@@ -89,6 +89,15 @@
 		<Pallet<T>>::set_allowance(&collection, &sender, item, Some(&spender))?;
 	}: {<Pallet<T>>::transfer_from(&collection, &spender, &sender, &receiver, item)?}
 
+	burn_from {
+		bench_init!{
+			owner: sub; collection: collection(owner);
+			owner: cross_from_sub; sender: cross_sub; burner: cross_sub;
+		};
+		let item = create_max_item(&collection, &owner, sender.clone())?;
+		<Pallet<T>>::set_allowance(&collection, &sender, item, Some(&burner))?;
+	}: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item)?}
+
 	set_variable_metadata {
 		let b in 0..CUSTOM_DATA_LIMIT;
 		bench_init!{
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -38,7 +38,7 @@
 	}
 
 	fn burn_from() -> Weight {
-		0
+		<SelfWeightOf<T>>::burn_from()
 	}
 
 	fn set_variable_metadata(bytes: u32) -> Weight {
@@ -100,7 +100,7 @@
 		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
 		if amount == 1 {
 			with_weight(
-				<Pallet<T>>::burn(&self, &sender, token),
+				<Pallet<T>>::burn(self, &sender, token),
 				<CommonWeights<T>>::burn_item(),
 			)
 		} else {
@@ -118,7 +118,7 @@
 		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
 		if amount == 1 {
 			with_weight(
-				<Pallet<T>>::transfer(&self, &from, &to, token),
+				<Pallet<T>>::transfer(self, &from, &to, token),
 				<CommonWeights<T>>::transfer(),
 			)
 		} else {
@@ -137,9 +137,9 @@
 
 		with_weight(
 			if amount == 1 {
-				<Pallet<T>>::set_allowance(&self, &sender, token, Some(&spender))
+				<Pallet<T>>::set_allowance(self, &sender, token, Some(&spender))
 			} else {
-				<Pallet<T>>::set_allowance(&self, &sender, token, None)
+				<Pallet<T>>::set_allowance(self, &sender, token, None)
 			},
 			<CommonWeights<T>>::approve(),
 		)
@@ -157,7 +157,7 @@
 
 		if amount == 1 {
 			with_weight(
-				<Pallet<T>>::transfer_from(&self, &sender, &from, &to, token),
+				<Pallet<T>>::transfer_from(self, &sender, &from, &to, token),
 				<CommonWeights<T>>::transfer_from(),
 			)
 		} else {
@@ -176,7 +176,7 @@
 
 		if amount == 1 {
 			with_weight(
-				<Pallet<T>>::burn_from(&self, &sender, &from, token),
+				<Pallet<T>>::burn_from(self, &sender, &from, token),
 				<CommonWeights<T>>::burn_from(),
 			)
 		} else {
@@ -192,7 +192,7 @@
 	) -> DispatchResultWithPostInfo {
 		let len = data.len();
 		with_weight(
-			<Pallet<T>>::set_variable_metadata(&self, &sender, token, data),
+			<Pallet<T>>::set_variable_metadata(self, &sender, token, data),
 			<CommonWeights<T>>::set_variable_metadata(len as u32),
 		)
 	}
@@ -218,12 +218,12 @@
 	}
 	fn const_metadata(&self, token: TokenId) -> Vec<u8> {
 		<TokenData<T>>::get((self.id, token))
-			.map(|t| t.const_data.clone())
+			.map(|t| t.const_data)
 			.unwrap_or_default()
 	}
 	fn variable_metadata(&self, token: TokenId) -> Vec<u8> {
 		<TokenData<T>>::get((self.id, token))
-			.map(|t| t.variable_data.clone())
+			.map(|t| t.variable_data)
 			.unwrap_or_default()
 	}
 
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -2,18 +2,21 @@
 	char::{REPLACEMENT_CHARACTER, decode_utf16},
 	convert::TryInto,
 };
-use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*};
+use evm_coder::{ToLog, execution::*, generate_stubgen, solidity, solidity_interface, types::*, weight};
 use frame_support::BoundedVec;
 use up_data_structs::TokenId;
 use pallet_evm_coder_substrate::dispatch_to_evm;
 use sp_core::{H160, U256};
 use sp_std::{vec::Vec, vec};
-use pallet_common::{account::CrossAccountId, erc::CommonEvmHandler};
-use pallet_evm_coder_substrate::call_internal;
-use pallet_common::erc::PrecompileOutput;
+use pallet_common::{
+	account::CrossAccountId,
+	erc::{CommonEvmHandler, PrecompileResult},
+};
+use pallet_evm_coder_substrate::call;
 
 use crate::{
 	AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,
+	SelfWeightOf, weights::WeightInfo,
 };
 
 #[derive(ToLog)]
@@ -61,8 +64,10 @@
 		Ok(string::from_utf8_lossy(&self.token_prefix).into())
 	}
 
+	/// Returns token's const_metadata
 	#[solidity(rename_selector = "tokenURI")]
 	fn token_uri(&self, token_id: uint256) -> Result<string> {
+		self.consume_store_reads(1)?;
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
 		Ok(string::from_utf8_lossy(
 			&<TokenData<T>>::get((self.id, token_id))
@@ -79,12 +84,14 @@
 		Ok(index)
 	}
 
+	/// Not implemented
 	fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
 
 	fn total_supply(&self) -> Result<uint256> {
+		self.consume_store_reads(1)?;
 		Ok(<Pallet<T>>::total_supply(self).into())
 	}
 }
@@ -92,17 +99,20 @@
 #[solidity_interface(name = "ERC721", events(ERC721Events))]
 impl<T: Config> NonfungibleHandle<T> {
 	fn balance_of(&self, owner: address) -> Result<uint256> {
+		self.consume_store_reads(1)?;
 		let owner = T::CrossAccountId::from_eth(owner);
 		let balance = <AccountBalance<T>>::get((self.id, owner));
 		Ok(balance.into())
 	}
 	fn owner_of(&self, token_id: uint256) -> Result<address> {
+		self.consume_store_reads(1)?;
 		let token: TokenId = token_id.try_into()?;
 		Ok(*<TokenData<T>>::get((self.id, token))
 			.ok_or("token not found")?
 			.owner
 			.as_eth())
 	}
+	/// Not implemented
 	fn safe_transfer_from_with_data(
 		&mut self,
 		_from: address,
@@ -114,6 +124,7 @@
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
+	/// Not implemented
 	fn safe_transfer_from(
 		&mut self,
 		_from: address,
@@ -125,6 +136,7 @@
 		Err("not implemented".into())
 	}
 
+	#[weight(<SelfWeightOf<T>>::transfer_from())]
 	fn transfer_from(
 		&mut self,
 		caller: caller,
@@ -143,6 +155,7 @@
 		Ok(())
 	}
 
+	#[weight(<SelfWeightOf<T>>::approve())]
 	fn approve(
 		&mut self,
 		caller: caller,
@@ -159,6 +172,7 @@
 		Ok(())
 	}
 
+	/// Not implemented
 	fn set_approval_for_all(
 		&mut self,
 		_caller: caller,
@@ -169,11 +183,13 @@
 		Err("not implemented".into())
 	}
 
+	/// Not implemented
 	fn get_approved(&self, _token_id: uint256) -> Result<address> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
 
+	/// Not implemented
 	fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result<address> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
@@ -182,6 +198,7 @@
 
 #[solidity_interface(name = "ERC721Burnable")]
 impl<T: Config> NonfungibleHandle<T> {
+	#[weight(<SelfWeightOf<T>>::burn_item())]
 	fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let token = token_id.try_into()?;
@@ -197,6 +214,9 @@
 		Ok(false)
 	}
 
+	/// `token_id` should be obtained with `next_token_id` method,
+	/// unlike standard, you can't specify it manually
+	#[weight(<SelfWeightOf<T>>::create_item())]
 	fn mint(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
@@ -223,7 +243,10 @@
 		Ok(true)
 	}
 
+	/// `token_id` should be obtained with `next_token_id` method,
+	/// unlike standard, you can't specify it manually
 	#[solidity(rename_selector = "mintWithTokenURI")]
+	#[weight(<SelfWeightOf<T>>::create_item())]
 	fn mint_with_token_uri(
 		&mut self,
 		caller: caller,
@@ -257,6 +280,7 @@
 		Ok(true)
 	}
 
+	/// Not implemented
 	fn finish_minting(&mut self, _caller: caller) -> Result<bool> {
 		Err("not implementable".into())
 	}
@@ -264,6 +288,7 @@
 
 #[solidity_interface(name = "ERC721UniqueExtensions")]
 impl<T: Config> NonfungibleHandle<T> {
+	#[weight(<SelfWeightOf<T>>::transfer())]
 	fn transfer(
 		&mut self,
 		caller: caller,
@@ -279,6 +304,7 @@
 		Ok(())
 	}
 
+	#[weight(<SelfWeightOf<T>>::burn_from())]
 	fn burn_from(
 		&mut self,
 		caller: caller,
@@ -295,12 +321,14 @@
 	}
 
 	fn next_token_id(&self) -> Result<uint256> {
+		self.consume_store_reads(1)?;
 		Ok(<TokensMinted<T>>::get(self.id)
 			.checked_add(1)
 			.ok_or("item id overflow")?
 			.into())
 	}
 
+	#[weight(<SelfWeightOf<T>>::set_variable_metadata(data.len() as u32))]
 	fn set_variable_metadata(
 		&mut self,
 		caller: caller,
@@ -316,6 +344,7 @@
 	}
 
 	fn get_variable_metadata(&self, token_id: uint256) -> Result<bytes> {
+		self.consume_store_reads(1)?;
 		let token: TokenId = token_id.try_into()?;
 
 		Ok(<TokenData<T>>::get((self.id, token))
@@ -323,6 +352,7 @@
 			.variable_data)
 	}
 
+	#[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]
 	fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
@@ -351,6 +381,7 @@
 	}
 
 	#[solidity(rename_selector = "mintBulkWithTokenURI")]
+	#[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]
 	fn mint_bulk_with_token_uri(
 		&mut self,
 		caller: caller,
@@ -399,16 +430,13 @@
 impl<T: Config> NonfungibleHandle<T> {}
 
 // Not a tests, but code generators
-generate_stubgen!(gen_impl, UniqueNFTCall, true);
-generate_stubgen!(gen_iface, UniqueNFTCall, false);
-
-pub const CODE: &[u8] = include_bytes!("./stubs/UniqueNFT.raw");
+generate_stubgen!(gen_impl, UniqueNFTCall<()>, true);
+generate_stubgen!(gen_iface, UniqueNFTCall<()>, false);
 
 impl<T: Config> CommonEvmHandler for NonfungibleHandle<T> {
 	const CODE: &'static [u8] = include_bytes!("./stubs/UniqueNFT.raw");
 
-	fn call(mut self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileOutput> {
-		let result = call_internal::<UniqueNFTCall, _>(*source, &mut self, value, input);
-		self.0.recorder.evm_to_precompile_output(result)
+	fn call(self, source: &H160, input: &[u8], value: U256) -> Option<PrecompileResult> {
+		call::<T, UniqueNFTCall<T>, _>(*source, self, value, input)
 	}
 }
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -8,6 +8,7 @@
 use pallet_common::{
 	Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, account::CrossAccountId,
 };
+use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
 use sp_core::H160;
 use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
 use sp_std::{vec::Vec, vec};
@@ -114,6 +115,14 @@
 		self.0
 	}
 }
+impl<T: Config> WithRecorder<T> for NonfungibleHandle<T> {
+	fn recorder(&self) -> &SubstrateRecorder<T> {
+		self.0.recorder()
+	}
+	fn into_recorder(self) -> SubstrateRecorder<T> {
+		self.0.into_recorder()
+	}
+}
 impl<T: Config> Deref for NonfungibleHandle<T> {
 	type Target = pallet_common::CollectionHandle<T>;
 
@@ -160,12 +169,11 @@
 		sender: &T::CrossAccountId,
 		token: TokenId,
 	) -> DispatchResult {
-		let token_data = <TokenData<T>>::get((collection.id, token))
-			.ok_or_else(|| <CommonError<T>>::TokenNotFound)?;
+		let token_data =
+			<TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;
 		ensure!(
 			&token_data.owner == sender
-				|| (collection.limits.owner_can_transfer()
-					&& collection.is_owner_or_admin(sender)?),
+				|| (collection.limits.owner_can_transfer() && collection.is_owner_or_admin(sender)),
 			<CommonError<T>>::NoPermission
 		);
 
@@ -188,7 +196,7 @@
 		}
 		// =========
 
-		<Owned<T>>::remove((collection.id, &token_data.owner.clone(), token));
+		<Owned<T>>::remove((collection.id, &token_data.owner, token));
 		<TokensBurnt<T>>::insert(collection.id, burnt);
 		<TokenData<T>>::remove((collection.id, token));
 		let old_spender = <Allowance<T>>::take((collection.id, token));
@@ -198,12 +206,12 @@
 				collection.id,
 				token,
 				sender.clone(),
-				old_spender.clone(),
+				old_spender,
 				0,
 			));
 		}
 
-		collection.log_infallible(ERC721Events::Transfer {
+		collection.log(ERC721Events::Transfer {
 			from: *token_data.owner.as_eth(),
 			to: H160::default(),
 			token_id: token.into(),
@@ -214,7 +222,7 @@
 			token_data.owner,
 			1,
 		));
-		return Ok(());
+		Ok(())
 	}
 
 	pub fn transfer(
@@ -228,12 +236,11 @@
 			<CommonError<T>>::TransferNotAllowed
 		);
 
-		let token_data = <TokenData<T>>::get((collection.id, token))
-			.ok_or_else(|| <CommonError<T>>::TokenNotFound)?;
+		let token_data =
+			<TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;
 		ensure!(
 			&token_data.owner == from
-				|| (collection.limits.owner_can_transfer()
-					&& collection.is_owner_or_admin(from)?),
+				|| (collection.limits.owner_can_transfer() && collection.is_owner_or_admin(from)),
 			<CommonError<T>>::NoPermission
 		);
 
@@ -260,9 +267,6 @@
 		} else {
 			None
 		};
-
-		collection.consume_sstores(4)?;
-		collection.consume_log(3, 0)?;
 
 		// =========
 
@@ -287,7 +291,7 @@
 		}
 		Self::set_allowance_unchecked(collection, from, token, None, true);
 
-		collection.log_infallible(ERC721Events::Transfer {
+		collection.log(ERC721Events::Transfer {
 			from: *from.as_eth(),
 			to: *to.as_eth(),
 			token_id: token.into(),
@@ -307,8 +311,7 @@
 		sender: &T::CrossAccountId,
 		data: Vec<CreateItemData<T>>,
 	) -> DispatchResult {
-		let unrestricted_minting = collection.is_owner_or_admin(sender)?;
-		if !unrestricted_minting {
+		if !collection.is_owner_or_admin(sender) {
 			ensure!(
 				collection.mint_mode,
 				<CommonError<T>>::PublicMintingNotAllowed
@@ -322,14 +325,6 @@
 
 		for data in data.iter() {
 			<PalletCommon<T>>::ensure_correct_receiver(&data.owner)?;
-			if !data.const_data.is_empty() {
-				collection.consume_sstore()?;
-			}
-			if !data.variable_data.is_empty() {
-				collection.consume_sstore()?;
-			}
-			collection.consume_sstore()?;
-			collection.consume_log(3, 0)?;
 		}
 
 		let first_token = <TokensMinted<T>>::get(collection.id);
@@ -340,7 +335,6 @@
 			tokens_minted <= collection.limits.token_limit(),
 			<CommonError<T>>::CollectionTokenLimitExceeded
 		);
-		collection.consume_sstore()?;
 
 		let mut balances = BTreeMap::new();
 		for data in &data {
@@ -354,7 +348,6 @@
 				<CommonError<T>>::AccountTokenLimitExceeded,
 			);
 		}
-		collection.consume_sstores(balances.len())?;
 
 		// =========
 
@@ -375,7 +368,7 @@
 			);
 			<Owned<T>>::insert((collection.id, &data.owner, token), true);
 
-			collection.log_infallible(ERC721Events::Transfer {
+			collection.log(ERC721Events::Transfer {
 				from: H160::default(),
 				to: *data.owner.as_eth(),
 				token_id: token.into(),
@@ -402,7 +395,7 @@
 			<Allowance<T>>::insert((collection.id, token), spender);
 			// In ERC721 there is only one possible approved user of token, so we set
 			// approved user to spender
-			collection.log_infallible(ERC721Events::Approval {
+			collection.log(ERC721Events::Approval {
 				owner: *sender.as_eth(),
 				approved: *spender.as_eth(),
 				token_id: token.into(),
@@ -415,7 +408,7 @@
 						collection.id,
 						token,
 						sender.clone(),
-						old_owner.clone(),
+						old_owner,
 						0,
 					));
 				}
@@ -432,7 +425,7 @@
 			if !assume_implicit_eth {
 				// In ERC721 there is only one possible approved user of token, so we set
 				// approved user to zero address
-				collection.log_infallible(ERC721Events::Approval {
+				collection.log(ERC721Events::Approval {
 					owner: *sender.as_eth(),
 					approved: H160::default(),
 					token_id: token.into(),
@@ -445,7 +438,7 @@
 					collection.id,
 					token,
 					sender.clone(),
-					old_spender.clone(),
+					old_spender,
 					0,
 				));
 			}
@@ -459,9 +452,9 @@
 		spender: Option<&T::CrossAccountId>,
 	) -> DispatchResult {
 		if collection.access == AccessMode::AllowList {
-			collection.check_allowlist(&sender)?;
+			collection.check_allowlist(sender)?;
 			if let Some(spender) = spender {
-				collection.check_allowlist(&spender)?;
+				collection.check_allowlist(spender)?;
 			}
 		}
 
@@ -472,7 +465,7 @@
 			<TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;
 		if &token_data.owner != sender {
 			ensure!(
-				collection.ignores_owned_amount(sender)?,
+				collection.ignores_owned_amount(sender),
 				<CommonError<T>>::CantApproveMoreThanOwned
 			);
 		}
@@ -500,14 +493,14 @@
 
 		if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {
 			ensure!(
-				collection.ignores_allowance(spender)?,
+				collection.ignores_allowance(spender),
 				<CommonError<T>>::TokenValueNotEnough
 			);
 		}
 
 		// =========
 
-		Self::transfer(collection, &from, to, token)?;
+		Self::transfer(collection, from, to, token)?;
 		// Allowance is reset in [`transfer`]
 		Ok(())
 	}
@@ -528,14 +521,14 @@
 
 		if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {
 			ensure!(
-				collection.ignores_allowance(spender)?,
+				collection.ignores_allowance(spender),
 				<CommonError<T>>::TokenValueNotEnough
 			);
 		}
 
 		// =========
 
-		Self::burn(collection, &from, token)
+		Self::burn(collection, from, token)
 	}
 
 	pub fn set_variable_metadata(
@@ -551,8 +544,6 @@
 		let token_data =
 			<TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;
 		collection.check_can_update_meta(sender, &token_data.owner)?;
-
-		collection.consume_sstore()?;
 
 		// =========
 
modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -51,6 +51,17 @@
 	event MintingFinished();
 }
 
+// Selector: 42966c68
+contract ERC721Burnable is Dummy, ERC165 {
+	// Selector: burn(uint256) 42966c68
+	function burn(uint256 tokenId) public {
+		require(false, stub_error);
+		tokenId;
+		dummy = 0;
+	}
+}
+
+// Selector: 58800161
 contract ERC721 is Dummy, ERC165, ERC721Events {
 	// Selector: balanceOf(address) 70a08231
 	function balanceOf(address owner) public view returns (uint256) {
@@ -68,6 +79,8 @@
 		return 0x0000000000000000000000000000000000000000;
 	}
 
+	// Not implemented
+	//
 	// Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672
 	function safeTransferFromWithData(
 		address from,
@@ -83,6 +96,8 @@
 		dummy = 0;
 	}
 
+	// Not implemented
+	//
 	// Selector: safeTransferFrom(address,address,uint256) 42842e0e
 	function safeTransferFrom(
 		address from,
@@ -117,6 +132,8 @@
 		dummy = 0;
 	}
 
+	// Not implemented
+	//
 	// Selector: setApprovalForAll(address,bool) a22cb465
 	function setApprovalForAll(address operator, bool approved) public {
 		require(false, stub_error);
@@ -125,6 +142,8 @@
 		dummy = 0;
 	}
 
+	// Not implemented
+	//
 	// Selector: getApproved(uint256) 081812fc
 	function getApproved(uint256 tokenId) public view returns (address) {
 		require(false, stub_error);
@@ -133,6 +152,8 @@
 		return 0x0000000000000000000000000000000000000000;
 	}
 
+	// Not implemented
+	//
 	// Selector: isApprovedForAll(address,address) e985e9c5
 	function isApprovedForAll(address owner, address operator)
 		public
@@ -147,45 +168,7 @@
 	}
 }
 
-contract ERC721Burnable is Dummy, ERC165 {
-	// Selector: burn(uint256) 42966c68
-	function burn(uint256 tokenId) public {
-		require(false, stub_error);
-		tokenId;
-		dummy = 0;
-	}
-}
-
-contract ERC721Enumerable is Dummy, ERC165 {
-	// Selector: tokenByIndex(uint256) 4f6ccce7
-	function tokenByIndex(uint256 index) public view returns (uint256) {
-		require(false, stub_error);
-		index;
-		dummy;
-		return 0;
-	}
-
-	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
-	function tokenOfOwnerByIndex(address owner, uint256 index)
-		public
-		view
-		returns (uint256)
-	{
-		require(false, stub_error);
-		owner;
-		index;
-		dummy;
-		return 0;
-	}
-
-	// Selector: totalSupply() 18160ddd
-	function totalSupply() public view returns (uint256) {
-		require(false, stub_error);
-		dummy;
-		return 0;
-	}
-}
-
+// Selector: 5b5e139f
 contract ERC721Metadata is Dummy, ERC165 {
 	// Selector: name() 06fdde03
 	function name() public view returns (string memory) {
@@ -201,6 +184,8 @@
 		return "";
 	}
 
+	// Returns token's const_metadata
+	//
 	// Selector: tokenURI(uint256) c87b56dd
 	function tokenURI(uint256 tokenId) public view returns (string memory) {
 		require(false, stub_error);
@@ -210,6 +195,7 @@
 	}
 }
 
+// Selector: 68ccfe89
 contract ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {
 	// Selector: mintingFinished() 05d2035b
 	function mintingFinished() public view returns (bool) {
@@ -218,6 +204,9 @@
 		return false;
 	}
 
+	// `token_id` should be obtained with `next_token_id` method,
+	// unlike standard, you can't specify it manually
+	//
 	// Selector: mint(address,uint256) 40c10f19
 	function mint(address to, uint256 tokenId) public returns (bool) {
 		require(false, stub_error);
@@ -227,6 +216,9 @@
 		return false;
 	}
 
+	// `token_id` should be obtained with `next_token_id` method,
+	// unlike standard, you can't specify it manually
+	//
 	// Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f
 	function mintWithTokenURI(
 		address to,
@@ -241,6 +233,8 @@
 		return false;
 	}
 
+	// Not implemented
+	//
 	// Selector: finishMinting() 7d64bcb4
 	function finishMinting() public returns (bool) {
 		require(false, stub_error);
@@ -249,6 +243,40 @@
 	}
 }
 
+// Selector: 780e9d63
+contract ERC721Enumerable is Dummy, ERC165 {
+	// Selector: tokenByIndex(uint256) 4f6ccce7
+	function tokenByIndex(uint256 index) public view returns (uint256) {
+		require(false, stub_error);
+		index;
+		dummy;
+		return 0;
+	}
+
+	// Not implemented
+	//
+	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
+	function tokenOfOwnerByIndex(address owner, uint256 index)
+		public
+		view
+		returns (uint256)
+	{
+		require(false, stub_error);
+		owner;
+		index;
+		dummy;
+		return 0;
+	}
+
+	// Selector: totalSupply() 18160ddd
+	function totalSupply() public view returns (uint256) {
+		require(false, stub_error);
+		dummy;
+		return 0;
+	}
+}
+
+// Selector: e562194d
 contract ERC721UniqueExtensions is Dummy, ERC165 {
 	// Selector: transfer(address,uint256) a9059cbb
 	function transfer(address to, uint256 tokenId) public {
modifiedpallets/nonfungible/src/weights.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/weights.rs
+++ b/pallets/nonfungible/src/weights.rs
@@ -25,6 +25,7 @@
 #![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;
@@ -37,6 +38,7 @@
 	fn transfer() -> Weight;
 	fn approve() -> Weight;
 	fn transfer_from() -> Weight;
+	fn burn_from() -> Weight;
 	fn set_variable_metadata(b: u32, ) -> Weight;
 }
 
@@ -98,6 +100,15 @@
 			.saturating_add(T::DbWeight::get().reads(4 as Weight))
 			.saturating_add(T::DbWeight::get().writes(6 as Weight))
 	}
+	// Storage: Nonfungible Allowance (r:1 w:1)
+	// Storage: Nonfungible TokenData (r:1 w:1)
+	// Storage: Nonfungible TokensBurnt (r:1 w:1)
+	// Storage: Nonfungible Owned (r:0 w:1)
+	fn burn_from() -> Weight {
+		(53_429_000 as Weight)
+			.saturating_add(T::DbWeight::get().reads(3 as Weight))
+			.saturating_add(T::DbWeight::get().writes(4 as Weight))
+	}
 	// Storage: Nonfungible TokenData (r:1 w:1)
 	fn set_variable_metadata(_b: u32, ) -> Weight {
 		(6_380_000 as Weight)
@@ -163,6 +174,15 @@
 			.saturating_add(RocksDbWeight::get().reads(4 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(6 as Weight))
 	}
+	// Storage: Nonfungible Allowance (r:1 w:1)
+	// Storage: Nonfungible TokenData (r:1 w:1)
+	// Storage: Nonfungible TokensBurnt (r:1 w:1)
+	// Storage: Nonfungible Owned (r:0 w:1)
+	fn burn_from() -> Weight {
+		(53_429_000 as Weight)
+			.saturating_add(RocksDbWeight::get().reads(3 as Weight))
+			.saturating_add(RocksDbWeight::get().writes(4 as Weight))
+	}
 	// Storage: Nonfungible TokenData (r:1 w:1)
 	fn set_variable_metadata(_b: u32, ) -> Weight {
 		(6_380_000 as Weight)
modifiedpallets/refungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/refungible/Cargo.toml
+++ b/pallets/refungible/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "pallet-refungible"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies.codec]
 default-features = false
modifiedpallets/refungible/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/refungible/src/benchmarking.rs
+++ b/pallets/refungible/src/benchmarking.rs
@@ -149,6 +149,16 @@
 		<Pallet<T>>::set_allowance(&collection, &sender, &spender, item, 200)?;
 	}: {<Pallet<T>>::transfer_from(&collection, &spender, &sender, &receiver, item, 200)?}
 
+	// Both source account and token is destroyed
+	burn_from {
+		bench_init!{
+			owner: sub; collection: collection(owner);
+			owner: cross_from_sub; sender: cross_sub; burner: cross_sub;
+		};
+		let item = create_max_item(&collection, &owner, [(sender.clone(), 200)])?;
+		<Pallet<T>>::set_allowance(&collection, &sender, &burner, item, 200)?;
+	}: {<Pallet<T>>::burn_from(&collection, &burner, &sender, item, 200)?}
+
 	set_variable_metadata {
 		let b in 0..CUSTOM_DATA_LIMIT;
 		bench_init!{
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -58,7 +58,7 @@
 	}
 
 	fn burn_from() -> Weight {
-		0
+		<SelfWeightOf<T>>::burn_from()
 	}
 
 	fn set_variable_metadata(bytes: u32) -> Weight {
@@ -135,7 +135,7 @@
 		amount: u128,
 	) -> DispatchResultWithPostInfo {
 		with_weight(
-			<Pallet<T>>::transfer(&self, &from, &to, token, amount),
+			<Pallet<T>>::transfer(self, &from, &to, token, amount),
 			<CommonWeights<T>>::transfer(),
 		)
 	}
@@ -148,7 +148,7 @@
 		amount: u128,
 	) -> DispatchResultWithPostInfo {
 		with_weight(
-			<Pallet<T>>::set_allowance(&self, &sender, &spender, token, amount),
+			<Pallet<T>>::set_allowance(self, &sender, &spender, token, amount),
 			<CommonWeights<T>>::approve(),
 		)
 	}
@@ -162,7 +162,7 @@
 		amount: u128,
 	) -> DispatchResultWithPostInfo {
 		with_weight(
-			<Pallet<T>>::transfer_from(&self, &sender, &from, &to, token, amount),
+			<Pallet<T>>::transfer_from(self, &sender, &from, &to, token, amount),
 			<CommonWeights<T>>::transfer_from(),
 		)
 	}
@@ -175,7 +175,7 @@
 		amount: u128,
 	) -> DispatchResultWithPostInfo {
 		with_weight(
-			<Pallet<T>>::burn_from(&self, &sender, &from, token, amount),
+			<Pallet<T>>::burn_from(self, &sender, &from, token, amount),
 			<CommonWeights<T>>::burn_from(),
 		)
 	}
@@ -188,7 +188,7 @@
 	) -> DispatchResultWithPostInfo {
 		let len = data.len();
 		with_weight(
-			<Pallet<T>>::set_variable_metadata(&self, &sender, token, data),
+			<Pallet<T>>::set_variable_metadata(self, &sender, token, data),
 			<CommonWeights<T>>::set_variable_metadata(len as u32),
 		)
 	}
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -11,7 +11,7 @@
 		_source: &sp_core::H160,
 		_input: &[u8],
 		_value: sp_core::U256,
-	) -> Option<pallet_common::erc::PrecompileOutput> {
+	) -> Option<pallet_common::erc::PrecompileResult> {
 		// TODO: Implement RFT variant of ERC721
 		None
 	}
@@ -27,7 +27,7 @@
 		_source: &sp_core::H160,
 		_input: &[u8],
 		_value: sp_core::U256,
-	) -> Option<pallet_common::erc::PrecompileOutput> {
+	) -> Option<pallet_common::erc::PrecompileResult> {
 		// TODO: Implement RFT variant of ERC20
 		None
 	}
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -191,7 +191,7 @@
 		<Balance<T>>::remove_prefix((collection.id, token_id), None);
 		<Allowance<T>>::remove_prefix((collection.id, token_id), None);
 		// TODO: ERC721 transfer event
-		return Ok(());
+		Ok(())
 	}
 
 	pub fn burn(
@@ -361,8 +361,7 @@
 		sender: &T::CrossAccountId,
 		data: Vec<CreateItemData<T>>,
 	) -> DispatchResult {
-		let unrestricted_minting = collection.is_owner_or_admin(sender)?;
-		if !unrestricted_minting {
+		if !collection.is_owner_or_admin(sender) {
 			ensure!(
 				collection.mint_mode,
 				<CommonError<T>>::PublicMintingNotAllowed
@@ -370,8 +369,8 @@
 			collection.check_allowlist(sender)?;
 
 			for item in data.iter() {
-				for (user, _) in &item.users {
-					collection.check_allowlist(&user)?;
+				for user in item.users.keys() {
+					collection.check_allowlist(user)?;
 				}
 			}
 		}
@@ -412,7 +411,7 @@
 
 		let mut balances = BTreeMap::new();
 		for data in &data {
-			for (owner, _) in &data.users {
+			for owner in data.users.keys() {
 				let balance = balances
 					.entry(owner)
 					.or_insert_with(|| <AccountBalance<T>>::get((collection.id, owner)));
@@ -490,15 +489,15 @@
 		amount: u128,
 	) -> DispatchResult {
 		if collection.access == AccessMode::AllowList {
-			collection.check_allowlist(&sender)?;
-			collection.check_allowlist(&spender)?;
+			collection.check_allowlist(sender)?;
+			collection.check_allowlist(spender)?;
 		}
 
 		<PalletCommon<T>>::ensure_correct_receiver(spender)?;
 
 		if <Balance<T>>::get((collection.id, token, sender)) < amount {
 			ensure!(
-				collection.ignores_owned_amount(sender)? && Self::token_exists(collection, token),
+				collection.ignores_owned_amount(sender) && Self::token_exists(collection, token),
 				<CommonError<T>>::CantApproveMoreThanOwned
 			);
 		}
@@ -529,7 +528,7 @@
 			<Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);
 		if allowance.is_none() {
 			ensure!(
-				collection.ignores_allowance(spender)?,
+				collection.ignores_allowance(spender),
 				<CommonError<T>>::TokenValueNotEnough
 			);
 		}
@@ -562,7 +561,7 @@
 			<Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);
 		if allowance.is_none() {
 			ensure!(
-				collection.ignores_allowance(spender)?,
+				collection.ignores_allowance(spender),
 				<CommonError<T>>::TokenValueNotEnough
 			);
 		}
@@ -591,7 +590,6 @@
 			&T::CrossAccountId::from_sub(collection.owner.clone()),
 		)?;
 
-		collection.consume_sstore()?;
 		let token_data = <TokenData<T>>::get((collection.id, token));
 
 		// =========
modifiedpallets/refungible/src/weights.rsdiffbeforeafterboth
--- a/pallets/refungible/src/weights.rs
+++ b/pallets/refungible/src/weights.rs
@@ -25,6 +25,7 @@
 #![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;
@@ -44,6 +45,7 @@
 	fn transfer_from_creating() -> Weight;
 	fn transfer_from_removing() -> Weight;
 	fn transfer_from_creating_removing() -> Weight;
+	fn burn_from() -> Weight;
 	fn set_variable_metadata(b: u32, ) -> Weight;
 }
 
@@ -166,6 +168,18 @@
 			.saturating_add(T::DbWeight::get().reads(5 as Weight))
 			.saturating_add(T::DbWeight::get().writes(7 as Weight))
 	}
+	// Storage: Refungible Allowance (r:1 w:1)
+	// Storage: Refungible TotalSupply (r:1 w:1)
+	// Storage: Refungible Balance (r:1 w:1)
+	// Storage: Refungible AccountBalance (r:1 w:1)
+	// Storage: Refungible TokensBurnt (r:1 w:1)
+	// Storage: Refungible TokenData (r:0 w:1)
+	// Storage: Refungible Owned (r:0 w:1)
+	fn burn_from() -> Weight {
+		(60_903_000 as Weight)
+			.saturating_add(T::DbWeight::get().reads(5 as Weight))
+			.saturating_add(T::DbWeight::get().writes(7 as Weight))
+	}
 	// Storage: Refungible TokenData (r:1 w:1)
 	fn set_variable_metadata(_b: u32, ) -> Weight {
 		(6_801_000 as Weight)
@@ -292,6 +306,18 @@
 			.saturating_add(RocksDbWeight::get().reads(5 as Weight))
 			.saturating_add(RocksDbWeight::get().writes(7 as Weight))
 	}
+	// Storage: Refungible Allowance (r:1 w:1)
+	// Storage: Refungible TotalSupply (r:1 w:1)
+	// Storage: Refungible Balance (r:1 w:1)
+	// Storage: Refungible AccountBalance (r:1 w:1)
+	// Storage: Refungible TokensBurnt (r:1 w:1)
+	// Storage: Refungible TokenData (r:0 w:1)
+	// Storage: Refungible Owned (r:0 w:1)
+	fn burn_from() -> Weight {
+		(60_903_000 as Weight)
+			.saturating_add(RocksDbWeight::get().reads(5 as Weight))
+			.saturating_add(RocksDbWeight::get().writes(7 as Weight))
+	}
 	// Storage: Refungible TokenData (r:1 w:1)
 	fn set_variable_metadata(_b: u32, ) -> Weight {
 		(6_801_000 as Weight)
modifiedpallets/scheduler/Cargo.tomldiffbeforeafterboth
--- a/pallets/scheduler/Cargo.toml
+++ b/pallets/scheduler/Cargo.toml
@@ -2,7 +2,7 @@
 name = "pallet-unq-scheduler"
 version = "0.1.0"
 authors = ["Unique Network <support@uniquenetwork.io>"]
-edition = "2018"
+edition = "2021"
 license = "All Rights Reserved"
 homepage = "https://unique.network"
 repository = "https://github.com/UniqueNetwork/unique-chain"
@@ -20,7 +20,7 @@
 sp-io = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 frame-benchmarking = { default-features = false, optional = true, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
 
-up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/UniqueNetwork/pallet-sponsoring" } 
+up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/UniqueNetwork/pallet-sponsoring" }
 log = { version = "0.4.14", default-features = false }
 
 [dev-dependencies]
modifiedpallets/scheduler/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/scheduler/src/benchmarking.rs
+++ b/pallets/scheduler/src/benchmarking.rs
@@ -33,7 +33,7 @@
 // Add `n` named items to the schedule
 fn fill_schedule<T: Config>(when: T::BlockNumber, n: u32) -> Result<(), &'static str> {
 	// Essentially a no-op call.
-	let call = frame_system::Call::set_storage(vec![]);
+	let call = frame_system::Call::set_storage { items: vec![] };
 	for i in 0..n {
 		// Named schedule is strictly heavier than anonymous
 		Scheduler::<T>::do_schedule_named(
@@ -61,7 +61,7 @@
 		let periodic = Some((T::BlockNumber::one(), 100));
 		let priority = 0;
 		// Essentially a no-op call.
-		let call = Box::new(frame_system::Call::set_storage(vec![]).into());
+		let call = Box::new(frame_system::Call::set_storage { items: vec![] }.into());
 
 		fill_schedule::<T>(when, s)?;
 	}: _(RawOrigin::Root, when, periodic, priority, call)
@@ -98,7 +98,7 @@
 		let periodic = Some((T::BlockNumber::one(), 100));
 		let priority = 0;
 		// Essentially a no-op call.
-		let call = Box::new(frame_system::Call::set_storage(vec![]).into());
+		let call = Box::new(frame_system::Call::set_storage { items: vec![] }.into());
 
 		fill_schedule::<T>(when, s)?;
 	}: _(RawOrigin::Root, id, when, periodic, priority, call)
modifiedpallets/unique/Cargo.tomldiffbeforeafterboth
--- a/pallets/unique/Cargo.toml
+++ b/pallets/unique/Cargo.toml
@@ -127,11 +127,11 @@
 scale-info = { version = "1.0.0", default-features = false, features = [
     "derive",
 ] }
-ethereum = { version = "0.9", git = "https://github.com/purestake/ethereum", branch = "joshy-scale-info", default-features = false }
+ethereum = { version = "0.10.0", default-features = false }
 rlp = { default-features = false, version = "0.5.0" }
 sp-api = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.12" }
 
-up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/UniqueNetwork/pallet-sponsoring" } 
+up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/UniqueNetwork/pallet-sponsoring" }
 up-evm-mapping = { default-features = false, path = "../../primitives/evm-mapping" }
 evm-coder = { default-features = false, path = "../../crates/evm-coder" }
 pallet-evm-coder-substrate = { default-features = false, path = "../../pallets/evm-coder-substrate" }
@@ -139,9 +139,9 @@
     "serde_no_std",
 ] }
 
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
 hex-literal = "0.3.3"
 
 pallet-common = { default-features = false, path = "../common" }
modifiedpallets/unique/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/unique/src/benchmarking.rs
+++ b/pallets/unique/src/benchmarking.rs
@@ -155,12 +155,14 @@
 
 		let cl = CollectionLimits {
 			account_token_ownership_limit: Some(0),
-			sponsored_data_size: 0,
-			token_limit: 1,
-			sponsor_transfer_timeout: 0,
-			owner_can_destroy: true,
-			owner_can_transfer: true,
+			sponsored_data_size: Some(0),
+			token_limit: Some(1),
+			sponsor_transfer_timeout: Some(0),
+			sponsor_approve_timeout: None,
+			owner_can_destroy: Some(true),
+			owner_can_transfer: Some(true),
 			sponsored_data_rate_limit: None,
+			transfers_enabled: Some(true),
 		};
 	}: set_collection_limits(RawOrigin::Signed(caller.clone()), collection, cl)
 
modifiedpallets/unique/src/dispatch.rsdiffbeforeafterboth
--- a/pallets/unique/src/dispatch.rs
+++ b/pallets/unique/src/dispatch.rs
@@ -83,10 +83,6 @@
 		_ => {}
 	}
 
-	// TODO: Make submit_logs infallible, but it shouldn't fail here anyway
-	dispatched
-		.into_inner()
-		.submit_logs()
-		.expect("should succeed");
+	dispatched.into_inner().submit_logs();
 	result
 }
modifiedpallets/unique/src/eth/mod.rsdiffbeforeafterboth
--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -1,5 +1,6 @@
 pub mod sponsoring;
 
+use fp_evm::PrecompileResult;
 use pallet_common::{
 	CollectionById,
 	erc::CommonEvmHandler,
@@ -10,7 +11,6 @@
 use pallet_refungible::{RefungibleHandle, erc::RefungibleTokenHandle};
 use sp_std::borrow::ToOwned;
 use sp_std::vec::Vec;
-use pallet_evm::{PrecompileOutput};
 use sp_core::{H160, U256};
 use crate::{CollectionMode, Config, dispatch::Dispatched};
 use pallet_common::CollectionHandle;
@@ -54,7 +54,7 @@
 		gas_limit: u64,
 		input: &[u8],
 		value: U256,
-	) -> Option<PrecompileOutput> {
+	) -> Option<PrecompileResult> {
 		if let Some(collection_id) = map_eth_to_id(target) {
 			let collection = <CollectionHandle<T>>::new_with_gas_limit(collection_id, gas_limit)?;
 			let dispatched = Dispatched::dispatch(collection);
modifiedpallets/unique/src/eth/sponsoring.rsdiffbeforeafterboth
--- a/pallets/unique/src/eth/sponsoring.rs
+++ b/pallets/unique/src/eth/sponsoring.rs
@@ -27,7 +27,7 @@
 		let (method_id, mut reader) = AbiReader::new_call(&call.1).ok()?;
 		match &collection.mode {
 			crate::CollectionMode::NFT => {
-				let call = UniqueNFTCall::parse(method_id, &mut reader).ok()??;
+				let call = <UniqueNFTCall<T>>::parse(method_id, &mut reader).ok()??;
 				match call {
 					UniqueNFTCall::ERC721UniqueExtensions(
 						ERC721UniqueExtensionsCall::Transfer { token_id, .. },
@@ -49,7 +49,7 @@
 				}
 			}
 			crate::CollectionMode::Fungible(_) => {
-				let call = UniqueFungibleCall::parse(method_id, &mut reader).ok()??;
+				let call = <UniqueFungibleCall<T>>::parse(method_id, &mut reader).ok()??;
 				#[allow(clippy::single_match)]
 				match call {
 					UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -16,7 +16,7 @@
 pub use serde::{Serialize, Deserialize};
 
 pub use frame_support::{
-	construct_runtime, decl_module, decl_storage, decl_error,
+	construct_runtime, decl_module, decl_storage, decl_error, decl_event,
 	dispatch::DispatchResult,
 	ensure, fail, parameter_types,
 	traits::{
@@ -87,6 +87,7 @@
 		OwnerPermissionsCantBeReverted,
 	}
 }
+
 pub trait Config:
 	system::Config
 	+ pallet_evm_coder_substrate::Config
@@ -97,10 +98,141 @@
 	+ Sized
 	+ TypeInfo
 {
+	type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
+
 	/// Weight information for extrinsics in this pallet.
 	type WeightInfo: WeightInfo;
 }
 
+decl_event! {
+	pub enum Event<T>
+	where
+		<T as frame_system::Config>::AccountId,
+		<T as pallet_common::Config>::CrossAccountId,
+	{
+		/// Collection sponsor was removed
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		CollectionSponsorRemoved(CollectionId),
+
+		/// Collection admin was added
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		///
+		/// * admin:  Admin address.
+		CollectionAdminAdded(CollectionId, CrossAccountId),
+
+		/// Collection owned was change
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		///
+		/// * owner:  New owner address.
+		CollectionOwnedChanged(CollectionId, AccountId),
+
+		/// Collection sponsor was set
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		///
+		/// * owner:  New sponsor address.
+		CollectionSponsorSet(CollectionId, AccountId),
+
+		/// const on chain schema was set
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		ConstOnChainSchemaSet(CollectionId),
+
+		/// New sponsor was confirm
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		///
+		/// * sponsor:  New sponsor address.
+		SponsorshipConfirmed(CollectionId, AccountId),
+
+		/// Collection admin was removed
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		///
+		/// * admin:  Admin address.
+		CollectionAdminRemoved(CollectionId, CrossAccountId),
+
+		/// Address was remove from allow list
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		///
+		/// * user:  Address.
+		AllowListAddressRemoved(CollectionId, CrossAccountId),
+
+		/// Address was add to allow list
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		///
+		/// * user:  Address.
+		AllowListAddressAdded(CollectionId, CrossAccountId),
+
+		/// Collection limits was set
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		CollectionLimitSet(CollectionId),
+
+		/// Mint permission	was set
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		MintPermissionSet(CollectionId),
+
+		/// Offchain schema was set
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		OffchainSchemaSet(CollectionId),
+
+		/// Public access mode was set
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		///
+		/// * mode: New access state.
+		PublicAccessModeSet(CollectionId, AccessMode),
+
+		/// Schema version was set
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		SchemaVersionSet(CollectionId),
+
+		/// Variable on chain schema was set
+		///
+		/// # Arguments
+		///
+		/// * collection_id: Globally unique collection identifier.
+		VariableOnChainSchemaSet(CollectionId),
+	}
+}
+
 type SelfWeightOf<T> = <T as Config>::WeightInfo;
 
 // # Used definitions
@@ -162,6 +294,8 @@
 	{
 		type Error = Error<T>;
 
+		fn deposit_event() = default;
+
 		fn on_initialize(_now: T::BlockNumber) -> Weight {
 			0
 		}
@@ -195,7 +329,7 @@
 
 			// Create new collection
 			let new_collection = Collection {
-				owner: who.clone(),
+				owner: who,
 				name: collection_name,
 				mode: mode.clone(),
 				mint_mode: false,
@@ -289,6 +423,11 @@
 				true,
 			)?;
 
+			Self::deposit_event(Event::<T>::AllowListAddressAdded(
+				collection_id,
+				address
+			));
+
 			Ok(())
 		}
 
@@ -318,6 +457,11 @@
 				false,
 			)?;
 
+			<Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(
+				collection_id,
+				address
+			));
+
 			Ok(())
 		}
 
@@ -341,7 +485,13 @@
 			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
 			target_collection.check_is_owner(&sender)?;
 
-			target_collection.access = mode;
+			target_collection.access = mode.clone();
+
+			<Pallet<T>>::deposit_event(Event::<T>::PublicAccessModeSet(
+				collection_id,
+				mode
+			));
+
 			target_collection.save()
 		}
 
@@ -368,6 +518,11 @@
 			target_collection.check_is_owner(&sender)?;
 
 			target_collection.mint_mode = mint_permission;
+
+			<Pallet<T>>::deposit_event(Event::<T>::MintPermissionSet(
+				collection_id
+			));
+
 			target_collection.save()
 		}
 
@@ -391,7 +546,12 @@
 			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
 			target_collection.check_is_owner(&sender)?;
 
-			target_collection.owner = new_owner;
+			target_collection.owner = new_owner.clone();
+			<Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(
+				collection_id,
+				new_owner
+			));
+
 			target_collection.save()
 		}
 
@@ -414,6 +574,11 @@
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
 			let collection = <CollectionHandle<T>>::try_get(collection_id)?;
 
+			<Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(
+				collection_id,
+				new_admin_id.clone()
+			));
+
 			<PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)
 		}
 
@@ -435,6 +600,11 @@
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
 			let collection = <CollectionHandle<T>>::try_get(collection_id)?;
 
+			<Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(
+				collection_id,
+				account_id.clone()
+			));
+
 			<PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)
 		}
 
@@ -455,7 +625,13 @@
 			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
 			target_collection.check_is_owner(&sender)?;
 
-			target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor);
+			target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor.clone());
+
+			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(
+				collection_id,
+				new_sponsor
+			));
+
 			target_collection.save()
 		}
 
@@ -477,7 +653,13 @@
 				Error::<T>::ConfirmUnsetSponsorFail
 			);
 
-			target_collection.sponsorship = SponsorshipState::Confirmed(sender);
+			target_collection.sponsorship = SponsorshipState::Confirmed(sender.clone());
+
+			<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(
+				collection_id,
+				sender
+			));
+
 			target_collection.save()
 		}
 
@@ -499,6 +681,10 @@
 			target_collection.check_is_owner(&sender)?;
 
 			target_collection.sponsorship = SponsorshipState::Disabled;
+
+			<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(
+				collection_id
+			));
 			target_collection.save()
 		}
 
@@ -793,6 +979,11 @@
 			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
 			target_collection.check_is_owner_or_admin(&sender)?;
 			target_collection.schema_version = version;
+
+			<Pallet<T>>::deposit_event(Event::<T>::SchemaVersionSet(
+				collection_id
+			));
+
 			target_collection.save()
 		}
 
@@ -823,6 +1014,11 @@
 			ensure!(schema.len() as u32 <= OFFCHAIN_SCHEMA_LIMIT, "");
 
 			target_collection.offchain_schema = schema;
+
+			<Pallet<T>>::deposit_event(Event::<T>::OffchainSchemaSet(
+				collection_id
+			));
+
 			target_collection.save()
 		}
 
@@ -853,6 +1049,11 @@
 			ensure!(schema.len() as u32 <= CONST_ON_CHAIN_SCHEMA_LIMIT, "");
 
 			target_collection.const_on_chain_schema = schema;
+
+			<Pallet<T>>::deposit_event(Event::<T>::ConstOnChainSchemaSet(
+				collection_id
+			));
+
 			target_collection.save()
 		}
 
@@ -883,6 +1084,11 @@
 			ensure!(schema.len() as u32 <= VARIABLE_ON_CHAIN_SCHEMA_LIMIT, "");
 
 			target_collection.variable_on_chain_schema = schema;
+
+			<Pallet<T>>::deposit_event(Event::<T>::VariableOnChainSchemaSet(
+				collection_id
+			));
+
 			target_collection.save()
 		}
 
@@ -949,6 +1155,10 @@
 
 			target_collection.limits = new_limit;
 
+			<Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(
+				collection_id
+			));
+
 			target_collection.save()
 		}
 	}
modifiedpallets/unique/src/mock.rsdiffbeforeafterboth
--- a/pallets/unique/src/mock.rs
+++ b/pallets/unique/src/mock.rs
@@ -1,7 +1,7 @@
 #![allow(clippy::from_over_into)]
 
 use crate as pallet_template;
-use sp_core::H256;
+use sp_core::{H160, H256};
 use frame_support::{parameter_types, traits::Everything, weights::IdentityFee};
 use sp_runtime::{
 	traits::{BlakeTwo256, IdentityLookup},
@@ -159,15 +159,16 @@
 pub struct TestEtheremTransactionSender;
 impl pallet_ethereum::EthereumTransactionSender for TestEtheremTransactionSender {
 	fn submit_logs_transaction(
+		_source: H160,
 		_tx: pallet_ethereum::Transaction,
 		_logs: Vec<pallet_ethereum::Log>,
-	) -> Result<(), sp_runtime::DispatchError> {
-		Ok(())
+	) {
 	}
 }
 
 impl pallet_evm_coder_substrate::Config for Test {
 	type EthereumTransactionSender = TestEtheremTransactionSender;
+	type GasWeightMapping = ();
 }
 
 impl pallet_common::Config for Test {
modifiedpallets/unique/src/tests.rsdiffbeforeafterboth
before · pallets/unique/src/tests.rs
1// Tests to be written here2use super::*;3use crate::mock::*;4use crate::{AccessMode, CollectionMode};5use up_data_structs::{6	COLLECTION_NUMBER_LIMIT, CollectionId, CreateItemData, CreateFungibleData, CreateNftData,7	CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission,8	TokenId,9};10use frame_support::{assert_noop, assert_ok};11use sp_std::convert::TryInto;1213fn default_nft_data() -> CreateNftData {14	CreateNftData {15		const_data: vec![1, 2, 3].try_into().unwrap(),16		variable_data: vec![3, 2, 1].try_into().unwrap(),17	}18}1920fn default_fungible_data() -> CreateFungibleData {21	CreateFungibleData { value: 5 }22}2324fn default_re_fungible_data() -> CreateReFungibleData {25	CreateReFungibleData {26		const_data: vec![1, 2, 3].try_into().unwrap(),27		variable_data: vec![3, 2, 1].try_into().unwrap(),28		pieces: 1023,29	}30}3132fn create_test_collection_for_owner(33	mode: &CollectionMode,34	owner: u64,35	id: CollectionId,36) -> CollectionId {37	let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();38	let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();39	let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();4041	let origin1 = Origin::signed(owner);42	assert_ok!(TemplateModule::create_collection(43		origin1,44		col_name1,45		col_desc1,46		token_prefix1,47		mode.clone()48	));4950	let saved_col_name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();51	let saved_description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();52	let saved_prefix: Vec<u8> = b"token_prefix1\0".to_vec();53	assert_eq!(54		<pallet_common::CollectionById<Test>>::get(id)55			.unwrap()56			.owner,57		owner58	);59	assert_eq!(60		<pallet_common::CollectionById<Test>>::get(id).unwrap().name,61		saved_col_name62	);63	assert_eq!(64		<pallet_common::CollectionById<Test>>::get(id).unwrap().mode,65		*mode66	);67	assert_eq!(68		<pallet_common::CollectionById<Test>>::get(id)69			.unwrap()70			.description,71		saved_description72	);73	assert_eq!(74		<pallet_common::CollectionById<Test>>::get(id)75			.unwrap()76			.token_prefix,77		saved_prefix78	);79	id80}8182fn create_test_collection(mode: &CollectionMode, id: CollectionId) -> CollectionId {83	create_test_collection_for_owner(&mode, 1, id)84}8586fn create_test_item(collection_id: CollectionId, data: &CreateItemData) {87	let origin1 = Origin::signed(1);88	assert_ok!(TemplateModule::create_item(89		origin1,90		collection_id,91		account(1),92		data.clone()93	));94}9596fn account(sub: u64) -> TestCrossAccountId {97	TestCrossAccountId::from_sub(sub)98}99100// Use cases tests region101// #region102103#[test]104fn set_version_schema() {105	new_test_ext().execute_with(|| {106		let origin1 = Origin::signed(1);107		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));108109		assert_ok!(TemplateModule::set_schema_version(110			origin1,111			collection_id,112			SchemaVersion::Unique113		));114		assert_eq!(115			<pallet_common::CollectionById<Test>>::get(collection_id)116				.unwrap()117				.schema_version,118			SchemaVersion::Unique119		);120	});121}122123#[test]124fn create_fungible_collection_fails_with_large_decimal_numbers() {125	new_test_ext().execute_with(|| {126		let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();127		let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();128		let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();129130		let origin1 = Origin::signed(1);131		assert_noop!(132			TemplateModule::create_collection(133				origin1,134				col_name1,135				col_desc1,136				token_prefix1,137				CollectionMode::Fungible(MAX_DECIMAL_POINTS + 1)138			),139			Error::<Test>::CollectionDecimalPointLimitExceeded140		);141	});142}143144#[test]145fn create_nft_item() {146	new_test_ext().execute_with(|| {147		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));148149		let data = default_nft_data();150		create_test_item(collection_id, &data.clone().into());151152		let item = <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1)).unwrap();153		assert_eq!(item.const_data, data.const_data.into_inner());154		assert_eq!(item.variable_data, data.variable_data.into_inner());155	});156}157158// Use cases tests region159// #region160#[test]161fn create_nft_multiple_items() {162	new_test_ext().execute_with(|| {163		create_test_collection(&CollectionMode::NFT, CollectionId(1));164165		let origin1 = Origin::signed(1);166167		let items_data = vec![default_nft_data(), default_nft_data(), default_nft_data()];168169		assert_ok!(TemplateModule::create_multiple_items(170			origin1,171			CollectionId(1),172			account(1),173			items_data174				.clone()175				.into_iter()176				.map(|d| { d.into() })177				.collect()178		));179		for (index, data) in items_data.into_iter().enumerate() {180			let item = <pallet_nonfungible::TokenData<Test>>::get((181				CollectionId(1),182				TokenId((index + 1) as u32),183			))184			.unwrap();185			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());186			assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());187		}188	});189}190191#[test]192fn create_refungible_item() {193	new_test_ext().execute_with(|| {194		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));195196		let data = default_re_fungible_data();197		create_test_item(collection_id, &data.clone().into());198		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));199		let balance =200			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1)));201		assert_eq!(item.const_data, data.const_data.into_inner());202		assert_eq!(item.variable_data, data.variable_data.into_inner());203		assert_eq!(balance, 1023);204	});205}206207#[test]208fn create_multiple_refungible_items() {209	new_test_ext().execute_with(|| {210		create_test_collection(&CollectionMode::ReFungible, CollectionId(1));211212		let origin1 = Origin::signed(1);213214		let items_data = vec![215			default_re_fungible_data(),216			default_re_fungible_data(),217			default_re_fungible_data(),218		];219220		assert_ok!(TemplateModule::create_multiple_items(221			origin1,222			CollectionId(1),223			account(1),224			items_data225				.clone()226				.into_iter()227				.map(|d| { d.into() })228				.collect()229		));230		for (index, data) in items_data.into_iter().enumerate() {231			let item = <pallet_refungible::TokenData<Test>>::get((232				CollectionId(1),233				TokenId((index + 1) as u32),234			));235			let balance =236				<pallet_refungible::Balance<Test>>::get((CollectionId(1), TokenId(1), account(1)));237			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());238			assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());239			assert_eq!(balance, 1023);240		}241	});242}243244#[test]245fn create_fungible_item() {246	new_test_ext().execute_with(|| {247		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));248249		let data = default_fungible_data();250		create_test_item(collection_id, &data.into());251252		assert_eq!(253			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),254			5255		);256	});257}258259//#[test]260// fn create_multiple_fungible_items() {261//     new_test_ext().execute_with(|| {262//         default_limits();263264//         create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));265266//         let origin1 = Origin::signed(1);267268//         let items_data = vec![default_fungible_data(), default_fungible_data(), default_fungible_data()];269270//         assert_ok!(TemplateModule::create_multiple_items(271//             origin1.clone(),272//             1,273//             1,274//             items_data.clone().into_iter().map(|d| { d.into() }).collect()275//         ));276277//         for (index, _) in items_data.iter().enumerate() {278//             assert_eq!(TemplateModule::fungible_item_id(1, (index + 1) as TokenId).value, 5);279//         }280//         assert_eq!(TemplateModule::balance_count(1, 1), 3000);281//         assert_eq!(TemplateModule::address_tokens(1, 1), [1, 2, 3]);282//     });283// }284285#[test]286fn transfer_fungible_item() {287	new_test_ext().execute_with(|| {288		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));289290		let origin1 = Origin::signed(1);291		let origin2 = Origin::signed(2);292293		let data = default_fungible_data();294		create_test_item(collection_id, &data.into());295296		assert_eq!(297			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))),298			5299		);300301		// change owner scenario302		assert_ok!(TemplateModule::transfer(303			origin1,304			account(2),305			CollectionId(1),306			TokenId(0),307			5308		));309		assert_eq!(310			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))),311			0312		);313314		// split item scenario315		assert_ok!(TemplateModule::transfer(316			origin2.clone(),317			account(3),318			CollectionId(1),319			TokenId(0),320			3321		));322323		// split item and new owner has account scenario324		assert_ok!(TemplateModule::transfer(325			origin2,326			account(3),327			CollectionId(1),328			TokenId(0),329			1330		));331		assert_eq!(332			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(2))),333			1334		);335		assert_eq!(336			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(3))),337			4338		);339	});340}341342#[test]343fn transfer_refungible_item() {344	new_test_ext().execute_with(|| {345		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));346347		// Create RFT 1 in 1023 pieces for account 1348		let data = default_re_fungible_data();349		create_test_item(collection_id, &data.clone().into());350		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));351		assert_eq!(item.const_data, data.const_data.into_inner());352		assert_eq!(item.variable_data, data.variable_data.into_inner());353		assert_eq!(354			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),355			1356		);357		assert_eq!(358			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),359			1023360		);361		assert_eq!(362			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),363			true364		);365366		// Account 1 transfers all 1023 pieces of RFT 1 to account 2367		let origin1 = Origin::signed(1);368		let origin2 = Origin::signed(2);369		assert_ok!(TemplateModule::transfer(370			origin1,371			account(2),372			CollectionId(1),373			TokenId(1),374			1023375		));376		assert_eq!(377			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),378			1023379		);380		assert_eq!(381			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),382			0383		);384		assert_eq!(385			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),386			1387		);388		assert_eq!(389			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),390			false391		);392		assert_eq!(393			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),394			true395		);396397		// Account 2 transfers 500 pieces of RFT 1 to account 3398		assert_ok!(TemplateModule::transfer(399			origin2.clone(),400			account(3),401			CollectionId(1),402			TokenId(1),403			500404		));405		assert_eq!(406			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),407			523408		);409		assert_eq!(410			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),411			500412		);413		assert_eq!(414			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),415			1416		);417		assert_eq!(418			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),419			1420		);421		assert_eq!(422			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),423			true424		);425		assert_eq!(426			<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))),427			true428		);429430		// Account 2 transfers 200 more pieces of RFT 1 to account 3 with pre-existing balance431		assert_ok!(TemplateModule::transfer(432			origin2,433			account(3),434			CollectionId(1),435			TokenId(1),436			200437		));438		assert_eq!(439			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),440			323441		);442		assert_eq!(443			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),444			700445		);446		assert_eq!(447			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),448			1449		);450		assert_eq!(451			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),452			1453		);454		assert_eq!(455			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),456			true457		);458		assert_eq!(459			<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))),460			true461		);462	});463}464465#[test]466fn transfer_nft_item() {467	new_test_ext().execute_with(|| {468		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));469470		let data = default_nft_data();471		create_test_item(collection_id, &data.into());472		assert_eq!(473			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),474			1475		);476		assert_eq!(477			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),478			true479		);480481		let origin1 = Origin::signed(1);482		// default scenario483		assert_ok!(TemplateModule::transfer(484			origin1,485			account(2),486			CollectionId(1),487			TokenId(1),488			1489		));490		assert_eq!(491			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),492			0493		);494		assert_eq!(495			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),496			1497		);498		assert_eq!(499			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),500			false501		);502		assert_eq!(503			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),504			true505		);506	});507}508509#[test]510fn transfer_nft_item_wrong_value() {511	new_test_ext().execute_with(|| {512		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));513514		let data = default_nft_data();515		create_test_item(collection_id, &data.into());516		assert_eq!(517			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),518			1519		);520		assert_eq!(521			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),522			true523		);524525		let origin1 = Origin::signed(1);526527		assert_noop!(528			TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 2)529				.map_err(|e| e.error),530			<pallet_nonfungible::Error::<Test>>::NonfungibleItemsHaveNoAmount531		);532	});533}534535#[test]536fn transfer_nft_item_zero_value() {537	new_test_ext().execute_with(|| {538		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));539540		let data = default_nft_data();541		create_test_item(collection_id, &data.into());542		assert_eq!(543			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),544			1545		);546		assert_eq!(547			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),548			true549		);550551		let origin1 = Origin::signed(1);552553		// Transferring 0 amount works on NFT...554		assert_ok!(TemplateModule::transfer(555			origin1,556			account(2),557			CollectionId(1),558			TokenId(1),559			0560		));561		// ... and results in no transfer562		assert_eq!(563			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),564			1565		);566		assert_eq!(567			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),568			true569		);570	});571}572573#[test]574fn nft_approve_and_transfer_from() {575	new_test_ext().execute_with(|| {576		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));577578		let data = default_nft_data();579		create_test_item(collection_id, &data.into());580581		let origin1 = Origin::signed(1);582		let origin2 = Origin::signed(2);583584		assert_eq!(585			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),586			1587		);588		assert_eq!(589			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),590			true591		);592593		// neg transfer_from594		assert_noop!(595			TemplateModule::transfer_from(596				origin2.clone(),597				account(1),598				account(2),599				CollectionId(1),600				TokenId(1),601				1602			)603			.map_err(|e| e.error),604			CommonError::<Test>::TokenValueNotEnough605		);606607		// do approve608		assert_ok!(TemplateModule::approve(609			origin1,610			account(2),611			CollectionId(1),612			TokenId(1),613			1614		));615		assert_eq!(616			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),617			account(2)618		);619620		assert_ok!(TemplateModule::transfer_from(621			origin2,622			account(1),623			account(3),624			CollectionId(1),625			TokenId(1),626			1627		));628		assert!(629			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).is_none()630		);631	});632}633634#[test]635fn nft_approve_and_transfer_from_allow_list() {636	new_test_ext().execute_with(|| {637		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));638639		let origin1 = Origin::signed(1);640		let origin2 = Origin::signed(2);641642		// Create NFT 1 for account 1643		let data = default_nft_data();644		create_test_item(collection_id, &data.clone().into());645		assert_eq!(646			&<pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))647				.unwrap()648				.const_data,649			&data.const_data.into_inner()650		);651		assert_eq!(652			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),653			1654		);655		assert_eq!(656			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),657			true658		);659660		// Allow allow-list users to mint and add accounts 1, 2, and 3 to allow-list661		assert_ok!(TemplateModule::set_mint_permission(662			origin1.clone(),663			CollectionId(1),664			true665		));666		assert_ok!(TemplateModule::set_public_access_mode(667			origin1.clone(),668			CollectionId(1),669			AccessMode::AllowList670		));671		assert_ok!(TemplateModule::add_to_allow_list(672			origin1.clone(),673			CollectionId(1),674			account(1)675		));676		assert_ok!(TemplateModule::add_to_allow_list(677			origin1.clone(),678			CollectionId(1),679			account(2)680		));681		assert_ok!(TemplateModule::add_to_allow_list(682			origin1.clone(),683			CollectionId(1),684			account(3)685		));686687		// Account 1 approves account 2 for NFT 1688		assert_ok!(TemplateModule::approve(689			origin1.clone(),690			account(2),691			CollectionId(1),692			TokenId(1),693			1694		));695		assert_eq!(696			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),697			account(2)698		);699700		// Account 2 transfers NFT 1 from account 1 to account 3701		assert_ok!(TemplateModule::transfer_from(702			origin2,703			account(1),704			account(3),705			CollectionId(1),706			TokenId(1),707			1708		));709		assert!(710			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).is_none()711		);712	});713}714715#[test]716fn refungible_approve_and_transfer_from() {717	new_test_ext().execute_with(|| {718		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));719720		let origin1 = Origin::signed(1);721		let origin2 = Origin::signed(2);722723		// Create RFT 1 in 1023 pieces for account 1724		let data = default_re_fungible_data();725		create_test_item(collection_id, &data.into());726727		assert_eq!(728			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),729			1730		);731		assert_eq!(732			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),733			1023734		);735		assert_eq!(736			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),737			true738		);739740		// Allow public minting, enable allow-list and add accounts 1, 2, 3 to allow-list741		assert_ok!(TemplateModule::set_mint_permission(742			origin1.clone(),743			CollectionId(1),744			true745		));746		assert_ok!(TemplateModule::set_public_access_mode(747			origin1.clone(),748			CollectionId(1),749			AccessMode::AllowList750		));751		assert_ok!(TemplateModule::add_to_allow_list(752			origin1.clone(),753			CollectionId(1),754			account(1)755		));756		assert_ok!(TemplateModule::add_to_allow_list(757			origin1.clone(),758			CollectionId(1),759			account(2)760		));761		assert_ok!(TemplateModule::add_to_allow_list(762			origin1.clone(),763			CollectionId(1),764			account(3)765		));766767		// Account 1 approves account 2 for 1023 pieces of RFT 1768		assert_ok!(TemplateModule::approve(769			origin1,770			account(2),771			CollectionId(1),772			TokenId(1),773			1023774		));775		assert_eq!(776			<pallet_refungible::Allowance<Test>>::get((777				CollectionId(1),778				TokenId(1),779				account(1),780				account(2)781			)),782			1023783		);784785		// Account 2 transfers 100 pieces of RFT 1 from account 1 to account 3786		assert_ok!(TemplateModule::transfer_from(787			origin2,788			account(1),789			account(3),790			CollectionId(1),791			TokenId(1),792			100793		));794		assert_eq!(795			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),796			1797		);798		assert_eq!(799			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),800			1801		);802		assert_eq!(803			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),804			923805		);806		assert_eq!(807			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),808			100809		);810		assert_eq!(811			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),812			true813		);814		assert_eq!(815			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),816			true817		);818		assert_eq!(819			<pallet_refungible::Allowance<Test>>::get((820				CollectionId(1),821				TokenId(1),822				account(1),823				account(2)824			)),825			923826		);827	});828}829830#[test]831fn fungible_approve_and_transfer_from() {832	new_test_ext().execute_with(|| {833		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));834835		let data = default_fungible_data();836		create_test_item(collection_id, &data.into());837838		let origin1 = Origin::signed(1);839		let origin2 = Origin::signed(2);840841		assert_ok!(TemplateModule::set_mint_permission(842			origin1.clone(),843			CollectionId(1),844			true845		));846		assert_ok!(TemplateModule::set_public_access_mode(847			origin1.clone(),848			CollectionId(1),849			AccessMode::AllowList850		));851		assert_ok!(TemplateModule::add_to_allow_list(852			origin1.clone(),853			CollectionId(1),854			account(1)855		));856		assert_ok!(TemplateModule::add_to_allow_list(857			origin1.clone(),858			CollectionId(1),859			account(2)860		));861		assert_ok!(TemplateModule::add_to_allow_list(862			origin1.clone(),863			CollectionId(1),864			account(3)865		));866867		// do approve868		assert_ok!(TemplateModule::approve(869			origin1.clone(),870			account(2),871			CollectionId(1),872			TokenId(0),873			5874		));875		assert_eq!(876			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),877			5878		);879		assert_ok!(TemplateModule::approve(880			origin1,881			account(3),882			CollectionId(1),883			TokenId(0),884			5885		));886		assert_eq!(887			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),888			5889		);890		assert_eq!(891			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(3))),892			5893		);894895		assert_ok!(TemplateModule::transfer_from(896			origin2.clone(),897			account(1),898			account(3),899			CollectionId(1),900			TokenId(0),901			4902		));903904		assert_eq!(905			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),906			1907		);908909		assert_noop!(910			TemplateModule::transfer_from(911				origin2,912				account(1),913				account(3),914				CollectionId(1),915				TokenId(0),916				4917			)918			.map_err(|e| e.error),919			CommonError::<Test>::TokenValueNotEnough920		);921	});922}923924#[test]925fn change_collection_owner() {926	new_test_ext().execute_with(|| {927		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));928929		let origin1 = Origin::signed(1);930		assert_ok!(TemplateModule::change_collection_owner(931			origin1,932			collection_id,933			2934		));935		assert_eq!(936			<pallet_common::CollectionById<Test>>::get(collection_id)937				.unwrap()938				.owner,939			2940		);941	});942}943944#[test]945fn destroy_collection() {946	new_test_ext().execute_with(|| {947		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));948949		let origin1 = Origin::signed(1);950		assert_ok!(TemplateModule::destroy_collection(origin1, collection_id));951	});952}953954#[test]955fn burn_nft_item() {956	new_test_ext().execute_with(|| {957		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));958959		let origin1 = Origin::signed(1);960961		let data = default_nft_data();962		create_test_item(collection_id, &data.into());963964		// check balance (collection with id = 1, user id = 1)965		assert_eq!(966			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),967			1968		);969970		// burn item971		assert_ok!(TemplateModule::burn_item(972			origin1.clone(),973			collection_id,974			TokenId(1),975			1976		));977		assert_eq!(978			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),979			0980		);981	});982}983984#[test]985fn burn_same_nft_item_twice() {986	new_test_ext().execute_with(|| {987		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));988989		let origin1 = Origin::signed(1);990991		let data = default_nft_data();992		create_test_item(collection_id, &data.into());993994		// check balance (collection with id = 1, user id = 1)995		assert_eq!(996			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),997			1998		);9991000		// burn item1001		assert_ok!(TemplateModule::burn_item(1002			origin1.clone(),1003			collection_id,1004			TokenId(1),1005			11006		));10071008		// burn item again1009		assert_noop!(1010			TemplateModule::burn_item(origin1, collection_id, TokenId(1), 1).map_err(|e| e.error),1011			CommonError::<Test>::TokenNotFound1012		);10131014		assert_eq!(1015			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),1016			01017		);1018	});1019}10201021#[test]1022fn burn_fungible_item() {1023	new_test_ext().execute_with(|| {1024		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));10251026		let origin1 = Origin::signed(1);1027		assert_ok!(TemplateModule::add_collection_admin(1028			origin1.clone(),1029			collection_id,1030			account(2)1031		));10321033		let data = default_fungible_data();1034		create_test_item(collection_id, &data.into());10351036		// check balance (collection with id = 1, user id = 1)1037		assert_eq!(1038			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),1039			51040		);10411042		// burn item1043		assert_ok!(TemplateModule::burn_item(1044			origin1.clone(),1045			CollectionId(1),1046			TokenId(0),1047			51048		));1049		assert_noop!(1050			TemplateModule::burn_item(origin1, CollectionId(1), TokenId(0), 5).map_err(|e| e.error),1051			CommonError::<Test>::TokenValueTooLow1052		);10531054		assert_eq!(1055			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),1056			01057		);1058	});1059}10601061#[test]1062fn burn_fungible_item_with_token_id() {1063	new_test_ext().execute_with(|| {1064		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));10651066		let origin1 = Origin::signed(1);1067		assert_ok!(TemplateModule::add_collection_admin(1068			origin1.clone(),1069			collection_id,1070			account(2)1071		));10721073		let data = default_fungible_data();1074		create_test_item(collection_id, &data.into());10751076		// check balance (collection with id = 1, user id = 1)1077		assert_eq!(1078			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),1079			51080		);10811082		// Try to burn item using Token ID1083		assert_noop!(1084			TemplateModule::burn_item(origin1, CollectionId(1), TokenId(1), 5).map_err(|e| e.error),1085			<pallet_fungible::Error::<Test>>::FungibleItemsHaveNoId1086		);1087	});1088}1089#[test]1090fn burn_refungible_item() {1091	new_test_ext().execute_with(|| {1092		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));1093		let origin1 = Origin::signed(1);10941095		assert_ok!(TemplateModule::set_mint_permission(1096			origin1.clone(),1097			collection_id,1098			true1099		));1100		assert_ok!(TemplateModule::set_public_access_mode(1101			origin1.clone(),1102			collection_id,1103			AccessMode::AllowList1104		));1105		assert_ok!(TemplateModule::add_to_allow_list(1106			origin1.clone(),1107			collection_id,1108			account(1)1109		));11101111		assert_ok!(TemplateModule::add_collection_admin(1112			origin1.clone(),1113			collection_id,1114			account(2)1115		));11161117		let data = default_re_fungible_data();1118		create_test_item(collection_id, &data.into());11191120		// check balance (collection with id = 1, user id = 2)1121		assert_eq!(1122			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),1123			11124		);1125		assert_eq!(1126			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),1127			10231128		);11291130		// burn item1131		assert_ok!(TemplateModule::burn_item(1132			origin1.clone(),1133			collection_id,1134			TokenId(1),1135			10231136		));1137		assert_noop!(1138			TemplateModule::burn_item(origin1, collection_id, TokenId(1), 1023)1139				.map_err(|e| e.error),1140			CommonError::<Test>::TokenValueTooLow1141		);11421143		assert_eq!(1144			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),1145			01146		);1147	});1148}11491150#[test]1151fn add_collection_admin() {1152	new_test_ext().execute_with(|| {1153		let collection1_id =1154			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));1155		let origin1 = Origin::signed(1);11561157		// Add collection admins1158		assert_ok!(TemplateModule::add_collection_admin(1159			origin1.clone(),1160			collection1_id,1161			account(2)1162		));1163		assert_ok!(TemplateModule::add_collection_admin(1164			origin1,1165			collection1_id,1166			account(3)1167		));11681169		// Owner is not an admin by default1170		assert_eq!(1171			<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(1))),1172			false1173		);1174		assert!(<pallet_common::IsAdmin<Test>>::get((1175			CollectionId(1),1176			account(2)1177		)));1178		assert!(<pallet_common::IsAdmin<Test>>::get((1179			CollectionId(1),1180			account(3)1181		)));1182	});1183}11841185#[test]1186fn remove_collection_admin() {1187	new_test_ext().execute_with(|| {1188		let collection1_id =1189			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));1190		let origin1 = Origin::signed(1);1191		let origin2 = Origin::signed(2);11921193		// Add collection admins 2 and 31194		assert_ok!(TemplateModule::add_collection_admin(1195			origin1.clone(),1196			collection1_id,1197			account(2)1198		));1199		assert_ok!(TemplateModule::add_collection_admin(1200			origin1,1201			collection1_id,1202			account(3)1203		));12041205		assert!(<pallet_common::IsAdmin<Test>>::get((1206			CollectionId(1),1207			account(2)1208		)));1209		assert!(<pallet_common::IsAdmin<Test>>::get((1210			CollectionId(1),1211			account(3)1212		)));12131214		// remove admin 31215		assert_ok!(TemplateModule::remove_collection_admin(1216			origin2,1217			CollectionId(1),1218			account(3)1219		));12201221		// 2 is still admin, 3 is not an admin anymore1222		assert!(<pallet_common::IsAdmin<Test>>::get((1223			CollectionId(1),1224			account(2)1225		)));1226		assert_eq!(1227			<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(3))),1228			false1229		);1230	});1231}12321233#[test]1234fn balance_of() {1235	new_test_ext().execute_with(|| {1236		let nft_collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1237		let fungible_collection_id =1238			create_test_collection(&CollectionMode::Fungible(3), CollectionId(2));1239		let re_fungible_collection_id =1240			create_test_collection(&CollectionMode::ReFungible, CollectionId(3));12411242		// check balance before1243		assert_eq!(1244			<pallet_nonfungible::AccountBalance<Test>>::get((nft_collection_id, account(1))),1245			01246		);1247		assert_eq!(1248			<pallet_fungible::Balance<Test>>::get((fungible_collection_id, account(1))),1249			01250		);1251		assert_eq!(1252			<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))),1253			01254		);12551256		let nft_data = default_nft_data();1257		create_test_item(nft_collection_id, &nft_data.into());12581259		let fungible_data = default_fungible_data();1260		create_test_item(fungible_collection_id, &fungible_data.into());12611262		let re_fungible_data = default_re_fungible_data();1263		create_test_item(re_fungible_collection_id, &re_fungible_data.into());12641265		// check balance (collection with id = 1, user id = 1)1266		assert_eq!(1267			<pallet_nonfungible::AccountBalance<Test>>::get((nft_collection_id, account(1))),1268			11269		);1270		assert_eq!(1271			<pallet_fungible::Balance<Test>>::get((fungible_collection_id, account(1))),1272			51273		);1274		assert_eq!(1275			<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))),1276			11277		);12781279		assert_eq!(1280			<pallet_nonfungible::Owned<Test>>::get((nft_collection_id, account(1), TokenId(1))),1281			true1282		);1283		assert_eq!(1284			<pallet_refungible::Owned<Test>>::get((1285				re_fungible_collection_id,1286				account(1),1287				TokenId(1)1288			)),1289			true1290		);1291	});1292}12931294#[test]1295fn approve() {1296	new_test_ext().execute_with(|| {1297		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));12981299		let data = default_nft_data();1300		create_test_item(collection_id, &data.into());13011302		let origin1 = Origin::signed(1);13031304		// approve1305		assert_ok!(TemplateModule::approve(1306			origin1,1307			account(2),1308			CollectionId(1),1309			TokenId(1),1310			11311		));1312		assert_eq!(1313			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1314			account(2)1315		);1316	});1317}13181319#[test]1320fn transfer_from() {1321	new_test_ext().execute_with(|| {1322		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1323		let origin1 = Origin::signed(1);1324		let origin2 = Origin::signed(2);13251326		let data = default_nft_data();1327		create_test_item(collection_id, &data.into());13281329		// approve1330		assert_ok!(TemplateModule::approve(1331			origin1.clone(),1332			account(2),1333			CollectionId(1),1334			TokenId(1),1335			11336		));1337		assert_eq!(1338			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1339			account(2)1340		);13411342		assert_ok!(TemplateModule::set_mint_permission(1343			origin1.clone(),1344			CollectionId(1),1345			true1346		));1347		assert_ok!(TemplateModule::set_public_access_mode(1348			origin1.clone(),1349			CollectionId(1),1350			AccessMode::AllowList1351		));1352		assert_ok!(TemplateModule::add_to_allow_list(1353			origin1.clone(),1354			CollectionId(1),1355			account(1)1356		));1357		assert_ok!(TemplateModule::add_to_allow_list(1358			origin1.clone(),1359			CollectionId(1),1360			account(2)1361		));1362		assert_ok!(TemplateModule::add_to_allow_list(1363			origin1,1364			CollectionId(1),1365			account(3)1366		));13671368		assert_ok!(TemplateModule::transfer_from(1369			origin2,1370			account(1),1371			account(2),1372			CollectionId(1),1373			TokenId(1),1374			11375		));13761377		// after transfer1378		assert_eq!(1379			<pallet_nonfungible::AccountBalance<Test>>::get((CollectionId(1), account(1))),1380			01381		);1382		assert_eq!(1383			<pallet_nonfungible::AccountBalance<Test>>::get((CollectionId(1), account(2))),1384			11385		);1386	});1387}13881389// #endregion13901391// Coverage tests region1392// #region13931394#[test]1395fn owner_can_add_address_to_allow_list() {1396	new_test_ext().execute_with(|| {1397		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));13981399		let origin1 = Origin::signed(1);1400		assert_ok!(TemplateModule::add_to_allow_list(1401			origin1,1402			collection_id,1403			account(2)1404		));1405		assert!(<pallet_common::Allowlist<Test>>::get((1406			collection_id,1407			account(2)1408		)));1409	});1410}14111412#[test]1413fn admin_can_add_address_to_allow_list() {1414	new_test_ext().execute_with(|| {1415		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1416		let origin1 = Origin::signed(1);1417		let origin2 = Origin::signed(2);14181419		assert_ok!(TemplateModule::add_collection_admin(1420			origin1,1421			collection_id,1422			account(2)1423		));1424		assert_ok!(TemplateModule::add_to_allow_list(1425			origin2,1426			collection_id,1427			account(3)1428		));1429		assert!(<pallet_common::Allowlist<Test>>::get((1430			collection_id,1431			account(3)1432		)));1433	});1434}14351436#[test]1437fn nonprivileged_user_cannot_add_address_to_allow_list() {1438	new_test_ext().execute_with(|| {1439		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));14401441		let origin2 = Origin::signed(2);1442		assert_noop!(1443			TemplateModule::add_to_allow_list(origin2, collection_id, account(3)),1444			CommonError::<Test>::NoPermission1445		);1446	});1447}14481449#[test]1450fn nobody_can_add_address_to_allow_list_of_nonexisting_collection() {1451	new_test_ext().execute_with(|| {1452		let origin1 = Origin::signed(1);14531454		assert_noop!(1455			TemplateModule::add_to_allow_list(origin1, CollectionId(1), account(2)),1456			CommonError::<Test>::CollectionNotFound1457		);1458	});1459}14601461#[test]1462fn nobody_can_add_address_to_allow_list_of_deleted_collection() {1463	new_test_ext().execute_with(|| {1464		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));14651466		let origin1 = Origin::signed(1);1467		assert_ok!(TemplateModule::destroy_collection(1468			origin1.clone(),1469			collection_id1470		));1471		assert_noop!(1472			TemplateModule::add_to_allow_list(origin1, collection_id, account(2)),1473			CommonError::<Test>::CollectionNotFound1474		);1475	});1476}14771478// If address is already added to allow list, nothing happens1479#[test]1480fn address_is_already_added_to_allow_list() {1481	new_test_ext().execute_with(|| {1482		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1483		let origin1 = Origin::signed(1);14841485		assert_ok!(TemplateModule::add_to_allow_list(1486			origin1.clone(),1487			collection_id,1488			account(2)1489		));1490		assert_ok!(TemplateModule::add_to_allow_list(1491			origin1,1492			collection_id,1493			account(2)1494		));1495		assert!(<pallet_common::Allowlist<Test>>::get((1496			collection_id,1497			account(2)1498		)));1499	});1500}15011502#[test]1503fn owner_can_remove_address_from_allow_list() {1504	new_test_ext().execute_with(|| {1505		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));15061507		let origin1 = Origin::signed(1);1508		assert_ok!(TemplateModule::add_to_allow_list(1509			origin1.clone(),1510			collection_id,1511			account(2)1512		));1513		assert_ok!(TemplateModule::remove_from_allow_list(1514			origin1,1515			collection_id,1516			account(2)1517		));1518		assert_eq!(1519			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1520			false1521		);1522	});1523}15241525#[test]1526fn admin_can_remove_address_from_allow_list() {1527	new_test_ext().execute_with(|| {1528		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1529		let origin1 = Origin::signed(1);1530		let origin2 = Origin::signed(2);15311532		// Owner adds admin1533		assert_ok!(TemplateModule::add_collection_admin(1534			origin1.clone(),1535			collection_id,1536			account(2)1537		));15381539		// Owner adds address 3 to allow list1540		assert_ok!(TemplateModule::add_to_allow_list(1541			origin1,1542			collection_id,1543			account(3)1544		));15451546		// Admin removes address 3 from allow list1547		assert_ok!(TemplateModule::remove_from_allow_list(1548			origin2,1549			collection_id,1550			account(3)1551		));1552		assert_eq!(1553			<pallet_common::Allowlist<Test>>::get((collection_id, account(3))),1554			false1555		);1556	});1557}15581559#[test]1560fn nonprivileged_user_cannot_remove_address_from_allow_list() {1561	new_test_ext().execute_with(|| {1562		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1563		let origin1 = Origin::signed(1);1564		let origin2 = Origin::signed(2);15651566		assert_ok!(TemplateModule::add_to_allow_list(1567			origin1,1568			collection_id,1569			account(2)1570		));1571		assert_noop!(1572			TemplateModule::remove_from_allow_list(origin2, collection_id, account(2)),1573			CommonError::<Test>::NoPermission1574		);1575		assert!(<pallet_common::Allowlist<Test>>::get((1576			collection_id,1577			account(2)1578		)));1579	});1580}15811582#[test]1583fn nobody_can_remove_address_from_allow_list_of_nonexisting_collection() {1584	new_test_ext().execute_with(|| {1585		let origin1 = Origin::signed(1);15861587		assert_noop!(1588			TemplateModule::remove_from_allow_list(origin1, CollectionId(1), account(2)),1589			CommonError::<Test>::CollectionNotFound1590		);1591	});1592}15931594#[test]1595fn nobody_can_remove_address_from_allow_list_of_deleted_collection() {1596	new_test_ext().execute_with(|| {1597		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1598		let origin1 = Origin::signed(1);1599		let origin2 = Origin::signed(2);16001601		// Add account 2 to allow list1602		assert_ok!(TemplateModule::add_to_allow_list(1603			origin1.clone(),1604			collection_id,1605			account(2)1606		));16071608		// Account 2 is in collection allow-list1609		assert!(<pallet_common::Allowlist<Test>>::get((1610			collection_id,1611			account(2)1612		)));16131614		// Destroy collection1615		assert_ok!(TemplateModule::destroy_collection(origin1, collection_id));16161617		// Attempt to remove account 2 from collection allow-list => error1618		assert_noop!(1619			TemplateModule::remove_from_allow_list(origin2, collection_id, account(2)),1620			CommonError::<Test>::CollectionNotFound1621		);16221623		// Account 2 is not found in collection allow-list anyway1624		assert_eq!(1625			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1626			false1627		);1628	});1629}16301631// If address is already removed from allow list, nothing happens1632#[test]1633fn address_is_already_removed_from_allow_list() {1634	new_test_ext().execute_with(|| {1635		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1636		let origin1 = Origin::signed(1);16371638		assert_ok!(TemplateModule::add_to_allow_list(1639			origin1.clone(),1640			collection_id,1641			account(2)1642		));1643		assert_ok!(TemplateModule::remove_from_allow_list(1644			origin1.clone(),1645			collection_id,1646			account(2)1647		));1648		assert_eq!(1649			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1650			false1651		);1652		assert_ok!(TemplateModule::remove_from_allow_list(1653			origin1,1654			collection_id,1655			account(2)1656		));1657		assert_eq!(1658			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1659			false1660		);1661	});1662}16631664// If Public Access mode is set to AllowList, tokens can’t be transferred from a non-allowlisted address with transfer or transferFrom (2 tests)1665#[test]1666fn allow_list_test_1() {1667	new_test_ext().execute_with(|| {1668		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));16691670		let origin1 = Origin::signed(1);16711672		let data = default_nft_data();1673		create_test_item(collection_id, &data.into());16741675		assert_ok!(TemplateModule::set_public_access_mode(1676			origin1.clone(),1677			collection_id,1678			AccessMode::AllowList1679		));1680		assert_ok!(TemplateModule::add_to_allow_list(1681			origin1.clone(),1682			collection_id,1683			account(2)1684		));16851686		assert_noop!(1687			TemplateModule::transfer(origin1, account(3), CollectionId(1), TokenId(1), 1)1688				.map_err(|e| e.error),1689			CommonError::<Test>::AddressNotInAllowlist1690		);1691	});1692}16931694#[test]1695fn allow_list_test_2() {1696	new_test_ext().execute_with(|| {1697		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1698		let origin1 = Origin::signed(1);16991700		let data = default_nft_data();1701		create_test_item(collection_id, &data.into());17021703		assert_ok!(TemplateModule::set_public_access_mode(1704			origin1.clone(),1705			collection_id,1706			AccessMode::AllowList1707		));1708		assert_ok!(TemplateModule::add_to_allow_list(1709			origin1.clone(),1710			collection_id,1711			account(1)1712		));1713		assert_ok!(TemplateModule::add_to_allow_list(1714			origin1.clone(),1715			collection_id,1716			account(2)1717		));17181719		// do approve1720		assert_ok!(TemplateModule::approve(1721			origin1.clone(),1722			account(1),1723			collection_id,1724			TokenId(1),1725			11726		));1727		assert_eq!(1728			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1729			account(1)1730		);17311732		assert_ok!(TemplateModule::remove_from_allow_list(1733			origin1.clone(),1734			collection_id,1735			account(1)1736		));17371738		assert_noop!(1739			TemplateModule::transfer_from(1740				origin1,1741				account(1),1742				account(3),1743				CollectionId(1),1744				TokenId(1),1745				11746			)1747			.map_err(|e| e.error),1748			CommonError::<Test>::AddressNotInAllowlist1749		);1750	});1751}17521753// If Public Access mode is set to AllowList, tokens can’t be transferred to a non-allowlisted address with transfer or transferFrom (2 tests)1754#[test]1755fn allow_list_test_3() {1756	new_test_ext().execute_with(|| {1757		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));17581759		let origin1 = Origin::signed(1);17601761		let data = default_nft_data();1762		create_test_item(collection_id, &data.into());17631764		assert_ok!(TemplateModule::set_public_access_mode(1765			origin1.clone(),1766			collection_id,1767			AccessMode::AllowList1768		));1769		assert_ok!(TemplateModule::add_to_allow_list(1770			origin1.clone(),1771			collection_id,1772			account(1)1773		));17741775		assert_noop!(1776			TemplateModule::transfer(origin1, account(3), collection_id, TokenId(1), 1)1777				.map_err(|e| e.error),1778			CommonError::<Test>::AddressNotInAllowlist1779		);1780	});1781}17821783#[test]1784fn allow_list_test_4() {1785	new_test_ext().execute_with(|| {1786		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));17871788		let origin1 = Origin::signed(1);17891790		let data = default_nft_data();1791		create_test_item(collection_id, &data.into());17921793		assert_ok!(TemplateModule::set_public_access_mode(1794			origin1.clone(),1795			collection_id,1796			AccessMode::AllowList1797		));1798		assert_ok!(TemplateModule::add_to_allow_list(1799			origin1.clone(),1800			collection_id,1801			account(1)1802		));1803		assert_ok!(TemplateModule::add_to_allow_list(1804			origin1.clone(),1805			collection_id,1806			account(2)1807		));18081809		// do approve1810		assert_ok!(TemplateModule::approve(1811			origin1.clone(),1812			account(1),1813			collection_id,1814			TokenId(1),1815			11816		));1817		assert_eq!(1818			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1819			account(1)1820		);18211822		assert_ok!(TemplateModule::remove_from_allow_list(1823			origin1.clone(),1824			collection_id,1825			account(2)1826		));18271828		assert_noop!(1829			TemplateModule::transfer_from(1830				origin1,1831				account(1),1832				account(3),1833				collection_id,1834				TokenId(1),1835				11836			)1837			.map_err(|e| e.error),1838			CommonError::<Test>::AddressNotInAllowlist1839		);1840	});1841}18421843// If Public Access mode is set to AllowList, tokens can’t be destroyed by a non-allowlisted address (even if it owned them before enabling AllowList mode)1844#[test]1845fn allow_list_test_5() {1846	new_test_ext().execute_with(|| {1847		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));18481849		let origin1 = Origin::signed(1);18501851		let data = default_nft_data();1852		create_test_item(collection_id, &data.into());18531854		assert_ok!(TemplateModule::set_public_access_mode(1855			origin1.clone(),1856			collection_id,1857			AccessMode::AllowList1858		));1859		assert_noop!(1860			TemplateModule::burn_item(origin1.clone(), CollectionId(1), TokenId(1), 1)1861				.map_err(|e| e.error),1862			CommonError::<Test>::AddressNotInAllowlist1863		);1864	});1865}18661867// If Public Access mode is set to AllowList, token transfers can’t be Approved by a non-allowlisted address (see Approve method).1868#[test]1869fn allow_list_test_6() {1870	new_test_ext().execute_with(|| {1871		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));18721873		let origin1 = Origin::signed(1);18741875		let data = default_nft_data();1876		create_test_item(collection_id, &data.into());18771878		assert_ok!(TemplateModule::set_public_access_mode(1879			origin1.clone(),1880			collection_id,1881			AccessMode::AllowList1882		));18831884		// do approve1885		assert_noop!(1886			TemplateModule::approve(origin1, account(1), CollectionId(1), TokenId(1), 1)1887				.map_err(|e| e.error),1888			CommonError::<Test>::AddressNotInAllowlist1889		);1890	});1891}18921893// If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transfer or transferFrom (2 tests) and1894//          tokens can be transferred from a allowlisted address with transfer or transferFrom (2 tests)1895#[test]1896fn allow_list_test_7() {1897	new_test_ext().execute_with(|| {1898		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));18991900		let data = default_nft_data();1901		create_test_item(collection_id, &data.into());19021903		let origin1 = Origin::signed(1);19041905		assert_ok!(TemplateModule::set_public_access_mode(1906			origin1.clone(),1907			collection_id,1908			AccessMode::AllowList1909		));1910		assert_ok!(TemplateModule::add_to_allow_list(1911			origin1.clone(),1912			collection_id,1913			account(1)1914		));1915		assert_ok!(TemplateModule::add_to_allow_list(1916			origin1.clone(),1917			collection_id,1918			account(2)1919		));19201921		assert_ok!(TemplateModule::transfer(1922			origin1,1923			account(2),1924			CollectionId(1),1925			TokenId(1),1926			11927		));1928	});1929}19301931#[test]1932fn allow_list_test_8() {1933	new_test_ext().execute_with(|| {1934		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));19351936		// Create NFT for account 11937		let data = default_nft_data();1938		create_test_item(collection_id, &data.into());19391940		let origin1 = Origin::signed(1);19411942		// Toggle Allow List mode and add accounts 1 and 21943		assert_ok!(TemplateModule::set_public_access_mode(1944			origin1.clone(),1945			collection_id,1946			AccessMode::AllowList1947		));1948		assert_ok!(TemplateModule::add_to_allow_list(1949			origin1.clone(),1950			collection_id,1951			account(1)1952		));1953		assert_ok!(TemplateModule::add_to_allow_list(1954			origin1.clone(),1955			collection_id,1956			account(2)1957		));19581959		// Sself-approve account 1 for NFT 11960		assert_ok!(TemplateModule::approve(1961			origin1.clone(),1962			account(1),1963			CollectionId(1),1964			TokenId(1),1965			11966		));1967		assert_eq!(1968			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1969			account(1)1970		);19711972		// Transfer from 1 to 21973		assert_ok!(TemplateModule::transfer_from(1974			origin1,1975			account(1),1976			account(2),1977			CollectionId(1),1978			TokenId(1),1979			11980		));1981	});1982}19831984// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by owner.1985#[test]1986fn allow_list_test_9() {1987	new_test_ext().execute_with(|| {1988		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1989		let origin1 = Origin::signed(1);19901991		assert_ok!(TemplateModule::set_public_access_mode(1992			origin1.clone(),1993			collection_id,1994			AccessMode::AllowList1995		));1996		assert_ok!(TemplateModule::set_mint_permission(1997			origin1,1998			collection_id,1999			false2000		));20012002		let data = default_nft_data();2003		create_test_item(collection_id, &data.into());2004	});2005}20062007// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by admin.2008#[test]2009fn allow_list_test_10() {2010	new_test_ext().execute_with(|| {2011		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));20122013		let origin1 = Origin::signed(1);2014		let origin2 = Origin::signed(2);20152016		assert_ok!(TemplateModule::set_public_access_mode(2017			origin1.clone(),2018			collection_id,2019			AccessMode::AllowList2020		));2021		assert_ok!(TemplateModule::set_mint_permission(2022			origin1.clone(),2023			collection_id,2024			false2025		));20262027		assert_ok!(TemplateModule::add_collection_admin(2028			origin1,2029			collection_id,2030			account(2)2031		));20322033		assert_ok!(TemplateModule::create_item(2034			origin2,2035			collection_id,2036			account(2),2037			default_nft_data().into()2038		));2039	});2040}20412042// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and allow listed address.2043#[test]2044fn allow_list_test_11() {2045	new_test_ext().execute_with(|| {2046		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));20472048		let origin1 = Origin::signed(1);2049		let origin2 = Origin::signed(2);20502051		assert_ok!(TemplateModule::set_public_access_mode(2052			origin1.clone(),2053			collection_id,2054			AccessMode::AllowList2055		));2056		assert_ok!(TemplateModule::set_mint_permission(2057			origin1.clone(),2058			collection_id,2059			false2060		));2061		assert_ok!(TemplateModule::add_to_allow_list(2062			origin1,2063			collection_id,2064			account(2)2065		));20662067		assert_noop!(2068			TemplateModule::create_item(2069				origin2,2070				CollectionId(1),2071				account(2),2072				default_nft_data().into()2073			)2074			.map_err(|e| e.error),2075			CommonError::<Test>::PublicMintingNotAllowed2076		);2077	});2078}20792080// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and non-allow listed address.2081#[test]2082fn allow_list_test_12() {2083	new_test_ext().execute_with(|| {2084		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));20852086		let origin1 = Origin::signed(1);2087		let origin2 = Origin::signed(2);20882089		assert_ok!(TemplateModule::set_public_access_mode(2090			origin1.clone(),2091			collection_id,2092			AccessMode::AllowList2093		));2094		assert_ok!(TemplateModule::set_mint_permission(2095			origin1,2096			collection_id,2097			false2098		));20992100		assert_noop!(2101			TemplateModule::create_item(2102				origin2,2103				CollectionId(1),2104				account(2),2105				default_nft_data().into()2106			)2107			.map_err(|e| e.error),2108			CommonError::<Test>::PublicMintingNotAllowed2109		);2110	});2111}21122113// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by owner.2114#[test]2115fn allow_list_test_13() {2116	new_test_ext().execute_with(|| {2117		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));21182119		let origin1 = Origin::signed(1);21202121		assert_ok!(TemplateModule::set_public_access_mode(2122			origin1.clone(),2123			collection_id,2124			AccessMode::AllowList2125		));2126		assert_ok!(TemplateModule::set_mint_permission(2127			origin1,2128			collection_id,2129			true2130		));21312132		let data = default_nft_data();2133		create_test_item(collection_id, &data.into());2134	});2135}21362137// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by admin.2138#[test]2139fn allow_list_test_14() {2140	new_test_ext().execute_with(|| {2141		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));21422143		let origin1 = Origin::signed(1);2144		let origin2 = Origin::signed(2);21452146		assert_ok!(TemplateModule::set_public_access_mode(2147			origin1.clone(),2148			collection_id,2149			AccessMode::AllowList2150		));2151		assert_ok!(TemplateModule::set_mint_permission(2152			origin1.clone(),2153			collection_id,2154			true2155		));21562157		assert_ok!(TemplateModule::add_collection_admin(2158			origin1,2159			collection_id,2160			account(2)2161		));21622163		assert_ok!(TemplateModule::create_item(2164			origin2,2165			collection_id,2166			account(2),2167			default_nft_data().into()2168		));2169	});2170}21712172// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens cannot be created by non-privileged and non-allow listed address.2173#[test]2174fn allow_list_test_15() {2175	new_test_ext().execute_with(|| {2176		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));21772178		let origin1 = Origin::signed(1);2179		let origin2 = Origin::signed(2);21802181		assert_ok!(TemplateModule::set_public_access_mode(2182			origin1.clone(),2183			collection_id,2184			AccessMode::AllowList2185		));2186		assert_ok!(TemplateModule::set_mint_permission(2187			origin1,2188			collection_id,2189			true2190		));21912192		assert_noop!(2193			TemplateModule::create_item(2194				origin2,2195				collection_id,2196				account(2),2197				default_nft_data().into()2198			)2199			.map_err(|e| e.error),2200			CommonError::<Test>::AddressNotInAllowlist2201		);2202	});2203}22042205// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by non-privileged and allow listed address.2206#[test]2207fn allow_list_test_16() {2208	new_test_ext().execute_with(|| {2209		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));22102211		let origin1 = Origin::signed(1);2212		let origin2 = Origin::signed(2);22132214		assert_ok!(TemplateModule::set_public_access_mode(2215			origin1.clone(),2216			collection_id,2217			AccessMode::AllowList2218		));2219		assert_ok!(TemplateModule::set_mint_permission(2220			origin1.clone(),2221			collection_id,2222			true2223		));2224		assert_ok!(TemplateModule::add_to_allow_list(2225			origin1,2226			collection_id,2227			account(2)2228		));22292230		assert_ok!(TemplateModule::create_item(2231			origin2,2232			collection_id,2233			account(2),2234			default_nft_data().into()2235		));2236	});2237}22382239// Total number of collections. Positive test2240#[test]2241fn total_number_collections_bound() {2242	new_test_ext().execute_with(|| {2243		create_test_collection(&CollectionMode::NFT, CollectionId(1));2244	});2245}22462247#[test]2248fn create_max_collections() {2249	new_test_ext().execute_with(|| {2250		for i in 1..=COLLECTION_NUMBER_LIMIT {2251			create_test_collection(&CollectionMode::NFT, CollectionId(i));2252		}2253	});2254}22552256// Total number of collections. Negative test2257#[test]2258fn total_number_collections_bound_neg() {2259	new_test_ext().execute_with(|| {2260		let origin1 = Origin::signed(1);22612262		for i in 1..=COLLECTION_NUMBER_LIMIT {2263			create_test_collection(&CollectionMode::NFT, CollectionId(i));2264		}22652266		let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();2267		let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();2268		let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();22692270		// 11-th collection in chain. Expects error2271		assert_noop!(2272			TemplateModule::create_collection(2273				origin1,2274				col_name1,2275				col_desc1,2276				token_prefix1,2277				CollectionMode::NFT2278			),2279			CommonError::<Test>::TotalCollectionsLimitExceeded2280		);2281	});2282}22832284// Owned tokens by a single address. Positive test2285#[test]2286fn owned_tokens_bound() {2287	new_test_ext().execute_with(|| {2288		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));22892290		let data = default_nft_data();2291		create_test_item(collection_id, &data.clone().into());2292		create_test_item(collection_id, &data.into());2293	});2294}22952296// Owned tokens by a single address. Negotive test2297#[test]2298fn owned_tokens_bound_neg() {2299	new_test_ext().execute_with(|| {2300		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23012302		let origin1 = Origin::signed(1);23032304		for _ in 1..=MAX_TOKEN_OWNERSHIP {2305			let data = default_nft_data();2306			create_test_item(collection_id, &data.clone().into());2307		}23082309		let data = default_nft_data();2310		assert_noop!(2311			TemplateModule::create_item(origin1, CollectionId(1), account(1), data.into())2312				.map_err(|e| e.error),2313			CommonError::<Test>::AccountTokenLimitExceeded2314		);2315	});2316}23172318// Number of collection admins. Positive test2319#[test]2320fn collection_admins_bound() {2321	new_test_ext().execute_with(|| {2322		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23232324		let origin1 = Origin::signed(1);23252326		assert_ok!(TemplateModule::add_collection_admin(2327			origin1.clone(),2328			collection_id,2329			account(2)2330		));2331		assert_ok!(TemplateModule::add_collection_admin(2332			origin1,2333			collection_id,2334			account(3)2335		));2336	});2337}23382339// Number of collection admins. Negotive test2340#[test]2341fn collection_admins_bound_neg() {2342	new_test_ext().execute_with(|| {2343		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23442345		let origin1 = Origin::signed(1);23462347		for i in 0..COLLECTION_ADMINS_LIMIT {2348			assert_ok!(TemplateModule::add_collection_admin(2349				origin1.clone(),2350				collection_id,2351				account((2 + i).into())2352			));2353		}2354		assert_noop!(2355			TemplateModule::add_collection_admin(2356				origin1,2357				collection_id,2358				account((3 + COLLECTION_ADMINS_LIMIT).into())2359			),2360			CommonError::<Test>::CollectionAdminCountExceeded2361		);2362	});2363}2364// #endregion23652366#[test]2367fn set_const_on_chain_schema() {2368	new_test_ext().execute_with(|| {2369		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23702371		let origin1 = Origin::signed(1);2372		assert_ok!(TemplateModule::set_const_on_chain_schema(2373			origin1,2374			collection_id,2375			b"test const on chain schema".to_vec()2376		));23772378		assert_eq!(2379			<pallet_common::CollectionById<Test>>::get(collection_id)2380				.unwrap()2381				.const_on_chain_schema,2382			b"test const on chain schema".to_vec()2383		);2384		assert_eq!(2385			<pallet_common::CollectionById<Test>>::get(collection_id)2386				.unwrap()2387				.variable_on_chain_schema,2388			b"".to_vec()2389		);2390	});2391}23922393#[test]2394fn set_variable_on_chain_schema() {2395	new_test_ext().execute_with(|| {2396		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23972398		let origin1 = Origin::signed(1);2399		assert_ok!(TemplateModule::set_variable_on_chain_schema(2400			origin1,2401			collection_id,2402			b"test variable on chain schema".to_vec()2403		));24042405		assert_eq!(2406			<pallet_common::CollectionById<Test>>::get(collection_id)2407				.unwrap()2408				.const_on_chain_schema,2409			b"".to_vec()2410		);2411		assert_eq!(2412			<pallet_common::CollectionById<Test>>::get(collection_id)2413				.unwrap()2414				.variable_on_chain_schema,2415			b"test variable on chain schema".to_vec()2416		);2417	});2418}24192420#[test]2421fn set_variable_meta_data_on_nft_token_stores_variable_meta_data() {2422	new_test_ext().execute_with(|| {2423		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));24242425		let origin1 = Origin::signed(1);24262427		let data = default_nft_data();2428		create_test_item(CollectionId(1), &data.into());24292430		let variable_data = b"test data".to_vec();2431		assert_ok!(TemplateModule::set_variable_meta_data(2432			origin1,2433			collection_id,2434			TokenId(1),2435			variable_data.clone()2436		));24372438		assert_eq!(2439			<pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))2440				.unwrap()2441				.variable_data,2442			variable_data2443		);2444	});2445}24462447#[test]2448fn set_variable_meta_data_on_re_fungible_token_stores_variable_meta_data() {2449	new_test_ext().execute_with(|| {2450		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));24512452		let origin1 = Origin::signed(1);24532454		let data = default_re_fungible_data();2455		create_test_item(collection_id, &data.into());24562457		let variable_data = b"test data".to_vec();2458		assert_ok!(TemplateModule::set_variable_meta_data(2459			origin1,2460			collection_id,2461			TokenId(1),2462			variable_data.clone()2463		));24642465		assert_eq!(2466			<pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1))).variable_data,2467			variable_data2468		);2469	});2470}24712472#[test]2473fn set_variable_meta_data_on_fungible_token_fails() {2474	new_test_ext().execute_with(|| {2475		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));24762477		let origin1 = Origin::signed(1);24782479		let data = default_fungible_data();2480		create_test_item(collection_id, &data.into());24812482		let variable_data = b"test data".to_vec();2483		assert_noop!(2484			TemplateModule::set_variable_meta_data(2485				origin1,2486				collection_id,2487				TokenId(0),2488				variable_data2489			)2490			.map_err(|e| e.error),2491			<pallet_fungible::Error<Test>>::FungibleItemsDontHaveData2492		);2493	});2494}24952496#[test]2497fn set_variable_meta_data_on_nft_token_fails_for_big_data() {2498	new_test_ext().execute_with(|| {2499		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));25002501		let origin1 = Origin::signed(1);25022503		let data = default_nft_data();2504		create_test_item(collection_id, &data.into());25052506		let variable_data = b"test set_variable_meta_data method, bigger than limits.".to_vec();2507		assert_noop!(2508			TemplateModule::set_variable_meta_data(2509				origin1,2510				collection_id,2511				TokenId(1),2512				variable_data2513			)2514			.map_err(|e| e.error),2515			CommonError::<Test>::TokenVariableDataLimitExceeded2516		);2517	});2518}25192520#[test]2521fn set_variable_meta_data_on_re_fungible_token_fails_for_big_data() {2522	new_test_ext().execute_with(|| {2523		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));25242525		let origin1 = Origin::signed(1);25262527		let data = default_re_fungible_data();2528		create_test_item(collection_id, &data.into());25292530		let variable_data = b"test set_variable_meta_data method, bigger than limits.".to_vec();2531		assert_noop!(2532			TemplateModule::set_variable_meta_data(2533				origin1,2534				collection_id,2535				TokenId(1),2536				variable_data2537			)2538			.map_err(|e| e.error),2539			CommonError::<Test>::TokenVariableDataLimitExceeded2540		);2541	});2542}25432544#[test]2545fn set_variable_meta_data_on_nft_with_item_owner_permission_flag() {2546	new_test_ext().execute_with(|| {2547		//default_limits();25482549		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));25502551		let origin1 = Origin::signed(1);25522553		let data = default_nft_data();2554		create_test_item(collection_id, &data.into());25552556		assert_ok!(TemplateModule::set_meta_update_permission_flag(2557			origin1.clone(),2558			collection_id,2559			MetaUpdatePermission::ItemOwner,2560		));25612562		let variable_data = b"ten chars.".to_vec();2563		assert_ok!(TemplateModule::set_variable_meta_data(2564			origin1,2565			collection_id,2566			TokenId(1),2567			variable_data.clone()2568		));25692570		assert_eq!(2571			<pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))2572				.unwrap()2573				.variable_data,2574			variable_data2575		);2576	});2577}25782579#[test]2580fn set_variable_meta_data_on_nft_with_item_owner_permission_flag_neg() {2581	new_test_ext().execute_with(|| {2582		let collection_id =2583			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));25842585		let origin1 = Origin::signed(1);25862587		assert_ok!(TemplateModule::set_mint_permission(2588			origin1.clone(),2589			collection_id,2590			true2591		));2592		assert_ok!(TemplateModule::add_to_allow_list(2593			origin1.clone(),2594			collection_id,2595			account(1)2596		));25972598		let data = default_nft_data();2599		create_test_item(collection_id, &data.into());26002601		assert_ok!(TemplateModule::set_meta_update_permission_flag(2602			origin1.clone(),2603			collection_id,2604			MetaUpdatePermission::ItemOwner,2605		));26062607		let variable_data = b"1234567890123".to_vec();2608		assert_noop!(2609			TemplateModule::set_variable_meta_data(2610				origin1,2611				collection_id,2612				TokenId(1),2613				variable_data.clone()2614			)2615			.map_err(|e| e.error),2616			CommonError::<Test>::TokenVariableDataLimitExceeded2617		);2618	})2619}26202621#[test]2622fn collection_transfer_flag_works() {2623	new_test_ext().execute_with(|| {2624		let origin1 = Origin::signed(1);26252626		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));2627		assert_ok!(TemplateModule::set_transfers_enabled_flag(2628			origin1,2629			collection_id,2630			true2631		));26322633		let data = default_nft_data();2634		create_test_item(collection_id, &data.into());2635		assert_eq!(2636			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2637			12638		);2639		assert_eq!(2640			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2641			true2642		);26432644		let origin1 = Origin::signed(1);26452646		// default scenario2647		assert_ok!(TemplateModule::transfer(2648			origin1,2649			account(2),2650			collection_id,2651			TokenId(1),2652			12653		));2654		assert_eq!(2655			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2656			false2657		);2658		assert_eq!(2659			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),2660			true2661		);2662		assert_eq!(2663			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2664			02665		);2666		assert_eq!(2667			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),2668			12669		);2670	});2671}26722673#[test]2674fn set_variable_meta_data_on_nft_with_admin_flag() {2675	new_test_ext().execute_with(|| {2676		// default_limits();26772678		let collection_id =2679			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));26802681		let origin1 = Origin::signed(1);2682		let origin2 = Origin::signed(2);26832684		assert_ok!(TemplateModule::set_mint_permission(2685			origin2.clone(),2686			collection_id,2687			true2688		));2689		assert_ok!(TemplateModule::add_to_allow_list(2690			origin2.clone(),2691			collection_id,2692			account(1)2693		));26942695		assert_ok!(TemplateModule::add_collection_admin(2696			origin2.clone(),2697			collection_id,2698			account(1)2699		));27002701		let data = default_nft_data();2702		create_test_item(collection_id, &data.into());27032704		assert_ok!(TemplateModule::set_meta_update_permission_flag(2705			origin2.clone(),2706			collection_id,2707			MetaUpdatePermission::Admin,2708		));27092710		let variable_data = b"test.".to_vec();2711		assert_ok!(TemplateModule::set_variable_meta_data(2712			origin1,2713			collection_id,2714			TokenId(1),2715			variable_data.clone()2716		));27172718		assert_eq!(2719			<pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))2720				.unwrap()2721				.variable_data,2722			variable_data2723		);2724	});2725}27262727#[test]2728fn set_variable_meta_data_on_nft_with_admin_flag_neg() {2729	new_test_ext().execute_with(|| {2730		// default_limits();27312732		let collection_id =2733			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));27342735		let origin1 = Origin::signed(1);2736		let origin2 = Origin::signed(2);27372738		assert_ok!(TemplateModule::set_mint_permission(2739			origin2.clone(),2740			collection_id,2741			true2742		));2743		assert_ok!(TemplateModule::add_to_allow_list(2744			origin2.clone(),2745			collection_id,2746			account(1)2747		));27482749		let data = default_nft_data();2750		create_test_item(collection_id, &data.into());27512752		assert_ok!(TemplateModule::set_meta_update_permission_flag(2753			origin2.clone(),2754			collection_id,2755			MetaUpdatePermission::Admin,2756		));27572758		let variable_data = b"test.".to_vec();2759		assert_noop!(2760			TemplateModule::set_variable_meta_data(2761				origin1,2762				collection_id,2763				TokenId(1),2764				variable_data.clone()2765			)2766			.map_err(|e| e.error),2767			CommonError::<Test>::NoPermission2768		);2769	});2770}27712772#[test]2773fn set_variable_meta_flag_after_freeze() {2774	new_test_ext().execute_with(|| {2775		// default_limits();27762777		let collection_id =2778			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));27792780		let origin2 = Origin::signed(2);27812782		assert_ok!(TemplateModule::set_meta_update_permission_flag(2783			origin2.clone(),2784			collection_id,2785			MetaUpdatePermission::None,2786		));2787		assert_noop!(2788			TemplateModule::set_meta_update_permission_flag(2789				origin2.clone(),2790				collection_id,2791				MetaUpdatePermission::Admin2792			),2793			CommonError::<Test>::MetadataFlagFrozen2794		);2795	});2796}27972798#[test]2799fn set_variable_meta_data_on_nft_with_none_flag_neg() {2800	new_test_ext().execute_with(|| {2801		// default_limits();28022803		let collection_id =2804			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));2805		let origin1 = Origin::signed(1);28062807		let data = default_nft_data();2808		create_test_item(collection_id, &data.into());28092810		assert_ok!(TemplateModule::set_meta_update_permission_flag(2811			origin1.clone(),2812			collection_id,2813			MetaUpdatePermission::None,2814		));28152816		let variable_data = b"test.".to_vec();2817		assert_noop!(2818			TemplateModule::set_variable_meta_data(2819				origin1.clone(),2820				collection_id,2821				TokenId(1),2822				variable_data.clone()2823			)2824			.map_err(|e| e.error),2825			CommonError::<Test>::NoPermission2826		);2827	});2828}28292830#[test]2831fn collection_transfer_flag_works_neg() {2832	new_test_ext().execute_with(|| {2833		let origin1 = Origin::signed(1);28342835		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));2836		assert_ok!(TemplateModule::set_transfers_enabled_flag(2837			origin1,2838			collection_id,2839			false2840		));28412842		let data = default_nft_data();2843		create_test_item(collection_id, &data.into());2844		assert_eq!(2845			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2846			12847		);2848		assert_eq!(2849			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2850			true2851		);28522853		let origin1 = Origin::signed(1);28542855		// default scenario2856		assert_noop!(2857			TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 1)2858				.map_err(|e| e.error),2859			CommonError::<Test>::TransferNotAllowed2860		);2861		assert_eq!(2862			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2863			12864		);2865		assert_eq!(2866			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),2867			02868		);2869		assert_eq!(2870			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2871			true2872		);2873		assert_eq!(2874			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),2875			false2876		);2877	});2878}
after · pallets/unique/src/tests.rs
1// Tests to be written here2use super::*;3use crate::mock::*;4use crate::{AccessMode, CollectionMode};5use up_data_structs::{6	COLLECTION_NUMBER_LIMIT, CollectionId, CreateItemData, CreateFungibleData, CreateNftData,7	CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT, MetaUpdatePermission,8	TokenId,9};10use frame_support::{assert_noop, assert_ok};11use sp_std::convert::TryInto;1213fn default_nft_data() -> CreateNftData {14	CreateNftData {15		const_data: vec![1, 2, 3].try_into().unwrap(),16		variable_data: vec![3, 2, 1].try_into().unwrap(),17	}18}1920fn default_fungible_data() -> CreateFungibleData {21	CreateFungibleData { value: 5 }22}2324fn default_re_fungible_data() -> CreateReFungibleData {25	CreateReFungibleData {26		const_data: vec![1, 2, 3].try_into().unwrap(),27		variable_data: vec![3, 2, 1].try_into().unwrap(),28		pieces: 1023,29	}30}3132fn create_test_collection_for_owner(33	mode: &CollectionMode,34	owner: u64,35	id: CollectionId,36) -> CollectionId {37	let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();38	let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();39	let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();4041	let origin1 = Origin::signed(owner);42	assert_ok!(TemplateModule::create_collection(43		origin1,44		col_name1,45		col_desc1,46		token_prefix1,47		mode.clone()48	));4950	let saved_col_name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();51	let saved_description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();52	let saved_prefix: Vec<u8> = b"token_prefix1\0".to_vec();53	assert_eq!(54		<pallet_common::CollectionById<Test>>::get(id)55			.unwrap()56			.owner,57		owner58	);59	assert_eq!(60		<pallet_common::CollectionById<Test>>::get(id).unwrap().name,61		saved_col_name62	);63	assert_eq!(64		<pallet_common::CollectionById<Test>>::get(id).unwrap().mode,65		*mode66	);67	assert_eq!(68		<pallet_common::CollectionById<Test>>::get(id)69			.unwrap()70			.description,71		saved_description72	);73	assert_eq!(74		<pallet_common::CollectionById<Test>>::get(id)75			.unwrap()76			.token_prefix,77		saved_prefix78	);79	id80}8182fn create_test_collection(mode: &CollectionMode, id: CollectionId) -> CollectionId {83	create_test_collection_for_owner(&mode, 1, id)84}8586fn create_test_item(collection_id: CollectionId, data: &CreateItemData) {87	let origin1 = Origin::signed(1);88	assert_ok!(TemplateModule::create_item(89		origin1,90		collection_id,91		account(1),92		data.clone()93	));94}9596fn account(sub: u64) -> TestCrossAccountId {97	TestCrossAccountId::from_sub(sub)98}99100// Use cases tests region101// #region102103#[test]104fn set_version_schema() {105	new_test_ext().execute_with(|| {106		let origin1 = Origin::signed(1);107		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));108109		assert_ok!(TemplateModule::set_schema_version(110			origin1,111			collection_id,112			SchemaVersion::Unique113		));114		assert_eq!(115			<pallet_common::CollectionById<Test>>::get(collection_id)116				.unwrap()117				.schema_version,118			SchemaVersion::Unique119		);120	});121}122123#[test]124fn create_fungible_collection_fails_with_large_decimal_numbers() {125	new_test_ext().execute_with(|| {126		let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();127		let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();128		let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();129130		let origin1 = Origin::signed(1);131		assert_noop!(132			TemplateModule::create_collection(133				origin1,134				col_name1,135				col_desc1,136				token_prefix1,137				CollectionMode::Fungible(MAX_DECIMAL_POINTS + 1)138			),139			Error::<Test>::CollectionDecimalPointLimitExceeded140		);141	});142}143144#[test]145fn create_nft_item() {146	new_test_ext().execute_with(|| {147		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));148149		let data = default_nft_data();150		create_test_item(collection_id, &data.clone().into());151152		let item = <pallet_nonfungible::TokenData<Test>>::get((collection_id, 1)).unwrap();153		assert_eq!(item.const_data, data.const_data.into_inner());154		assert_eq!(item.variable_data, data.variable_data.into_inner());155	});156}157158// Use cases tests region159// #region160#[test]161fn create_nft_multiple_items() {162	new_test_ext().execute_with(|| {163		create_test_collection(&CollectionMode::NFT, CollectionId(1));164165		let origin1 = Origin::signed(1);166167		let items_data = vec![default_nft_data(), default_nft_data(), default_nft_data()];168169		assert_ok!(TemplateModule::create_multiple_items(170			origin1,171			CollectionId(1),172			account(1),173			items_data174				.clone()175				.into_iter()176				.map(|d| { d.into() })177				.collect()178		));179		for (index, data) in items_data.into_iter().enumerate() {180			let item = <pallet_nonfungible::TokenData<Test>>::get((181				CollectionId(1),182				TokenId((index + 1) as u32),183			))184			.unwrap();185			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());186			assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());187		}188	});189}190191#[test]192fn create_refungible_item() {193	new_test_ext().execute_with(|| {194		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));195196		let data = default_re_fungible_data();197		create_test_item(collection_id, &data.clone().into());198		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));199		let balance =200			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1)));201		assert_eq!(item.const_data, data.const_data.into_inner());202		assert_eq!(item.variable_data, data.variable_data.into_inner());203		assert_eq!(balance, 1023);204	});205}206207#[test]208fn create_multiple_refungible_items() {209	new_test_ext().execute_with(|| {210		create_test_collection(&CollectionMode::ReFungible, CollectionId(1));211212		let origin1 = Origin::signed(1);213214		let items_data = vec![215			default_re_fungible_data(),216			default_re_fungible_data(),217			default_re_fungible_data(),218		];219220		assert_ok!(TemplateModule::create_multiple_items(221			origin1,222			CollectionId(1),223			account(1),224			items_data225				.clone()226				.into_iter()227				.map(|d| { d.into() })228				.collect()229		));230		for (index, data) in items_data.into_iter().enumerate() {231			let item = <pallet_refungible::TokenData<Test>>::get((232				CollectionId(1),233				TokenId((index + 1) as u32),234			));235			let balance =236				<pallet_refungible::Balance<Test>>::get((CollectionId(1), TokenId(1), account(1)));237			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());238			assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());239			assert_eq!(balance, 1023);240		}241	});242}243244#[test]245fn create_fungible_item() {246	new_test_ext().execute_with(|| {247		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));248249		let data = default_fungible_data();250		create_test_item(collection_id, &data.into());251252		assert_eq!(253			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),254			5255		);256	});257}258259//#[test]260// fn create_multiple_fungible_items() {261//     new_test_ext().execute_with(|| {262//         default_limits();263264//         create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));265266//         let origin1 = Origin::signed(1);267268//         let items_data = vec![default_fungible_data(), default_fungible_data(), default_fungible_data()];269270//         assert_ok!(TemplateModule::create_multiple_items(271//             origin1.clone(),272//             1,273//             1,274//             items_data.clone().into_iter().map(|d| { d.into() }).collect()275//         ));276277//         for (index, _) in items_data.iter().enumerate() {278//             assert_eq!(TemplateModule::fungible_item_id(1, (index + 1) as TokenId).value, 5);279//         }280//         assert_eq!(TemplateModule::balance_count(1, 1), 3000);281//         assert_eq!(TemplateModule::address_tokens(1, 1), [1, 2, 3]);282//     });283// }284285#[test]286fn transfer_fungible_item() {287	new_test_ext().execute_with(|| {288		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));289290		let origin1 = Origin::signed(1);291		let origin2 = Origin::signed(2);292293		let data = default_fungible_data();294		create_test_item(collection_id, &data.into());295296		assert_eq!(297			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))),298			5299		);300301		// change owner scenario302		assert_ok!(TemplateModule::transfer(303			origin1,304			account(2),305			CollectionId(1),306			TokenId(0),307			5308		));309		assert_eq!(310			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))),311			0312		);313314		// split item scenario315		assert_ok!(TemplateModule::transfer(316			origin2.clone(),317			account(3),318			CollectionId(1),319			TokenId(0),320			3321		));322323		// split item and new owner has account scenario324		assert_ok!(TemplateModule::transfer(325			origin2,326			account(3),327			CollectionId(1),328			TokenId(0),329			1330		));331		assert_eq!(332			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(2))),333			1334		);335		assert_eq!(336			<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(3))),337			4338		);339	});340}341342#[test]343fn transfer_refungible_item() {344	new_test_ext().execute_with(|| {345		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));346347		// Create RFT 1 in 1023 pieces for account 1348		let data = default_re_fungible_data();349		create_test_item(collection_id, &data.clone().into());350		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));351		assert_eq!(item.const_data, data.const_data.into_inner());352		assert_eq!(item.variable_data, data.variable_data.into_inner());353		assert_eq!(354			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),355			1356		);357		assert_eq!(358			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),359			1023360		);361		assert_eq!(362			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),363			true364		);365366		// Account 1 transfers all 1023 pieces of RFT 1 to account 2367		let origin1 = Origin::signed(1);368		let origin2 = Origin::signed(2);369		assert_ok!(TemplateModule::transfer(370			origin1,371			account(2),372			CollectionId(1),373			TokenId(1),374			1023375		));376		assert_eq!(377			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),378			1023379		);380		assert_eq!(381			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),382			0383		);384		assert_eq!(385			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),386			1387		);388		assert_eq!(389			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),390			false391		);392		assert_eq!(393			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),394			true395		);396397		// Account 2 transfers 500 pieces of RFT 1 to account 3398		assert_ok!(TemplateModule::transfer(399			origin2.clone(),400			account(3),401			CollectionId(1),402			TokenId(1),403			500404		));405		assert_eq!(406			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),407			523408		);409		assert_eq!(410			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),411			500412		);413		assert_eq!(414			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),415			1416		);417		assert_eq!(418			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),419			1420		);421		assert_eq!(422			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),423			true424		);425		assert_eq!(426			<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))),427			true428		);429430		// Account 2 transfers 200 more pieces of RFT 1 to account 3 with pre-existing balance431		assert_ok!(TemplateModule::transfer(432			origin2,433			account(3),434			CollectionId(1),435			TokenId(1),436			200437		));438		assert_eq!(439			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))),440			323441		);442		assert_eq!(443			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),444			700445		);446		assert_eq!(447			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))),448			1449		);450		assert_eq!(451			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),452			1453		);454		assert_eq!(455			<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),456			true457		);458		assert_eq!(459			<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))),460			true461		);462	});463}464465#[test]466fn transfer_nft_item() {467	new_test_ext().execute_with(|| {468		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));469470		let data = default_nft_data();471		create_test_item(collection_id, &data.into());472		assert_eq!(473			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),474			1475		);476		assert_eq!(477			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),478			true479		);480481		let origin1 = Origin::signed(1);482		// default scenario483		assert_ok!(TemplateModule::transfer(484			origin1,485			account(2),486			CollectionId(1),487			TokenId(1),488			1489		));490		assert_eq!(491			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),492			0493		);494		assert_eq!(495			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),496			1497		);498		assert_eq!(499			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),500			false501		);502		assert_eq!(503			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),504			true505		);506	});507}508509#[test]510fn transfer_nft_item_wrong_value() {511	new_test_ext().execute_with(|| {512		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));513514		let data = default_nft_data();515		create_test_item(collection_id, &data.into());516		assert_eq!(517			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),518			1519		);520		assert_eq!(521			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),522			true523		);524525		let origin1 = Origin::signed(1);526527		assert_noop!(528			TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 2)529				.map_err(|e| e.error),530			<pallet_nonfungible::Error::<Test>>::NonfungibleItemsHaveNoAmount531		);532	});533}534535#[test]536fn transfer_nft_item_zero_value() {537	new_test_ext().execute_with(|| {538		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));539540		let data = default_nft_data();541		create_test_item(collection_id, &data.into());542		assert_eq!(543			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),544			1545		);546		assert_eq!(547			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),548			true549		);550551		let origin1 = Origin::signed(1);552553		// Transferring 0 amount works on NFT...554		assert_ok!(TemplateModule::transfer(555			origin1,556			account(2),557			CollectionId(1),558			TokenId(1),559			0560		));561		// ... and results in no transfer562		assert_eq!(563			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),564			1565		);566		assert_eq!(567			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),568			true569		);570	});571}572573#[test]574fn nft_approve_and_transfer_from() {575	new_test_ext().execute_with(|| {576		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));577578		let data = default_nft_data();579		create_test_item(collection_id, &data.into());580581		let origin1 = Origin::signed(1);582		let origin2 = Origin::signed(2);583584		assert_eq!(585			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),586			1587		);588		assert_eq!(589			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),590			true591		);592593		// neg transfer_from594		assert_noop!(595			TemplateModule::transfer_from(596				origin2.clone(),597				account(1),598				account(2),599				CollectionId(1),600				TokenId(1),601				1602			)603			.map_err(|e| e.error),604			CommonError::<Test>::TokenValueNotEnough605		);606607		// do approve608		assert_ok!(TemplateModule::approve(609			origin1,610			account(2),611			CollectionId(1),612			TokenId(1),613			1614		));615		assert_eq!(616			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),617			account(2)618		);619620		assert_ok!(TemplateModule::transfer_from(621			origin2,622			account(1),623			account(3),624			CollectionId(1),625			TokenId(1),626			1627		));628		assert!(629			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).is_none()630		);631	});632}633634#[test]635fn nft_approve_and_transfer_from_allow_list() {636	new_test_ext().execute_with(|| {637		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));638639		let origin1 = Origin::signed(1);640		let origin2 = Origin::signed(2);641642		// Create NFT 1 for account 1643		let data = default_nft_data();644		create_test_item(collection_id, &data.clone().into());645		assert_eq!(646			&<pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))647				.unwrap()648				.const_data,649			&data.const_data.into_inner()650		);651		assert_eq!(652			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),653			1654		);655		assert_eq!(656			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),657			true658		);659660		// Allow allow-list users to mint and add accounts 1, 2, and 3 to allow-list661		assert_ok!(TemplateModule::set_mint_permission(662			origin1.clone(),663			CollectionId(1),664			true665		));666		assert_ok!(TemplateModule::set_public_access_mode(667			origin1.clone(),668			CollectionId(1),669			AccessMode::AllowList670		));671		assert_ok!(TemplateModule::add_to_allow_list(672			origin1.clone(),673			CollectionId(1),674			account(1)675		));676		assert_ok!(TemplateModule::add_to_allow_list(677			origin1.clone(),678			CollectionId(1),679			account(2)680		));681		assert_ok!(TemplateModule::add_to_allow_list(682			origin1.clone(),683			CollectionId(1),684			account(3)685		));686687		// Account 1 approves account 2 for NFT 1688		assert_ok!(TemplateModule::approve(689			origin1.clone(),690			account(2),691			CollectionId(1),692			TokenId(1),693			1694		));695		assert_eq!(696			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),697			account(2)698		);699700		// Account 2 transfers NFT 1 from account 1 to account 3701		assert_ok!(TemplateModule::transfer_from(702			origin2,703			account(1),704			account(3),705			CollectionId(1),706			TokenId(1),707			1708		));709		assert!(710			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).is_none()711		);712	});713}714715#[test]716fn refungible_approve_and_transfer_from() {717	new_test_ext().execute_with(|| {718		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));719720		let origin1 = Origin::signed(1);721		let origin2 = Origin::signed(2);722723		// Create RFT 1 in 1023 pieces for account 1724		let data = default_re_fungible_data();725		create_test_item(collection_id, &data.into());726727		assert_eq!(728			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),729			1730		);731		assert_eq!(732			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),733			1023734		);735		assert_eq!(736			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),737			true738		);739740		// Allow public minting, enable allow-list and add accounts 1, 2, 3 to allow-list741		assert_ok!(TemplateModule::set_mint_permission(742			origin1.clone(),743			CollectionId(1),744			true745		));746		assert_ok!(TemplateModule::set_public_access_mode(747			origin1.clone(),748			CollectionId(1),749			AccessMode::AllowList750		));751		assert_ok!(TemplateModule::add_to_allow_list(752			origin1.clone(),753			CollectionId(1),754			account(1)755		));756		assert_ok!(TemplateModule::add_to_allow_list(757			origin1.clone(),758			CollectionId(1),759			account(2)760		));761		assert_ok!(TemplateModule::add_to_allow_list(762			origin1.clone(),763			CollectionId(1),764			account(3)765		));766767		// Account 1 approves account 2 for 1023 pieces of RFT 1768		assert_ok!(TemplateModule::approve(769			origin1,770			account(2),771			CollectionId(1),772			TokenId(1),773			1023774		));775		assert_eq!(776			<pallet_refungible::Allowance<Test>>::get((777				CollectionId(1),778				TokenId(1),779				account(1),780				account(2)781			)),782			1023783		);784785		// Account 2 transfers 100 pieces of RFT 1 from account 1 to account 3786		assert_ok!(TemplateModule::transfer_from(787			origin2,788			account(1),789			account(3),790			CollectionId(1),791			TokenId(1),792			100793		));794		assert_eq!(795			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),796			1797		);798		assert_eq!(799			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))),800			1801		);802		assert_eq!(803			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),804			923805		);806		assert_eq!(807			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))),808			100809		);810		assert_eq!(811			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),812			true813		);814		assert_eq!(815			<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),816			true817		);818		assert_eq!(819			<pallet_refungible::Allowance<Test>>::get((820				CollectionId(1),821				TokenId(1),822				account(1),823				account(2)824			)),825			923826		);827	});828}829830#[test]831fn fungible_approve_and_transfer_from() {832	new_test_ext().execute_with(|| {833		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));834835		let data = default_fungible_data();836		create_test_item(collection_id, &data.into());837838		let origin1 = Origin::signed(1);839		let origin2 = Origin::signed(2);840841		assert_ok!(TemplateModule::set_mint_permission(842			origin1.clone(),843			CollectionId(1),844			true845		));846		assert_ok!(TemplateModule::set_public_access_mode(847			origin1.clone(),848			CollectionId(1),849			AccessMode::AllowList850		));851		assert_ok!(TemplateModule::add_to_allow_list(852			origin1.clone(),853			CollectionId(1),854			account(1)855		));856		assert_ok!(TemplateModule::add_to_allow_list(857			origin1.clone(),858			CollectionId(1),859			account(2)860		));861		assert_ok!(TemplateModule::add_to_allow_list(862			origin1.clone(),863			CollectionId(1),864			account(3)865		));866867		// do approve868		assert_ok!(TemplateModule::approve(869			origin1.clone(),870			account(2),871			CollectionId(1),872			TokenId(0),873			5874		));875		assert_eq!(876			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),877			5878		);879		assert_ok!(TemplateModule::approve(880			origin1,881			account(3),882			CollectionId(1),883			TokenId(0),884			5885		));886		assert_eq!(887			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),888			5889		);890		assert_eq!(891			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(3))),892			5893		);894895		assert_ok!(TemplateModule::transfer_from(896			origin2.clone(),897			account(1),898			account(3),899			CollectionId(1),900			TokenId(0),901			4902		));903904		assert_eq!(905			<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))),906			1907		);908909		assert_noop!(910			TemplateModule::transfer_from(911				origin2,912				account(1),913				account(3),914				CollectionId(1),915				TokenId(0),916				4917			)918			.map_err(|e| e.error),919			CommonError::<Test>::TokenValueNotEnough920		);921	});922}923924#[test]925fn change_collection_owner() {926	new_test_ext().execute_with(|| {927		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));928929		let origin1 = Origin::signed(1);930		assert_ok!(TemplateModule::change_collection_owner(931			origin1,932			collection_id,933			2934		));935		assert_eq!(936			<pallet_common::CollectionById<Test>>::get(collection_id)937				.unwrap()938				.owner,939			2940		);941	});942}943944#[test]945fn destroy_collection() {946	new_test_ext().execute_with(|| {947		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));948949		let origin1 = Origin::signed(1);950		assert_ok!(TemplateModule::destroy_collection(origin1, collection_id));951	});952}953954#[test]955fn burn_nft_item() {956	new_test_ext().execute_with(|| {957		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));958959		let origin1 = Origin::signed(1);960961		let data = default_nft_data();962		create_test_item(collection_id, &data.into());963964		// check balance (collection with id = 1, user id = 1)965		assert_eq!(966			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),967			1968		);969970		// burn item971		assert_ok!(TemplateModule::burn_item(972			origin1.clone(),973			collection_id,974			TokenId(1),975			1976		));977		assert_eq!(978			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),979			0980		);981	});982}983984#[test]985fn burn_same_nft_item_twice() {986	new_test_ext().execute_with(|| {987		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));988989		let origin1 = Origin::signed(1);990991		let data = default_nft_data();992		create_test_item(collection_id, &data.into());993994		// check balance (collection with id = 1, user id = 1)995		assert_eq!(996			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),997			1998		);9991000		// burn item1001		assert_ok!(TemplateModule::burn_item(1002			origin1.clone(),1003			collection_id,1004			TokenId(1),1005			11006		));10071008		// burn item again1009		assert_noop!(1010			TemplateModule::burn_item(origin1, collection_id, TokenId(1), 1).map_err(|e| e.error),1011			CommonError::<Test>::TokenNotFound1012		);10131014		assert_eq!(1015			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),1016			01017		);1018	});1019}10201021#[test]1022fn burn_fungible_item() {1023	new_test_ext().execute_with(|| {1024		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));10251026		let origin1 = Origin::signed(1);1027		assert_ok!(TemplateModule::add_collection_admin(1028			origin1.clone(),1029			collection_id,1030			account(2)1031		));10321033		let data = default_fungible_data();1034		create_test_item(collection_id, &data.into());10351036		// check balance (collection with id = 1, user id = 1)1037		assert_eq!(1038			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),1039			51040		);10411042		// burn item1043		assert_ok!(TemplateModule::burn_item(1044			origin1.clone(),1045			CollectionId(1),1046			TokenId(0),1047			51048		));1049		assert_noop!(1050			TemplateModule::burn_item(origin1, CollectionId(1), TokenId(0), 5).map_err(|e| e.error),1051			CommonError::<Test>::TokenValueTooLow1052		);10531054		assert_eq!(1055			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),1056			01057		);1058	});1059}10601061#[test]1062fn burn_fungible_item_with_token_id() {1063	new_test_ext().execute_with(|| {1064		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));10651066		let origin1 = Origin::signed(1);1067		assert_ok!(TemplateModule::add_collection_admin(1068			origin1.clone(),1069			collection_id,1070			account(2)1071		));10721073		let data = default_fungible_data();1074		create_test_item(collection_id, &data.into());10751076		// check balance (collection with id = 1, user id = 1)1077		assert_eq!(1078			<pallet_fungible::Balance<Test>>::get((collection_id, account(1))),1079			51080		);10811082		// Try to burn item using Token ID1083		assert_noop!(1084			TemplateModule::burn_item(origin1, CollectionId(1), TokenId(1), 5).map_err(|e| e.error),1085			<pallet_fungible::Error::<Test>>::FungibleItemsHaveNoId1086		);1087	});1088}1089#[test]1090fn burn_refungible_item() {1091	new_test_ext().execute_with(|| {1092		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));1093		let origin1 = Origin::signed(1);10941095		assert_ok!(TemplateModule::set_mint_permission(1096			origin1.clone(),1097			collection_id,1098			true1099		));1100		assert_ok!(TemplateModule::set_public_access_mode(1101			origin1.clone(),1102			collection_id,1103			AccessMode::AllowList1104		));1105		assert_ok!(TemplateModule::add_to_allow_list(1106			origin1.clone(),1107			collection_id,1108			account(1)1109		));11101111		assert_ok!(TemplateModule::add_collection_admin(1112			origin1.clone(),1113			collection_id,1114			account(2)1115		));11161117		let data = default_re_fungible_data();1118		create_test_item(collection_id, &data.into());11191120		// check balance (collection with id = 1, user id = 2)1121		assert_eq!(1122			<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))),1123			11124		);1125		assert_eq!(1126			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),1127			10231128		);11291130		// burn item1131		assert_ok!(TemplateModule::burn_item(1132			origin1.clone(),1133			collection_id,1134			TokenId(1),1135			10231136		));1137		assert_noop!(1138			TemplateModule::burn_item(origin1, collection_id, TokenId(1), 1023)1139				.map_err(|e| e.error),1140			CommonError::<Test>::TokenValueTooLow1141		);11421143		assert_eq!(1144			<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))),1145			01146		);1147	});1148}11491150#[test]1151fn add_collection_admin() {1152	new_test_ext().execute_with(|| {1153		let collection1_id =1154			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));1155		let origin1 = Origin::signed(1);11561157		// Add collection admins1158		assert_ok!(TemplateModule::add_collection_admin(1159			origin1.clone(),1160			collection1_id,1161			account(2)1162		));1163		assert_ok!(TemplateModule::add_collection_admin(1164			origin1,1165			collection1_id,1166			account(3)1167		));11681169		// Owner is not an admin by default1170		assert_eq!(1171			<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(1))),1172			false1173		);1174		assert!(<pallet_common::IsAdmin<Test>>::get((1175			CollectionId(1),1176			account(2)1177		)));1178		assert!(<pallet_common::IsAdmin<Test>>::get((1179			CollectionId(1),1180			account(3)1181		)));1182	});1183}11841185#[test]1186fn remove_collection_admin() {1187	new_test_ext().execute_with(|| {1188		let collection1_id =1189			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));1190		let origin1 = Origin::signed(1);1191		let origin2 = Origin::signed(2);11921193		// Add collection admins 2 and 31194		assert_ok!(TemplateModule::add_collection_admin(1195			origin1.clone(),1196			collection1_id,1197			account(2)1198		));1199		assert_ok!(TemplateModule::add_collection_admin(1200			origin1,1201			collection1_id,1202			account(3)1203		));12041205		assert!(<pallet_common::IsAdmin<Test>>::get((1206			CollectionId(1),1207			account(2)1208		)));1209		assert!(<pallet_common::IsAdmin<Test>>::get((1210			CollectionId(1),1211			account(3)1212		)));12131214		// remove admin 31215		assert_ok!(TemplateModule::remove_collection_admin(1216			origin2,1217			CollectionId(1),1218			account(3)1219		));12201221		// 2 is still admin, 3 is not an admin anymore1222		assert!(<pallet_common::IsAdmin<Test>>::get((1223			CollectionId(1),1224			account(2)1225		)));1226		assert_eq!(1227			<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(3))),1228			false1229		);1230	});1231}12321233#[test]1234fn balance_of() {1235	new_test_ext().execute_with(|| {1236		let nft_collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1237		let fungible_collection_id =1238			create_test_collection(&CollectionMode::Fungible(3), CollectionId(2));1239		let re_fungible_collection_id =1240			create_test_collection(&CollectionMode::ReFungible, CollectionId(3));12411242		// check balance before1243		assert_eq!(1244			<pallet_nonfungible::AccountBalance<Test>>::get((nft_collection_id, account(1))),1245			01246		);1247		assert_eq!(1248			<pallet_fungible::Balance<Test>>::get((fungible_collection_id, account(1))),1249			01250		);1251		assert_eq!(1252			<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))),1253			01254		);12551256		let nft_data = default_nft_data();1257		create_test_item(nft_collection_id, &nft_data.into());12581259		let fungible_data = default_fungible_data();1260		create_test_item(fungible_collection_id, &fungible_data.into());12611262		let re_fungible_data = default_re_fungible_data();1263		create_test_item(re_fungible_collection_id, &re_fungible_data.into());12641265		// check balance (collection with id = 1, user id = 1)1266		assert_eq!(1267			<pallet_nonfungible::AccountBalance<Test>>::get((nft_collection_id, account(1))),1268			11269		);1270		assert_eq!(1271			<pallet_fungible::Balance<Test>>::get((fungible_collection_id, account(1))),1272			51273		);1274		assert_eq!(1275			<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))),1276			11277		);12781279		assert_eq!(1280			<pallet_nonfungible::Owned<Test>>::get((nft_collection_id, account(1), TokenId(1))),1281			true1282		);1283		assert_eq!(1284			<pallet_refungible::Owned<Test>>::get((1285				re_fungible_collection_id,1286				account(1),1287				TokenId(1)1288			)),1289			true1290		);1291	});1292}12931294#[test]1295fn approve() {1296	new_test_ext().execute_with(|| {1297		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));12981299		let data = default_nft_data();1300		create_test_item(collection_id, &data.into());13011302		let origin1 = Origin::signed(1);13031304		// approve1305		assert_ok!(TemplateModule::approve(1306			origin1,1307			account(2),1308			CollectionId(1),1309			TokenId(1),1310			11311		));1312		assert_eq!(1313			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1314			account(2)1315		);1316	});1317}13181319#[test]1320fn transfer_from() {1321	new_test_ext().execute_with(|| {1322		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1323		let origin1 = Origin::signed(1);1324		let origin2 = Origin::signed(2);13251326		let data = default_nft_data();1327		create_test_item(collection_id, &data.into());13281329		// approve1330		assert_ok!(TemplateModule::approve(1331			origin1.clone(),1332			account(2),1333			CollectionId(1),1334			TokenId(1),1335			11336		));1337		assert_eq!(1338			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1339			account(2)1340		);13411342		assert_ok!(TemplateModule::set_mint_permission(1343			origin1.clone(),1344			CollectionId(1),1345			true1346		));1347		assert_ok!(TemplateModule::set_public_access_mode(1348			origin1.clone(),1349			CollectionId(1),1350			AccessMode::AllowList1351		));1352		assert_ok!(TemplateModule::add_to_allow_list(1353			origin1.clone(),1354			CollectionId(1),1355			account(1)1356		));1357		assert_ok!(TemplateModule::add_to_allow_list(1358			origin1.clone(),1359			CollectionId(1),1360			account(2)1361		));1362		assert_ok!(TemplateModule::add_to_allow_list(1363			origin1,1364			CollectionId(1),1365			account(3)1366		));13671368		assert_ok!(TemplateModule::transfer_from(1369			origin2,1370			account(1),1371			account(2),1372			CollectionId(1),1373			TokenId(1),1374			11375		));13761377		// after transfer1378		assert_eq!(1379			<pallet_nonfungible::AccountBalance<Test>>::get((CollectionId(1), account(1))),1380			01381		);1382		assert_eq!(1383			<pallet_nonfungible::AccountBalance<Test>>::get((CollectionId(1), account(2))),1384			11385		);1386	});1387}13881389// #endregion13901391// Coverage tests region1392// #region13931394#[test]1395fn owner_can_add_address_to_allow_list() {1396	new_test_ext().execute_with(|| {1397		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));13981399		let origin1 = Origin::signed(1);1400		assert_ok!(TemplateModule::add_to_allow_list(1401			origin1,1402			collection_id,1403			account(2)1404		));1405		assert!(<pallet_common::Allowlist<Test>>::get((1406			collection_id,1407			account(2)1408		)));1409	});1410}14111412#[test]1413fn admin_can_add_address_to_allow_list() {1414	new_test_ext().execute_with(|| {1415		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1416		let origin1 = Origin::signed(1);1417		let origin2 = Origin::signed(2);14181419		assert_ok!(TemplateModule::add_collection_admin(1420			origin1,1421			collection_id,1422			account(2)1423		));1424		assert_ok!(TemplateModule::add_to_allow_list(1425			origin2,1426			collection_id,1427			account(3)1428		));1429		assert!(<pallet_common::Allowlist<Test>>::get((1430			collection_id,1431			account(3)1432		)));1433	});1434}14351436#[test]1437fn nonprivileged_user_cannot_add_address_to_allow_list() {1438	new_test_ext().execute_with(|| {1439		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));14401441		let origin2 = Origin::signed(2);1442		assert_noop!(1443			TemplateModule::add_to_allow_list(origin2, collection_id, account(3)),1444			CommonError::<Test>::NoPermission1445		);1446	});1447}14481449#[test]1450fn nobody_can_add_address_to_allow_list_of_nonexisting_collection() {1451	new_test_ext().execute_with(|| {1452		let origin1 = Origin::signed(1);14531454		assert_noop!(1455			TemplateModule::add_to_allow_list(origin1, CollectionId(1), account(2)),1456			CommonError::<Test>::CollectionNotFound1457		);1458	});1459}14601461#[test]1462fn nobody_can_add_address_to_allow_list_of_deleted_collection() {1463	new_test_ext().execute_with(|| {1464		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));14651466		let origin1 = Origin::signed(1);1467		assert_ok!(TemplateModule::destroy_collection(1468			origin1.clone(),1469			collection_id1470		));1471		assert_noop!(1472			TemplateModule::add_to_allow_list(origin1, collection_id, account(2)),1473			CommonError::<Test>::CollectionNotFound1474		);1475	});1476}14771478// If address is already added to allow list, nothing happens1479#[test]1480fn address_is_already_added_to_allow_list() {1481	new_test_ext().execute_with(|| {1482		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1483		let origin1 = Origin::signed(1);14841485		assert_ok!(TemplateModule::add_to_allow_list(1486			origin1.clone(),1487			collection_id,1488			account(2)1489		));1490		assert_ok!(TemplateModule::add_to_allow_list(1491			origin1,1492			collection_id,1493			account(2)1494		));1495		assert!(<pallet_common::Allowlist<Test>>::get((1496			collection_id,1497			account(2)1498		)));1499	});1500}15011502#[test]1503fn owner_can_remove_address_from_allow_list() {1504	new_test_ext().execute_with(|| {1505		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));15061507		let origin1 = Origin::signed(1);1508		assert_ok!(TemplateModule::add_to_allow_list(1509			origin1.clone(),1510			collection_id,1511			account(2)1512		));1513		assert_ok!(TemplateModule::remove_from_allow_list(1514			origin1,1515			collection_id,1516			account(2)1517		));1518		assert_eq!(1519			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1520			false1521		);1522	});1523}15241525#[test]1526fn admin_can_remove_address_from_allow_list() {1527	new_test_ext().execute_with(|| {1528		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1529		let origin1 = Origin::signed(1);1530		let origin2 = Origin::signed(2);15311532		// Owner adds admin1533		assert_ok!(TemplateModule::add_collection_admin(1534			origin1.clone(),1535			collection_id,1536			account(2)1537		));15381539		// Owner adds address 3 to allow list1540		assert_ok!(TemplateModule::add_to_allow_list(1541			origin1,1542			collection_id,1543			account(3)1544		));15451546		// Admin removes address 3 from allow list1547		assert_ok!(TemplateModule::remove_from_allow_list(1548			origin2,1549			collection_id,1550			account(3)1551		));1552		assert_eq!(1553			<pallet_common::Allowlist<Test>>::get((collection_id, account(3))),1554			false1555		);1556	});1557}15581559#[test]1560fn nonprivileged_user_cannot_remove_address_from_allow_list() {1561	new_test_ext().execute_with(|| {1562		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1563		let origin1 = Origin::signed(1);1564		let origin2 = Origin::signed(2);15651566		assert_ok!(TemplateModule::add_to_allow_list(1567			origin1,1568			collection_id,1569			account(2)1570		));1571		assert_noop!(1572			TemplateModule::remove_from_allow_list(origin2, collection_id, account(2)),1573			CommonError::<Test>::NoPermission1574		);1575		assert!(<pallet_common::Allowlist<Test>>::get((1576			collection_id,1577			account(2)1578		)));1579	});1580}15811582#[test]1583fn nobody_can_remove_address_from_allow_list_of_nonexisting_collection() {1584	new_test_ext().execute_with(|| {1585		let origin1 = Origin::signed(1);15861587		assert_noop!(1588			TemplateModule::remove_from_allow_list(origin1, CollectionId(1), account(2)),1589			CommonError::<Test>::CollectionNotFound1590		);1591	});1592}15931594#[test]1595fn nobody_can_remove_address_from_allow_list_of_deleted_collection() {1596	new_test_ext().execute_with(|| {1597		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1598		let origin1 = Origin::signed(1);1599		let origin2 = Origin::signed(2);16001601		// Add account 2 to allow list1602		assert_ok!(TemplateModule::add_to_allow_list(1603			origin1.clone(),1604			collection_id,1605			account(2)1606		));16071608		// Account 2 is in collection allow-list1609		assert!(<pallet_common::Allowlist<Test>>::get((1610			collection_id,1611			account(2)1612		)));16131614		// Destroy collection1615		assert_ok!(TemplateModule::destroy_collection(origin1, collection_id));16161617		// Attempt to remove account 2 from collection allow-list => error1618		assert_noop!(1619			TemplateModule::remove_from_allow_list(origin2, collection_id, account(2)),1620			CommonError::<Test>::CollectionNotFound1621		);16221623		// Account 2 is not found in collection allow-list anyway1624		assert_eq!(1625			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1626			false1627		);1628	});1629}16301631// If address is already removed from allow list, nothing happens1632#[test]1633fn address_is_already_removed_from_allow_list() {1634	new_test_ext().execute_with(|| {1635		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1636		let origin1 = Origin::signed(1);16371638		assert_ok!(TemplateModule::add_to_allow_list(1639			origin1.clone(),1640			collection_id,1641			account(2)1642		));1643		assert_ok!(TemplateModule::remove_from_allow_list(1644			origin1.clone(),1645			collection_id,1646			account(2)1647		));1648		assert_eq!(1649			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1650			false1651		);1652		assert_ok!(TemplateModule::remove_from_allow_list(1653			origin1,1654			collection_id,1655			account(2)1656		));1657		assert_eq!(1658			<pallet_common::Allowlist<Test>>::get((collection_id, account(2))),1659			false1660		);1661	});1662}16631664// If Public Access mode is set to AllowList, tokens can’t be transferred from a non-allowlisted address with transfer or transferFrom (2 tests)1665#[test]1666fn allow_list_test_1() {1667	new_test_ext().execute_with(|| {1668		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));16691670		let origin1 = Origin::signed(1);16711672		let data = default_nft_data();1673		create_test_item(collection_id, &data.into());16741675		assert_ok!(TemplateModule::set_public_access_mode(1676			origin1.clone(),1677			collection_id,1678			AccessMode::AllowList1679		));1680		assert_ok!(TemplateModule::add_to_allow_list(1681			origin1.clone(),1682			collection_id,1683			account(2)1684		));16851686		assert_noop!(1687			TemplateModule::transfer(origin1, account(3), CollectionId(1), TokenId(1), 1)1688				.map_err(|e| e.error),1689			CommonError::<Test>::AddressNotInAllowlist1690		);1691	});1692}16931694#[test]1695fn allow_list_test_2() {1696	new_test_ext().execute_with(|| {1697		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1698		let origin1 = Origin::signed(1);16991700		let data = default_nft_data();1701		create_test_item(collection_id, &data.into());17021703		assert_ok!(TemplateModule::set_public_access_mode(1704			origin1.clone(),1705			collection_id,1706			AccessMode::AllowList1707		));1708		assert_ok!(TemplateModule::add_to_allow_list(1709			origin1.clone(),1710			collection_id,1711			account(1)1712		));1713		assert_ok!(TemplateModule::add_to_allow_list(1714			origin1.clone(),1715			collection_id,1716			account(2)1717		));17181719		// do approve1720		assert_ok!(TemplateModule::approve(1721			origin1.clone(),1722			account(1),1723			collection_id,1724			TokenId(1),1725			11726		));1727		assert_eq!(1728			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1729			account(1)1730		);17311732		assert_ok!(TemplateModule::remove_from_allow_list(1733			origin1.clone(),1734			collection_id,1735			account(1)1736		));17371738		assert_noop!(1739			TemplateModule::transfer_from(1740				origin1,1741				account(1),1742				account(3),1743				CollectionId(1),1744				TokenId(1),1745				11746			)1747			.map_err(|e| e.error),1748			CommonError::<Test>::AddressNotInAllowlist1749		);1750	});1751}17521753// If Public Access mode is set to AllowList, tokens can’t be transferred to a non-allowlisted address with transfer or transferFrom (2 tests)1754#[test]1755fn allow_list_test_3() {1756	new_test_ext().execute_with(|| {1757		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));17581759		let origin1 = Origin::signed(1);17601761		let data = default_nft_data();1762		create_test_item(collection_id, &data.into());17631764		assert_ok!(TemplateModule::set_public_access_mode(1765			origin1.clone(),1766			collection_id,1767			AccessMode::AllowList1768		));1769		assert_ok!(TemplateModule::add_to_allow_list(1770			origin1.clone(),1771			collection_id,1772			account(1)1773		));17741775		assert_noop!(1776			TemplateModule::transfer(origin1, account(3), collection_id, TokenId(1), 1)1777				.map_err(|e| e.error),1778			CommonError::<Test>::AddressNotInAllowlist1779		);1780	});1781}17821783#[test]1784fn allow_list_test_4() {1785	new_test_ext().execute_with(|| {1786		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));17871788		let origin1 = Origin::signed(1);17891790		let data = default_nft_data();1791		create_test_item(collection_id, &data.into());17921793		assert_ok!(TemplateModule::set_public_access_mode(1794			origin1.clone(),1795			collection_id,1796			AccessMode::AllowList1797		));1798		assert_ok!(TemplateModule::add_to_allow_list(1799			origin1.clone(),1800			collection_id,1801			account(1)1802		));1803		assert_ok!(TemplateModule::add_to_allow_list(1804			origin1.clone(),1805			collection_id,1806			account(2)1807		));18081809		// do approve1810		assert_ok!(TemplateModule::approve(1811			origin1.clone(),1812			account(1),1813			collection_id,1814			TokenId(1),1815			11816		));1817		assert_eq!(1818			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1819			account(1)1820		);18211822		assert_ok!(TemplateModule::remove_from_allow_list(1823			origin1.clone(),1824			collection_id,1825			account(2)1826		));18271828		assert_noop!(1829			TemplateModule::transfer_from(1830				origin1,1831				account(1),1832				account(3),1833				collection_id,1834				TokenId(1),1835				11836			)1837			.map_err(|e| e.error),1838			CommonError::<Test>::AddressNotInAllowlist1839		);1840	});1841}18421843// If Public Access mode is set to AllowList, tokens can’t be destroyed by a non-allowlisted address (even if it owned them before enabling AllowList mode)1844#[test]1845fn allow_list_test_5() {1846	new_test_ext().execute_with(|| {1847		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));18481849		let origin1 = Origin::signed(1);18501851		let data = default_nft_data();1852		create_test_item(collection_id, &data.into());18531854		assert_ok!(TemplateModule::set_public_access_mode(1855			origin1.clone(),1856			collection_id,1857			AccessMode::AllowList1858		));1859		assert_noop!(1860			TemplateModule::burn_item(origin1.clone(), CollectionId(1), TokenId(1), 1)1861				.map_err(|e| e.error),1862			CommonError::<Test>::AddressNotInAllowlist1863		);1864	});1865}18661867// If Public Access mode is set to AllowList, token transfers can’t be Approved by a non-allowlisted address (see Approve method).1868#[test]1869fn allow_list_test_6() {1870	new_test_ext().execute_with(|| {1871		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));18721873		let origin1 = Origin::signed(1);18741875		let data = default_nft_data();1876		create_test_item(collection_id, &data.into());18771878		assert_ok!(TemplateModule::set_public_access_mode(1879			origin1.clone(),1880			collection_id,1881			AccessMode::AllowList1882		));18831884		// do approve1885		assert_noop!(1886			TemplateModule::approve(origin1, account(1), CollectionId(1), TokenId(1), 1)1887				.map_err(|e| e.error),1888			CommonError::<Test>::AddressNotInAllowlist1889		);1890	});1891}18921893// If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transfer or transferFrom (2 tests) and1894//          tokens can be transferred from a allowlisted address with transfer or transferFrom (2 tests)1895#[test]1896fn allow_list_test_7() {1897	new_test_ext().execute_with(|| {1898		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));18991900		let data = default_nft_data();1901		create_test_item(collection_id, &data.into());19021903		let origin1 = Origin::signed(1);19041905		assert_ok!(TemplateModule::set_public_access_mode(1906			origin1.clone(),1907			collection_id,1908			AccessMode::AllowList1909		));1910		assert_ok!(TemplateModule::add_to_allow_list(1911			origin1.clone(),1912			collection_id,1913			account(1)1914		));1915		assert_ok!(TemplateModule::add_to_allow_list(1916			origin1.clone(),1917			collection_id,1918			account(2)1919		));19201921		assert_ok!(TemplateModule::transfer(1922			origin1,1923			account(2),1924			CollectionId(1),1925			TokenId(1),1926			11927		));1928	});1929}19301931#[test]1932fn allow_list_test_8() {1933	new_test_ext().execute_with(|| {1934		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));19351936		// Create NFT for account 11937		let data = default_nft_data();1938		create_test_item(collection_id, &data.into());19391940		let origin1 = Origin::signed(1);19411942		// Toggle Allow List mode and add accounts 1 and 21943		assert_ok!(TemplateModule::set_public_access_mode(1944			origin1.clone(),1945			collection_id,1946			AccessMode::AllowList1947		));1948		assert_ok!(TemplateModule::add_to_allow_list(1949			origin1.clone(),1950			collection_id,1951			account(1)1952		));1953		assert_ok!(TemplateModule::add_to_allow_list(1954			origin1.clone(),1955			collection_id,1956			account(2)1957		));19581959		// Sself-approve account 1 for NFT 11960		assert_ok!(TemplateModule::approve(1961			origin1.clone(),1962			account(1),1963			CollectionId(1),1964			TokenId(1),1965			11966		));1967		assert_eq!(1968			<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(),1969			account(1)1970		);19711972		// Transfer from 1 to 21973		assert_ok!(TemplateModule::transfer_from(1974			origin1,1975			account(1),1976			account(2),1977			CollectionId(1),1978			TokenId(1),1979			11980		));1981	});1982}19831984// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by owner.1985#[test]1986fn allow_list_test_9() {1987	new_test_ext().execute_with(|| {1988		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));1989		let origin1 = Origin::signed(1);19901991		assert_ok!(TemplateModule::set_public_access_mode(1992			origin1.clone(),1993			collection_id,1994			AccessMode::AllowList1995		));1996		assert_ok!(TemplateModule::set_mint_permission(1997			origin1,1998			collection_id,1999			false2000		));20012002		let data = default_nft_data();2003		create_test_item(collection_id, &data.into());2004	});2005}20062007// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by admin.2008#[test]2009fn allow_list_test_10() {2010	new_test_ext().execute_with(|| {2011		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));20122013		let origin1 = Origin::signed(1);2014		let origin2 = Origin::signed(2);20152016		assert_ok!(TemplateModule::set_public_access_mode(2017			origin1.clone(),2018			collection_id,2019			AccessMode::AllowList2020		));2021		assert_ok!(TemplateModule::set_mint_permission(2022			origin1.clone(),2023			collection_id,2024			false2025		));20262027		assert_ok!(TemplateModule::add_collection_admin(2028			origin1,2029			collection_id,2030			account(2)2031		));20322033		assert_ok!(TemplateModule::create_item(2034			origin2,2035			collection_id,2036			account(2),2037			default_nft_data().into()2038		));2039	});2040}20412042// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and allow listed address.2043#[test]2044fn allow_list_test_11() {2045	new_test_ext().execute_with(|| {2046		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));20472048		let origin1 = Origin::signed(1);2049		let origin2 = Origin::signed(2);20502051		assert_ok!(TemplateModule::set_public_access_mode(2052			origin1.clone(),2053			collection_id,2054			AccessMode::AllowList2055		));2056		assert_ok!(TemplateModule::set_mint_permission(2057			origin1.clone(),2058			collection_id,2059			false2060		));2061		assert_ok!(TemplateModule::add_to_allow_list(2062			origin1,2063			collection_id,2064			account(2)2065		));20662067		assert_noop!(2068			TemplateModule::create_item(2069				origin2,2070				CollectionId(1),2071				account(2),2072				default_nft_data().into()2073			)2074			.map_err(|e| e.error),2075			CommonError::<Test>::PublicMintingNotAllowed2076		);2077	});2078}20792080// If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and non-allow listed address.2081#[test]2082fn allow_list_test_12() {2083	new_test_ext().execute_with(|| {2084		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));20852086		let origin1 = Origin::signed(1);2087		let origin2 = Origin::signed(2);20882089		assert_ok!(TemplateModule::set_public_access_mode(2090			origin1.clone(),2091			collection_id,2092			AccessMode::AllowList2093		));2094		assert_ok!(TemplateModule::set_mint_permission(2095			origin1,2096			collection_id,2097			false2098		));20992100		assert_noop!(2101			TemplateModule::create_item(2102				origin2,2103				CollectionId(1),2104				account(2),2105				default_nft_data().into()2106			)2107			.map_err(|e| e.error),2108			CommonError::<Test>::PublicMintingNotAllowed2109		);2110	});2111}21122113// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by owner.2114#[test]2115fn allow_list_test_13() {2116	new_test_ext().execute_with(|| {2117		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));21182119		let origin1 = Origin::signed(1);21202121		assert_ok!(TemplateModule::set_public_access_mode(2122			origin1.clone(),2123			collection_id,2124			AccessMode::AllowList2125		));2126		assert_ok!(TemplateModule::set_mint_permission(2127			origin1,2128			collection_id,2129			true2130		));21312132		let data = default_nft_data();2133		create_test_item(collection_id, &data.into());2134	});2135}21362137// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by admin.2138#[test]2139fn allow_list_test_14() {2140	new_test_ext().execute_with(|| {2141		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));21422143		let origin1 = Origin::signed(1);2144		let origin2 = Origin::signed(2);21452146		assert_ok!(TemplateModule::set_public_access_mode(2147			origin1.clone(),2148			collection_id,2149			AccessMode::AllowList2150		));2151		assert_ok!(TemplateModule::set_mint_permission(2152			origin1.clone(),2153			collection_id,2154			true2155		));21562157		assert_ok!(TemplateModule::add_collection_admin(2158			origin1,2159			collection_id,2160			account(2)2161		));21622163		assert_ok!(TemplateModule::create_item(2164			origin2,2165			collection_id,2166			account(2),2167			default_nft_data().into()2168		));2169	});2170}21712172// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens cannot be created by non-privileged and non-allow listed address.2173#[test]2174fn allow_list_test_15() {2175	new_test_ext().execute_with(|| {2176		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));21772178		let origin1 = Origin::signed(1);2179		let origin2 = Origin::signed(2);21802181		assert_ok!(TemplateModule::set_public_access_mode(2182			origin1.clone(),2183			collection_id,2184			AccessMode::AllowList2185		));2186		assert_ok!(TemplateModule::set_mint_permission(2187			origin1,2188			collection_id,2189			true2190		));21912192		assert_noop!(2193			TemplateModule::create_item(2194				origin2,2195				collection_id,2196				account(2),2197				default_nft_data().into()2198			)2199			.map_err(|e| e.error),2200			CommonError::<Test>::AddressNotInAllowlist2201		);2202	});2203}22042205// If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by non-privileged and allow listed address.2206#[test]2207fn allow_list_test_16() {2208	new_test_ext().execute_with(|| {2209		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));22102211		let origin1 = Origin::signed(1);2212		let origin2 = Origin::signed(2);22132214		assert_ok!(TemplateModule::set_public_access_mode(2215			origin1.clone(),2216			collection_id,2217			AccessMode::AllowList2218		));2219		assert_ok!(TemplateModule::set_mint_permission(2220			origin1.clone(),2221			collection_id,2222			true2223		));2224		assert_ok!(TemplateModule::add_to_allow_list(2225			origin1,2226			collection_id,2227			account(2)2228		));22292230		assert_ok!(TemplateModule::create_item(2231			origin2,2232			collection_id,2233			account(2),2234			default_nft_data().into()2235		));2236	});2237}22382239// Total number of collections. Positive test2240#[test]2241fn total_number_collections_bound() {2242	new_test_ext().execute_with(|| {2243		create_test_collection(&CollectionMode::NFT, CollectionId(1));2244	});2245}22462247#[test]2248fn create_max_collections() {2249	new_test_ext().execute_with(|| {2250		for i in 1..COLLECTION_NUMBER_LIMIT {2251			create_test_collection(&CollectionMode::NFT, CollectionId(i));2252		}2253	});2254}22552256// Total number of collections. Negative test2257#[test]2258fn total_number_collections_bound_neg() {2259	new_test_ext().execute_with(|| {2260		let origin1 = Origin::signed(1);22612262		for i in 1..COLLECTION_NUMBER_LIMIT {2263			create_test_collection(&CollectionMode::NFT, CollectionId(i));2264		}22652266		let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();2267		let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();2268		let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();22692270		// 11-th collection in chain. Expects error2271		assert_noop!(2272			TemplateModule::create_collection(2273				origin1,2274				col_name1,2275				col_desc1,2276				token_prefix1,2277				CollectionMode::NFT2278			),2279			CommonError::<Test>::TotalCollectionsLimitExceeded2280		);2281	});2282}22832284// Owned tokens by a single address. Positive test2285#[test]2286fn owned_tokens_bound() {2287	new_test_ext().execute_with(|| {2288		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));22892290		let data = default_nft_data();2291		create_test_item(collection_id, &data.clone().into());2292		create_test_item(collection_id, &data.into());2293	});2294}22952296// Owned tokens by a single address. Negotive test2297#[test]2298fn owned_tokens_bound_neg() {2299	new_test_ext().execute_with(|| {2300		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23012302		let origin1 = Origin::signed(1);23032304		for _ in 1..=MAX_TOKEN_OWNERSHIP {2305			let data = default_nft_data();2306			create_test_item(collection_id, &data.clone().into());2307		}23082309		let data = default_nft_data();2310		assert_noop!(2311			TemplateModule::create_item(origin1, CollectionId(1), account(1), data.into())2312				.map_err(|e| e.error),2313			CommonError::<Test>::AccountTokenLimitExceeded2314		);2315	});2316}23172318// Number of collection admins. Positive test2319#[test]2320fn collection_admins_bound() {2321	new_test_ext().execute_with(|| {2322		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23232324		let origin1 = Origin::signed(1);23252326		assert_ok!(TemplateModule::add_collection_admin(2327			origin1.clone(),2328			collection_id,2329			account(2)2330		));2331		assert_ok!(TemplateModule::add_collection_admin(2332			origin1,2333			collection_id,2334			account(3)2335		));2336	});2337}23382339// Number of collection admins. Negotive test2340#[test]2341fn collection_admins_bound_neg() {2342	new_test_ext().execute_with(|| {2343		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23442345		let origin1 = Origin::signed(1);23462347		for i in 0..COLLECTION_ADMINS_LIMIT {2348			assert_ok!(TemplateModule::add_collection_admin(2349				origin1.clone(),2350				collection_id,2351				account((2 + i).into())2352			));2353		}2354		assert_noop!(2355			TemplateModule::add_collection_admin(2356				origin1,2357				collection_id,2358				account((3 + COLLECTION_ADMINS_LIMIT).into())2359			),2360			CommonError::<Test>::CollectionAdminCountExceeded2361		);2362	});2363}2364// #endregion23652366#[test]2367fn set_const_on_chain_schema() {2368	new_test_ext().execute_with(|| {2369		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23702371		let origin1 = Origin::signed(1);2372		assert_ok!(TemplateModule::set_const_on_chain_schema(2373			origin1,2374			collection_id,2375			b"test const on chain schema".to_vec()2376		));23772378		assert_eq!(2379			<pallet_common::CollectionById<Test>>::get(collection_id)2380				.unwrap()2381				.const_on_chain_schema,2382			b"test const on chain schema".to_vec()2383		);2384		assert_eq!(2385			<pallet_common::CollectionById<Test>>::get(collection_id)2386				.unwrap()2387				.variable_on_chain_schema,2388			b"".to_vec()2389		);2390	});2391}23922393#[test]2394fn set_variable_on_chain_schema() {2395	new_test_ext().execute_with(|| {2396		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));23972398		let origin1 = Origin::signed(1);2399		assert_ok!(TemplateModule::set_variable_on_chain_schema(2400			origin1,2401			collection_id,2402			b"test variable on chain schema".to_vec()2403		));24042405		assert_eq!(2406			<pallet_common::CollectionById<Test>>::get(collection_id)2407				.unwrap()2408				.const_on_chain_schema,2409			b"".to_vec()2410		);2411		assert_eq!(2412			<pallet_common::CollectionById<Test>>::get(collection_id)2413				.unwrap()2414				.variable_on_chain_schema,2415			b"test variable on chain schema".to_vec()2416		);2417	});2418}24192420#[test]2421fn set_variable_meta_data_on_nft_token_stores_variable_meta_data() {2422	new_test_ext().execute_with(|| {2423		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));24242425		let origin1 = Origin::signed(1);24262427		let data = default_nft_data();2428		create_test_item(CollectionId(1), &data.into());24292430		let variable_data = b"test data".to_vec();2431		assert_ok!(TemplateModule::set_variable_meta_data(2432			origin1,2433			collection_id,2434			TokenId(1),2435			variable_data.clone()2436		));24372438		assert_eq!(2439			<pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))2440				.unwrap()2441				.variable_data,2442			variable_data2443		);2444	});2445}24462447#[test]2448fn set_variable_meta_data_on_re_fungible_token_stores_variable_meta_data() {2449	new_test_ext().execute_with(|| {2450		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));24512452		let origin1 = Origin::signed(1);24532454		let data = default_re_fungible_data();2455		create_test_item(collection_id, &data.into());24562457		let variable_data = b"test data".to_vec();2458		assert_ok!(TemplateModule::set_variable_meta_data(2459			origin1,2460			collection_id,2461			TokenId(1),2462			variable_data.clone()2463		));24642465		assert_eq!(2466			<pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1))).variable_data,2467			variable_data2468		);2469	});2470}24712472#[test]2473fn set_variable_meta_data_on_fungible_token_fails() {2474	new_test_ext().execute_with(|| {2475		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));24762477		let origin1 = Origin::signed(1);24782479		let data = default_fungible_data();2480		create_test_item(collection_id, &data.into());24812482		let variable_data = b"test data".to_vec();2483		assert_noop!(2484			TemplateModule::set_variable_meta_data(2485				origin1,2486				collection_id,2487				TokenId(0),2488				variable_data2489			)2490			.map_err(|e| e.error),2491			<pallet_fungible::Error<Test>>::FungibleItemsDontHaveData2492		);2493	});2494}24952496#[test]2497fn set_variable_meta_data_on_nft_token_fails_for_big_data() {2498	new_test_ext().execute_with(|| {2499		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));25002501		let origin1 = Origin::signed(1);25022503		let data = default_nft_data();2504		create_test_item(collection_id, &data.into());25052506		let variable_data = b"test set_variable_meta_data method, bigger than limits.".to_vec();2507		assert_noop!(2508			TemplateModule::set_variable_meta_data(2509				origin1,2510				collection_id,2511				TokenId(1),2512				variable_data2513			)2514			.map_err(|e| e.error),2515			CommonError::<Test>::TokenVariableDataLimitExceeded2516		);2517	});2518}25192520#[test]2521fn set_variable_meta_data_on_re_fungible_token_fails_for_big_data() {2522	new_test_ext().execute_with(|| {2523		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));25242525		let origin1 = Origin::signed(1);25262527		let data = default_re_fungible_data();2528		create_test_item(collection_id, &data.into());25292530		let variable_data = b"test set_variable_meta_data method, bigger than limits.".to_vec();2531		assert_noop!(2532			TemplateModule::set_variable_meta_data(2533				origin1,2534				collection_id,2535				TokenId(1),2536				variable_data2537			)2538			.map_err(|e| e.error),2539			CommonError::<Test>::TokenVariableDataLimitExceeded2540		);2541	});2542}25432544#[test]2545fn set_variable_meta_data_on_nft_with_item_owner_permission_flag() {2546	new_test_ext().execute_with(|| {2547		//default_limits();25482549		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));25502551		let origin1 = Origin::signed(1);25522553		let data = default_nft_data();2554		create_test_item(collection_id, &data.into());25552556		assert_ok!(TemplateModule::set_meta_update_permission_flag(2557			origin1.clone(),2558			collection_id,2559			MetaUpdatePermission::ItemOwner,2560		));25612562		let variable_data = b"ten chars.".to_vec();2563		assert_ok!(TemplateModule::set_variable_meta_data(2564			origin1,2565			collection_id,2566			TokenId(1),2567			variable_data.clone()2568		));25692570		assert_eq!(2571			<pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1)))2572				.unwrap()2573				.variable_data,2574			variable_data2575		);2576	});2577}25782579#[test]2580fn set_variable_meta_data_on_nft_with_item_owner_permission_flag_neg() {2581	new_test_ext().execute_with(|| {2582		let collection_id =2583			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));25842585		let origin1 = Origin::signed(1);25862587		assert_ok!(TemplateModule::set_mint_permission(2588			origin1.clone(),2589			collection_id,2590			true2591		));2592		assert_ok!(TemplateModule::add_to_allow_list(2593			origin1.clone(),2594			collection_id,2595			account(1)2596		));25972598		let data = default_nft_data();2599		create_test_item(collection_id, &data.into());26002601		assert_ok!(TemplateModule::set_meta_update_permission_flag(2602			origin1.clone(),2603			collection_id,2604			MetaUpdatePermission::ItemOwner,2605		));26062607		let variable_data = b"1234567890123".to_vec();2608		assert_noop!(2609			TemplateModule::set_variable_meta_data(2610				origin1,2611				collection_id,2612				TokenId(1),2613				variable_data.clone()2614			)2615			.map_err(|e| e.error),2616			CommonError::<Test>::TokenVariableDataLimitExceeded2617		);2618	})2619}26202621#[test]2622fn collection_transfer_flag_works() {2623	new_test_ext().execute_with(|| {2624		let origin1 = Origin::signed(1);26252626		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));2627		assert_ok!(TemplateModule::set_transfers_enabled_flag(2628			origin1,2629			collection_id,2630			true2631		));26322633		let data = default_nft_data();2634		create_test_item(collection_id, &data.into());2635		assert_eq!(2636			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2637			12638		);2639		assert_eq!(2640			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2641			true2642		);26432644		let origin1 = Origin::signed(1);26452646		// default scenario2647		assert_ok!(TemplateModule::transfer(2648			origin1,2649			account(2),2650			collection_id,2651			TokenId(1),2652			12653		));2654		assert_eq!(2655			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2656			false2657		);2658		assert_eq!(2659			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),2660			true2661		);2662		assert_eq!(2663			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2664			02665		);2666		assert_eq!(2667			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),2668			12669		);2670	});2671}26722673#[test]2674fn set_variable_meta_data_on_nft_with_admin_flag() {2675	new_test_ext().execute_with(|| {2676		// default_limits();26772678		let collection_id =2679			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));26802681		let origin1 = Origin::signed(1);2682		let origin2 = Origin::signed(2);26832684		assert_ok!(TemplateModule::set_mint_permission(2685			origin2.clone(),2686			collection_id,2687			true2688		));2689		assert_ok!(TemplateModule::add_to_allow_list(2690			origin2.clone(),2691			collection_id,2692			account(1)2693		));26942695		assert_ok!(TemplateModule::add_collection_admin(2696			origin2.clone(),2697			collection_id,2698			account(1)2699		));27002701		let data = default_nft_data();2702		create_test_item(collection_id, &data.into());27032704		assert_ok!(TemplateModule::set_meta_update_permission_flag(2705			origin2.clone(),2706			collection_id,2707			MetaUpdatePermission::Admin,2708		));27092710		let variable_data = b"test.".to_vec();2711		assert_ok!(TemplateModule::set_variable_meta_data(2712			origin1,2713			collection_id,2714			TokenId(1),2715			variable_data.clone()2716		));27172718		assert_eq!(2719			<pallet_nonfungible::TokenData<Test>>::get((collection_id, 1))2720				.unwrap()2721				.variable_data,2722			variable_data2723		);2724	});2725}27262727#[test]2728fn set_variable_meta_data_on_nft_with_admin_flag_neg() {2729	new_test_ext().execute_with(|| {2730		// default_limits();27312732		let collection_id =2733			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));27342735		let origin1 = Origin::signed(1);2736		let origin2 = Origin::signed(2);27372738		assert_ok!(TemplateModule::set_mint_permission(2739			origin2.clone(),2740			collection_id,2741			true2742		));2743		assert_ok!(TemplateModule::add_to_allow_list(2744			origin2.clone(),2745			collection_id,2746			account(1)2747		));27482749		let data = default_nft_data();2750		create_test_item(collection_id, &data.into());27512752		assert_ok!(TemplateModule::set_meta_update_permission_flag(2753			origin2.clone(),2754			collection_id,2755			MetaUpdatePermission::Admin,2756		));27572758		let variable_data = b"test.".to_vec();2759		assert_noop!(2760			TemplateModule::set_variable_meta_data(2761				origin1,2762				collection_id,2763				TokenId(1),2764				variable_data.clone()2765			)2766			.map_err(|e| e.error),2767			CommonError::<Test>::NoPermission2768		);2769	});2770}27712772#[test]2773fn set_variable_meta_flag_after_freeze() {2774	new_test_ext().execute_with(|| {2775		// default_limits();27762777		let collection_id =2778			create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(1));27792780		let origin2 = Origin::signed(2);27812782		assert_ok!(TemplateModule::set_meta_update_permission_flag(2783			origin2.clone(),2784			collection_id,2785			MetaUpdatePermission::None,2786		));2787		assert_noop!(2788			TemplateModule::set_meta_update_permission_flag(2789				origin2.clone(),2790				collection_id,2791				MetaUpdatePermission::Admin2792			),2793			CommonError::<Test>::MetadataFlagFrozen2794		);2795	});2796}27972798#[test]2799fn set_variable_meta_data_on_nft_with_none_flag_neg() {2800	new_test_ext().execute_with(|| {2801		// default_limits();28022803		let collection_id =2804			create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));2805		let origin1 = Origin::signed(1);28062807		let data = default_nft_data();2808		create_test_item(collection_id, &data.into());28092810		assert_ok!(TemplateModule::set_meta_update_permission_flag(2811			origin1.clone(),2812			collection_id,2813			MetaUpdatePermission::None,2814		));28152816		let variable_data = b"test.".to_vec();2817		assert_noop!(2818			TemplateModule::set_variable_meta_data(2819				origin1.clone(),2820				collection_id,2821				TokenId(1),2822				variable_data.clone()2823			)2824			.map_err(|e| e.error),2825			CommonError::<Test>::NoPermission2826		);2827	});2828}28292830#[test]2831fn collection_transfer_flag_works_neg() {2832	new_test_ext().execute_with(|| {2833		let origin1 = Origin::signed(1);28342835		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));2836		assert_ok!(TemplateModule::set_transfers_enabled_flag(2837			origin1,2838			collection_id,2839			false2840		));28412842		let data = default_nft_data();2843		create_test_item(collection_id, &data.into());2844		assert_eq!(2845			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2846			12847		);2848		assert_eq!(2849			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2850			true2851		);28522853		let origin1 = Origin::signed(1);28542855		// default scenario2856		assert_noop!(2857			TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 1)2858				.map_err(|e| e.error),2859			CommonError::<Test>::TransferNotAllowed2860		);2861		assert_eq!(2862			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))),2863			12864		);2865		assert_eq!(2866			<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))),2867			02868		);2869		assert_eq!(2870			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))),2871			true2872		);2873		assert_eq!(2874			<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))),2875			false2876		);2877	});2878}
modifiedpallets/unique/src/weights.rsdiffbeforeafterboth
--- a/pallets/unique/src/weights.rs
+++ b/pallets/unique/src/weights.rs
@@ -25,6 +25,7 @@
 #![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;
modifiedprimitives/data-structs/Cargo.tomldiffbeforeafterboth
--- a/primitives/data-structs/Cargo.toml
+++ b/primitives/data-structs/Cargo.toml
@@ -2,7 +2,7 @@
 name = "up-data-structs"
 authors = ["Unique Network <support@uniquenetwork.io>"]
 description = "Unique data structs definitions"
-edition = "2018"
+edition = "2021"
 license = 'All Rights Reserved'
 homepage = "https://unique.network"
 repository = 'https://github.com/UniqueNetwork/unique-chain'
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -31,7 +31,7 @@
 pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;
 
 pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {
-	10_000_000
+	100_000
 } else {
 	10
 };
@@ -61,9 +61,9 @@
 pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;
 
 // Schema limits
-pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 1024;
-pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 1024;
-pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 1024;
+pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;
+pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;
+pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 1048576;
 
 pub const MAX_COLLECTION_NAME_LENGTH: usize = 64;
 pub const MAX_COLLECTION_DESCRIPTION_LENGTH: usize = 256;
@@ -331,8 +331,7 @@
 		D: ser::Serializer,
 		V: Serialize,
 	{
-		let vec: &Vec<_> = &value;
-		vec.serialize(serializer)
+		(value as &Vec<_>).serialize(serializer)
 	}
 
 	pub fn deserialize<'de, D, V, S>(deserializer: D) -> Result<BoundedVec<V, S>, D::Error>
modifiedprimitives/evm-mapping/Cargo.tomldiffbeforeafterboth
--- a/primitives/evm-mapping/Cargo.toml
+++ b/primitives/evm-mapping/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "up-evm-mapping"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 sp-core = { default-features = false, git = 'https://github.com/paritytech/substrate.git', branch = 'polkadot-v0.9.12' }
@@ -9,7 +9,4 @@
 
 [features]
 default = ["std"]
-std = [
-	"sp-core/std",
-	"frame-support/std",
-]
+std = ["sp-core/std", "frame-support/std"]
modifiedprimitives/rpc/Cargo.tomldiffbeforeafterboth
--- a/primitives/rpc/Cargo.toml
+++ b/primitives/rpc/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "up-rpc"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 pallet-common = { default-features = false, path = '../../pallets/common' }
modifiedruntime/Cargo.tomldiffbeforeafterboth
--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -23,7 +23,9 @@
     'frame-support/runtime-benchmarks',
     'frame-system-benchmarking',
     'frame-system/runtime-benchmarks',
+    'pallet-ethereum/runtime-benchmarks',
     'pallet-evm-migration/runtime-benchmarks',
+    'pallet-evm-coder-substrate/runtime-benchmarks',
     'pallet-balances/runtime-benchmarks',
     'pallet-timestamp/runtime-benchmarks',
     'pallet-common/runtime-benchmarks',
@@ -391,10 +393,10 @@
 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.git", branch = "unique-polkadot-v0.9.12" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
-fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
+fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier.git", branch = "unique-polkadot-v0.9.12-weights" }
 
 ################################################################################
 # Build Dependencies
modifiedruntime/src/lib.rsdiffbeforeafterboth
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -65,7 +65,7 @@
 };
 use smallvec::smallvec;
 use codec::{Encode, Decode};
-use pallet_evm::{Account as EVMAccount, FeeCalculator, OnMethodCall};
+use pallet_evm::{Account as EVMAccount, FeeCalculator, GasWeightMapping, OnMethodCall};
 use fp_rpc::TransactionStatus;
 use sp_core::crypto::Public;
 use sp_runtime::{
@@ -242,14 +242,42 @@
 pub struct FixedFee;
 impl FeeCalculator for FixedFee {
 	fn min_gas_price() -> U256 {
-		1.into()
+		// Targeting 0.15 UNQ per transfer
+		1_024_947_215_000u64.into()
+	}
+}
+
+// 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 / <Runtime as frame_system::Config>::DbWeight::get().write;
+	pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;
+	pub const WeightPerGas: u64 = WEIGHT_PER_SECOND / GasPerSecond::get();
+}
+
+/// Limiting EVM execution to 50% of block for substrate users and management tasks
+/// EVM transaction consumes more weight than substrate's, so we can't rely on them being
+/// 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());
+}
+
+pub enum FixedGasWeightMapping {}
+impl GasWeightMapping for FixedGasWeightMapping {
+	fn gas_to_weight(gas: u64) -> Weight {
+		gas.saturating_mul(WeightPerGas::get())
 	}
+	fn weight_to_gas(weight: Weight) -> u64 {
+		weight / WeightPerGas::get()
+	}
 }
 
 impl pallet_evm::Config for Runtime {
 	type BlockGasLimit = BlockGasLimit;
 	type FeeCalculator = FixedFee;
-	type GasWeightMapping = ();
+	type GasWeightMapping = FixedGasWeightMapping;
 	type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
 	type CallOrigin = EnsureAddressTruncated;
 	type WithdrawOrigin = EnsureAddressTruncated;
@@ -286,16 +314,11 @@
 		}
 		None
 	}
-}
-
-parameter_types! {
-	pub BlockGasLimit: U256 = U256::from(u32::max_value());
 }
 
 impl pallet_ethereum::Config for Runtime {
 	type Event = Event;
 	type StateRoot = pallet_ethereum::IntermediateStateRoot;
-	type EvmSubmitLog = pallet_evm::Pallet<Self>;
 }
 
 impl pallet_randomness_collective_flip::Config for Runtime {}
@@ -380,7 +403,7 @@
 	type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;
 }
 
-pub const MICROUNIQUE: Balance = 1_000_000_000;
+pub const MICROUNIQUE: Balance = 1_000_000_000_000;
 pub const MILLIUNIQUE: Balance = 1_000 * MICROUNIQUE;
 pub const CENTIUNIQUE: Balance = 10 * MILLIUNIQUE;
 pub const UNIQUE: Balance = 100 * CENTIUNIQUE;
@@ -457,7 +480,8 @@
 
 	fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
 		smallvec!(WeightToFeeCoefficient {
-			coeff_integer: 146_700u32.into(), // Targeting 0.1 Unique per NFT transfer
+			// Targeting 0.1 Unique per NFT transfer
+			coeff_integer: 142_688_000u32.into(),
 			coeff_frac: Perbill::zero(),
 			negative: false,
 			degree: 1,
@@ -686,6 +710,7 @@
 
 impl pallet_evm_coder_substrate::Config for Runtime {
 	type EthereumTransactionSender = pallet_ethereum::Pallet<Self>;
+	type GasWeightMapping = FixedGasWeightMapping;
 }
 
 impl pallet_xcm::Config for Runtime {
@@ -756,6 +781,7 @@
 }
 
 impl pallet_unique::Config for Runtime {
+	type Event = Event;
 	type WeightInfo = pallet_unique::weights::SubstrateWeight<Self>;
 }
 
@@ -856,7 +882,7 @@
 
 		// Unique Pallets
 		Inflation: pallet_inflation::{Pallet, Call, Storage} = 60,
-		Unique: pallet_unique::{Pallet, Call, Storage} = 61,
+		Unique: pallet_unique::{Pallet, Call, Storage, Event<T>} = 61,
 		// Scheduler: pallet_unq_scheduler::{Pallet, Call, Storage, Event<T>} = 62,
 		// free = 63
 		Charging: pallet_charge_transaction::{Pallet, Call, Storage } = 64,
@@ -1151,6 +1177,7 @@
 			EVM::account_storages(address, H256::from_slice(&tmp[..]))
 		}
 
+		#[allow(clippy::redundant_closure)]
 		fn call(
 			from: H160,
 			to: H160,
@@ -1181,6 +1208,7 @@
 			).map_err(|err| err.into())
 		}
 
+		#[allow(clippy::redundant_closure)]
 		fn create(
 			from: H160,
 			data: Vec<u8>,
@@ -1342,6 +1370,7 @@
 			list_benchmark!(list, extra, pallet_fungible, Fungible);
 			list_benchmark!(list, extra, pallet_refungible, Refungible);
 			list_benchmark!(list, extra, pallet_nonfungible, Nonfungible);
+			// list_benchmark!(list, extra, pallet_evm_coder_substrate, EvmCoderSubstrate);
 
 			let storage_info = AllPalletsWithSystem::storage_info();
 
@@ -1375,6 +1404,7 @@
 			add_benchmark!(params, batches, pallet_fungible, Fungible);
 			add_benchmark!(params, batches, pallet_refungible, Refungible);
 			add_benchmark!(params, batches, pallet_nonfungible, Nonfungible);
+			// add_benchmark!(params, batches, pallet_evm_coder_substrate, EvmCoderSubstrate);
 
 			if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
 			Ok(batches)
modifiedsmart_contracs/transfer/Cargo.tomldiffbeforeafterboth
--- a/smart_contracs/transfer/Cargo.toml
+++ b/smart_contracs/transfer/Cargo.toml
@@ -2,7 +2,7 @@
 name = "nft_transfer"
 version = "0.1.0"
 authors = ["[Greg Zaitsev] <[your_email]>"]
-edition = "2018"
+edition = "2021"
 
 [workspace]
 
modifiedtests/README.mddiffbeforeafterboth
--- a/tests/README.md
+++ b/tests/README.md
@@ -8,7 +8,7 @@
 git checkout release-v0.9.12
 ```
 
-2. Build with nightly-2021-06-28
+2. Build with nightly-2021-11-11
 ```bash
 cargo build --release
 ```
@@ -28,4 +28,3 @@
 1. Run `yarn install`.
 2. Optional step - configure tests with env variables or by editing [configuration file](src/config.ts).
 3. Run `yarn test`.
-
modifiedtests/flipper-src/Cargo.tomldiffbeforeafterboth
--- a/tests/flipper-src/Cargo.toml
+++ b/tests/flipper-src/Cargo.toml
@@ -2,7 +2,7 @@
 name = "flipper"
 version = "3.0.0-rc1"
 authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 ink_primitives = { version = "3.0.0-rc1", git = "https://github.com/paritytech/ink", tag = "v3.0.0-rc1", default-features = false }
@@ -32,4 +32,4 @@
     "scale-info",
     "scale-info/std",
 ]
-ink-as-dependency = []
\ No newline at end of file
+ink-as-dependency = []
modifiedtests/ink-types-node-runtime/Cargo.tomldiffbeforeafterboth
--- a/tests/ink-types-node-runtime/Cargo.toml
+++ b/tests/ink-types-node-runtime/Cargo.toml
@@ -2,7 +2,7 @@
 name = "ink_types_node_runtime"
 version = "0.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2018"
+edition = "2021"
 
 license = "GPL-3.0"
 readme = "README.md"
modifiedtests/ink-types-node-runtime/examples/calls/.ink/abi_gen/Cargo.tomldiffbeforeafterboth
--- a/tests/ink-types-node-runtime/examples/calls/.ink/abi_gen/Cargo.toml
+++ b/tests/ink-types-node-runtime/examples/calls/.ink/abi_gen/Cargo.toml
@@ -2,7 +2,7 @@
 name = "abi-gen"
 version = "0.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2018"
+edition = "2021"
 publish = false
 
 [[bin]]
modifiedtests/ink-types-node-runtime/examples/calls/Cargo.tomldiffbeforeafterboth
--- a/tests/ink-types-node-runtime/examples/calls/Cargo.toml
+++ b/tests/ink-types-node-runtime/examples/calls/Cargo.toml
@@ -2,7 +2,7 @@
 name = "calls"
 version = "0.1.0"
 authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 ink_abi = { version = "2", git = "https://github.com/paritytech/ink", tag = "latest-v2", package = "ink_abi", default-features = false, features = ["derive"], optional = true }
modifiedtests/loadtester-src/Cargo.tomldiffbeforeafterboth
--- a/tests/loadtester-src/Cargo.toml
+++ b/tests/loadtester-src/Cargo.toml
@@ -2,7 +2,7 @@
 name = "loadtester"
 version = "0.1.0"
 authors = ["[your_name] <[your_email]>"]
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 ink_primitives = { version = "3.0.0-rc2", default-features = false }
modifiedtests/src/confirmSponsorship.test.tsdiffbeforeafterboth
--- a/tests/src/confirmSponsorship.test.ts
+++ b/tests/src/confirmSponsorship.test.ts
@@ -21,6 +21,7 @@
   normalizeAccountId,
   addCollectionAdminExpectSuccess,
   getCreatedCollectionCount,
+  UNIQUE,
 } from './util/helpers';
 import {Keyring} from '@polkadot/api';
 import {IKeyringPair} from '@polkadot/types/types';
@@ -198,7 +199,7 @@
       const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();
 
       // Try again after Zero gets some balance - now it should succeed
-      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1e15);
+      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);
       await submitTransactionAsync(alice, balancetx);
       const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);
       const result2 = getGenericResult(events2);
@@ -232,7 +233,7 @@
       const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();
 
       // Try again after Zero gets some balance - now it should succeed
-      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1e15);
+      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);
       await submitTransactionAsync(alice, balancetx);
       const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);
       const result2 = getGenericResult(events2);
@@ -268,7 +269,7 @@
       expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore);
 
       // Try again after Zero gets some balance - now it should succeed
-      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1e15);
+      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);
       await submitTransactionAsync(alice, balancetx);
       const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice);
       const result2 = getGenericResult(events2);
@@ -307,7 +308,7 @@
       const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt();
 
       // Try again after Zero gets some balance - now it should succeed
-      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1e15);
+      const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);
       await submitTransactionAsync(alice, balancetx);
       await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address);
 
modifiedtests/src/creditFeesToTreasury.test.tsdiffbeforeafterboth
--- a/tests/src/creditFeesToTreasury.test.ts
+++ b/tests/src/creditFeesToTreasury.test.ts
@@ -154,8 +154,8 @@
       const aliceBalanceAfter: bigint = (await api.query.system.account(alicesPublicKey)).data.free.toBigInt();
       const fee = aliceBalanceBefore - aliceBalanceAfter;
 
-      expect(fee / 10n ** 15n < BigInt(Math.ceil(saneMaximumFee + createCollectionDeposit))).to.be.true;
-      expect(fee / 10n ** 15n < BigInt(Math.ceil(saneMinimumFee  + createCollectionDeposit))).to.be.true;
+      expect(fee / UNIQUE < BigInt(Math.ceil(saneMaximumFee + createCollectionDeposit))).to.be.true;
+      expect(fee / UNIQUE < BigInt(Math.ceil(saneMinimumFee  + createCollectionDeposit))).to.be.true;
     });
   });
 
@@ -170,11 +170,13 @@
       const aliceBalanceBefore: bigint = (await api.query.system.account(alicesPublicKey)).data.free.toBigInt();
       await transferExpectSuccess(collectionId, tokenId, alice, bob, 1, 'NFT');
       const aliceBalanceAfter: bigint = (await api.query.system.account(alicesPublicKey)).data.free.toBigInt();
+
       const fee = Number(aliceBalanceBefore - aliceBalanceAfter) / Number(UNIQUE);
-
       const expectedTransferFee = 0.1;
+      // fee drifts because of NextFeeMultiplier
       const tolerance = 0.001;
-      expect(Number(fee) / Number(UNIQUE) - expectedTransferFee).to.be.lessThan(tolerance);
+
+      expect(Math.abs(fee - expectedTransferFee)).to.be.lessThan(tolerance);
     });
   });
 
modifiedtests/src/eth/api/ContractHelpers.soldiffbeforeafterboth
--- a/tests/src/eth/api/ContractHelpers.sol
+++ b/tests/src/eth/api/ContractHelpers.sol
@@ -12,6 +12,7 @@
 	function supportsInterface(bytes4 interfaceID) external view returns (bool);
 }
 
+// Selector: 31acb1fe
 interface ContractHelpers is Dummy, ERC165 {
 	// Selector: contractOwner(address) 5152b14c
 	function contractOwner(address contractAddress)
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -22,6 +22,7 @@
 	);
 }
 
+// Selector: 942e8b22
 interface ERC20 is Dummy, ERC165, ERC20Events {
 	// Selector: name() 06fdde03
 	function name() external view returns (string memory);
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -42,6 +42,13 @@
 	event MintingFinished();
 }
 
+// Selector: 42966c68
+interface ERC721Burnable is Dummy, ERC165 {
+	// Selector: burn(uint256) 42966c68
+	function burn(uint256 tokenId) external;
+}
+
+// Selector: 58800161
 interface ERC721 is Dummy, ERC165, ERC721Events {
 	// Selector: balanceOf(address) 70a08231
 	function balanceOf(address owner) external view returns (uint256);
@@ -49,6 +56,8 @@
 	// Selector: ownerOf(uint256) 6352211e
 	function ownerOf(uint256 tokenId) external view returns (address);
 
+	// Not implemented
+	//
 	// Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672
 	function safeTransferFromWithData(
 		address from,
@@ -57,6 +66,8 @@
 		bytes memory data
 	) external;
 
+	// Not implemented
+	//
 	// Selector: safeTransferFrom(address,address,uint256) 42842e0e
 	function safeTransferFrom(
 		address from,
@@ -74,12 +85,18 @@
 	// Selector: approve(address,uint256) 095ea7b3
 	function approve(address approved, uint256 tokenId) external;
 
+	// Not implemented
+	//
 	// Selector: setApprovalForAll(address,bool) a22cb465
 	function setApprovalForAll(address operator, bool approved) external;
 
+	// Not implemented
+	//
 	// Selector: getApproved(uint256) 081812fc
 	function getApproved(uint256 tokenId) external view returns (address);
 
+	// Not implemented
+	//
 	// Selector: isApprovedForAll(address,address) e985e9c5
 	function isApprovedForAll(address owner, address operator)
 		external
@@ -87,25 +104,7 @@
 		returns (address);
 }
 
-interface ERC721Burnable is Dummy, ERC165 {
-	// Selector: burn(uint256) 42966c68
-	function burn(uint256 tokenId) external;
-}
-
-interface ERC721Enumerable is Dummy, ERC165 {
-	// Selector: tokenByIndex(uint256) 4f6ccce7
-	function tokenByIndex(uint256 index) external view returns (uint256);
-
-	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
-	function tokenOfOwnerByIndex(address owner, uint256 index)
-		external
-		view
-		returns (uint256);
-
-	// Selector: totalSupply() 18160ddd
-	function totalSupply() external view returns (uint256);
-}
-
+// Selector: 5b5e139f
 interface ERC721Metadata is Dummy, ERC165 {
 	// Selector: name() 06fdde03
 	function name() external view returns (string memory);
@@ -113,17 +112,26 @@
 	// Selector: symbol() 95d89b41
 	function symbol() external view returns (string memory);
 
+	// Returns token's const_metadata
+	//
 	// Selector: tokenURI(uint256) c87b56dd
 	function tokenURI(uint256 tokenId) external view returns (string memory);
 }
 
+// Selector: 68ccfe89
 interface ERC721Mintable is Dummy, ERC165, ERC721MintableEvents {
 	// Selector: mintingFinished() 05d2035b
 	function mintingFinished() external view returns (bool);
 
+	// `token_id` should be obtained with `next_token_id` method,
+	// unlike standard, you can't specify it manually
+	//
 	// Selector: mint(address,uint256) 40c10f19
 	function mint(address to, uint256 tokenId) external returns (bool);
 
+	// `token_id` should be obtained with `next_token_id` method,
+	// unlike standard, you can't specify it manually
+	//
 	// Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f
 	function mintWithTokenURI(
 		address to,
@@ -131,10 +139,30 @@
 		string memory tokenUri
 	) external returns (bool);
 
+	// Not implemented
+	//
 	// Selector: finishMinting() 7d64bcb4
 	function finishMinting() external returns (bool);
 }
 
+// Selector: 780e9d63
+interface ERC721Enumerable is Dummy, ERC165 {
+	// Selector: tokenByIndex(uint256) 4f6ccce7
+	function tokenByIndex(uint256 index) external view returns (uint256);
+
+	// Not implemented
+	//
+	// Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59
+	function tokenOfOwnerByIndex(address owner, uint256 index)
+		external
+		view
+		returns (uint256);
+
+	// Selector: totalSupply() 18160ddd
+	function totalSupply() external view returns (uint256);
+}
+
+// Selector: e562194d
 interface ERC721UniqueExtensions is Dummy, ERC165 {
 	// Selector: transfer(address,uint256) a9059cbb
 	function transfer(address to, uint256 tokenId) external;
modifiedtests/src/eth/base.test.tsdiffbeforeafterboth
--- a/tests/src/eth/base.test.ts
+++ b/tests/src/eth/base.test.ts
@@ -1,7 +1,9 @@
 
-import {createEthAccount, createEthAccountWithBalance, deployFlipper, ethBalanceViaSub, GAS_ARGS, itWeb3, recordEthFee} from './util/helpers';
+import {collectionIdToAddress, createEthAccount, createEthAccountWithBalance, deployFlipper, ethBalanceViaSub, GAS_ARGS, itWeb3, recordEthFee} from './util/helpers';
 import {expect} from 'chai';
-import {UNIQUE} from '../util/helpers';
+import {createCollectionExpectSuccess, createItemExpectSuccess, UNIQUE} from '../util/helpers';
+import nonFungibleAbi from './nonFungibleAbi.json';
+import privateKey from '../substrate/privateKey';
 
 describe('Contract calls', () => {
   itWeb3('Call of simple contract fee is less than 0.2 UNQ', async ({web3, api}) => {
@@ -19,4 +21,26 @@
     const cost = await recordEthFee(api, userA, () => web3.eth.sendTransaction({from: userA, to: userB, value: '1000000', ...GAS_ARGS}));
     expect(cost - await ethBalanceViaSub(api, userB) < BigInt(0.2 * Number(UNIQUE))).to.be.true;
   });
+
+  itWeb3('NFT transfer is close to 0.15 UNQ', async ({web3, api}) => {
+    const caller = await createEthAccountWithBalance(api, web3);
+    const receiver = createEthAccount(web3);
+
+    const alice = privateKey('//Alice');
+    const collection = await createCollectionExpectSuccess({
+      mode: {type: 'NFT'},
+    });
+    const itemId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: caller});
+
+    const address = collectionIdToAddress(collection);
+    const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: caller, ...GAS_ARGS});
+
+    const cost = await recordEthFee(api, caller, () => contract.methods.transfer(receiver, itemId).send(caller));
+
+    const fee = Number(cost) / Number(UNIQUE);
+    const expectedFee = 0.15;
+    const tolerance = 0.00001;
+
+    expect(Math.abs(fee - expectedFee)).to.be.lessThan(tolerance);
+  });
 });
modifiedtests/src/eth/fungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/fungible.test.ts
+++ b/tests/src/eth/fungible.test.ts
@@ -95,12 +95,12 @@
     const alice = privateKey('//Alice');
 
     const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner, 999999999999999);
+    await transferBalanceToEth(api, alice, owner);
 
     await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
 
     const spender = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, spender, 999999999999999);
+    await transferBalanceToEth(api, alice, spender);
 
     const receiver = createEthAccount(web3);
 
@@ -153,12 +153,12 @@
     const alice = privateKey('//Alice');
 
     const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner, 999999999999999);
+    await transferBalanceToEth(api, alice, owner);
 
     await createFungibleItemExpectSuccess(alice, collection, {Value: 200n}, {Ethereum: owner});
 
     const receiver = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, receiver, 999999999999999);
+    await transferBalanceToEth(api, alice, receiver);
 
     const address = collectionIdToAddress(collection);
     const contract = new web3.eth.Contract(fungibleAbi as any, address, {from: owner, ...GAS_ARGS});
modifiedtests/src/eth/marketplace/marketplace.test.tsdiffbeforeafterboth
--- a/tests/src/eth/marketplace/marketplace.test.ts
+++ b/tests/src/eth/marketplace/marketplace.test.ts
@@ -1,7 +1,7 @@
 import {readFile} from 'fs/promises';
 import {getBalanceSingle, transferBalanceExpectSuccess} from '../../substrate/get-balance';
 import privateKey from '../../substrate/privateKey';
-import {addToAllowListExpectSuccess, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, createFungibleItemExpectSuccess, createItemExpectSuccess, getTokenOwner, setCollectionSponsorExpectSuccess, transferExpectSuccess, transferFromExpectSuccess} from '../../util/helpers';
+import {addToAllowListExpectSuccess, confirmSponsorshipExpectSuccess, createCollectionExpectSuccess, createFungibleItemExpectSuccess, createItemExpectSuccess, getTokenOwner, setCollectionLimitsExpectSuccess, setCollectionSponsorExpectSuccess, transferExpectSuccess, transferFromExpectSuccess} from '../../util/helpers';
 import {collectionIdToAddress, contractHelpers, createEthAccountWithBalance, executeEthTxOnSub, GAS_ARGS, itWeb3, subToEth, subToEthLowercase, transferBalanceToEth} from '../util/helpers';
 import {evmToAddress} from '@polkadot/util-crypto';
 import nonFungibleAbi from '../nonFungibleAbi.json';
@@ -13,38 +13,42 @@
 describe('Matcher contract usage', () => {
   itWeb3('With UNQ', async ({api, web3}) => {
     const alice = privateKey('//Alice');
-    const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
-    const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId));
     const matcherOwner = await createEthAccountWithBalance(api, web3);
-    const helpers = contractHelpers(web3, matcherOwner);
-
     const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {
       from: matcherOwner,
       ...GAS_ARGS,
     });
     const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments:[matcherOwner]}).send({from: matcherOwner});
-
-    await transferBalanceToEth(api, alice, matcher.options.address);
+    const helpers = contractHelpers(web3, matcherOwner);
     await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner});
+    await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});
+    await transferBalanceToEth(api, alice, matcher.options.address);
 
-    await transferBalanceToEth(api, alice, subToEth(alice.address));
+    const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+    await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});
+    const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});
     await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+    await transferBalanceToEth(api, alice, subToEth(alice.address));
     await confirmSponsorshipExpectSuccess(collectionId);
 
-    const seller = privateKey('//Seller/' + Date.now());
-    await addToAllowListExpectSuccess(alice, collectionId, {Ethereum:subToEth(seller.address)});
+    await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});
+    await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));
+
+    const seller = privateKey(`//Seller/${Date.now()}`);
     await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});
 
     const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);
 
-    // To transfer item to matcher it first needs to be transfered to EVM account of seller
+    // To transfer item to matcher it first needs to be transfered to EVM account of bob
     await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});
+
+    // Token is owned by seller initially
     expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});
 
     // Ask
     {
-      await executeEthTxOnSub(api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));
-      await executeEthTxOnSub(api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));
+      await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));
+      await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));
     }
 
     // Token is transferred to matcher
@@ -53,7 +57,7 @@
     // Buy
     {
       const sellerBalanceBeforePurchase = await getBalanceSingle(api, seller.address);
-      await executeEthTxOnSub(api, alice, matcher, m => m.buy(evmCollection.options.address, tokenId), {value: PRICE});
+      await executeEthTxOnSub(web3, api, alice, matcher, m => m.buy(evmCollection.options.address, tokenId), {value: PRICE});
       expect(await getBalanceSingle(api, seller.address) - sellerBalanceBeforePurchase === PRICE);
     }
 
@@ -69,6 +73,7 @@
 
   // selling for custom tokens excluded from release
   itWeb3.skip('With custom ERC20', async ({api, web3}) => {
+    const alice = privateKey('//Alice');
     const matcherOwner = await createEthAccountWithBalance(api, web3);
     const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {
       from: matcherOwner,
@@ -76,7 +81,6 @@
     });
     const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner});
 
-    const alice = privateKey('//Alice');
     const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
     const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});
 
@@ -99,8 +103,8 @@
 
     // Ask
     {
-      await executeEthTxOnSub(api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));
-      await executeEthTxOnSub(api, seller, matcher, m => m.setAsk(PRICE, evmFungible.options.address, evmCollection.options.address, tokenId, 1));
+      await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));
+      await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, evmFungible.options.address, evmCollection.options.address, tokenId, 1));
     }
 
     // Token is transferred to matcher
@@ -111,9 +115,9 @@
       const sellerBalanceBeforePurchase = BigInt(await evmFungible.methods.balanceOf(subToEth(seller.address)).call());
       const buyerBalanceBeforePurchase = BigInt(await evmFungible.methods.balanceOf(subToEth(alice.address)).call());
 
-      await executeEthTxOnSub(api, alice, evmFungible, m => m.approve(matcher.options.address, PRICE));
+      await executeEthTxOnSub(web3, api, alice, evmFungible, m => m.approve(matcher.options.address, PRICE));
       // There is two functions named 'buy', so we should provide full signature
-      await executeEthTxOnSub(api, alice, matcher, m =>
+      await executeEthTxOnSub(web3, api, alice, matcher, m =>
         m['buy(address,uint256,address,uint256)'](evmCollection.options.address, tokenId, evmFungible.options.address, PRICE));
 
       // Approved price is removed from buyer balance, and added to seller
@@ -134,40 +138,44 @@
 
   itWeb3('With escrow', async ({api, web3}) => {
     const alice = privateKey('//Alice');
-    const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
-    const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId));
     const matcherOwner = await createEthAccountWithBalance(api, web3);
-    const helpers = contractHelpers(web3, matcherOwner);
     const escrow = await createEthAccountWithBalance(api, web3);
-
     const matcherContract = new web3.eth.Contract(JSON.parse((await readFile(`${__dirname}/MarketPlace.abi`)).toString()), undefined, {
       from: matcherOwner,
       ...GAS_ARGS,
     });
-    const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner});
+    const matcher = await matcherContract.deploy({data: (await readFile(`${__dirname}/MarketPlace.bin`)).toString(), arguments: [matcherOwner]}).send({from: matcherOwner, gas: 10000000});
     await matcher.methods.setEscrow(escrow).send({from: matcherOwner});
-
-    await transferBalanceToEth(api, alice, matcher.options.address);
+    const helpers = contractHelpers(web3, matcherOwner);
     await helpers.methods.toggleSponsoring(matcher.options.address, true).send({from: matcherOwner});
+    await helpers.methods.setSponsoringRateLimit(matcher.options.address, 1).send({from: matcherOwner});
+    await transferBalanceToEth(api, alice, matcher.options.address);
 
-    await transferBalanceToEth(api, alice, subToEth(alice.address));
+    const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+    await setCollectionLimitsExpectSuccess(alice, collectionId, {sponsorApproveTimeout: 1});
+    const evmCollection = new web3.eth.Contract(nonFungibleAbi as any, collectionIdToAddress(collectionId), {from: matcherOwner});
     await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+    await transferBalanceToEth(api, alice, subToEth(alice.address));
     await confirmSponsorshipExpectSuccess(collectionId);
 
-    const seller = privateKey('//Seller/' + Date.now());
+    await helpers.methods.toggleAllowed(matcher.options.address, subToEth(alice.address), true).send({from: matcherOwner});
+    await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(alice.address)));
+
+    const seller = privateKey(`//Seller/${Date.now()}`);
     await helpers.methods.toggleAllowed(matcher.options.address, subToEth(seller.address), true).send({from: matcherOwner});
-    await addToAllowListExpectSuccess(alice, collectionId, evmToAddress(subToEth(seller.address)));
 
     const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', seller.address);
 
-    // To transfer item to matcher it first needs to be transfered to EVM account of seller
+    // To transfer item to matcher it first needs to be transfered to EVM account of bob
     await transferExpectSuccess(collectionId, tokenId, seller, {Ethereum: subToEth(seller.address)});
+
+    // Token is owned by seller initially
     expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal({Ethereum: subToEthLowercase(seller.address)});
 
     // Ask
     {
-      await executeEthTxOnSub(api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));
-      await executeEthTxOnSub(api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));
+      await executeEthTxOnSub(web3, api, seller, evmCollection, m => m.approve(matcher.options.address, tokenId));
+      await executeEthTxOnSub(web3, api, seller, matcher, m => m.addAsk(PRICE, '0x0000000000000000000000000000000000000001', evmCollection.options.address, tokenId));
     }
 
     // Token is transferred to matcher
@@ -181,7 +189,7 @@
       expect(await matcher.methods.balanceKSM(subToEth(seller.address)).call()).to.be.equal('0');
       expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal(PRICE.toString());
 
-      await executeEthTxOnSub(api, alice, matcher, m => m.buyKSM(evmCollection.options.address, tokenId, subToEth(alice.address), subToEth(alice.address)));
+      await executeEthTxOnSub(web3, api, alice, matcher, m => m.buyKSM(evmCollection.options.address, tokenId, subToEth(alice.address), subToEth(alice.address)));
 
       // Price is removed from buyer balance, and added to seller
       expect(await matcher.methods.balanceKSM(subToEth(alice.address)).call()).to.be.equal('0');
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -203,7 +203,7 @@
     const alice = privateKey('//Alice');
 
     const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner, 999999999999999);
+    await transferBalanceToEth(api, alice, owner);
 
     const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
 
@@ -213,7 +213,7 @@
     const contract = new web3.eth.Contract(nonFungibleAbi as any, address);
 
     {
-      const result = await contract.methods.approve(spender, tokenId).send({from: owner, gas: '0x1000000', gasPrice: '0x01'});
+      const result = await contract.methods.approve(spender, tokenId).send({from: owner, ...GAS_ARGS});
       const events = normalizeEvents(result.events);
 
       expect(events).to.be.deep.equal([
@@ -237,12 +237,12 @@
     const alice = privateKey('//Alice');
 
     const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner, 999999999999999);
+    await transferBalanceToEth(api, alice, owner);
 
     const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
 
     const spender = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, spender, 999999999999999);
+    await transferBalanceToEth(api, alice, spender);
 
     const receiver = createEthAccount(web3);
 
@@ -285,12 +285,12 @@
     const alice = privateKey('//Alice');
 
     const owner = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, owner, 999999999999999);
+    await transferBalanceToEth(api, alice, owner);
 
     const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: owner});
 
     const receiver = createEthAccount(web3);
-    await transferBalanceToEth(api, alice, receiver, 999999999999999);
+    await transferBalanceToEth(api, alice, receiver);
 
     const address = collectionIdToAddress(collection);
     const contract = new web3.eth.Contract(nonFungibleAbi as any, address, {from: owner, ...GAS_ARGS});
modifiedtests/src/eth/payable.test.tsdiffbeforeafterboth
--- a/tests/src/eth/payable.test.ts
+++ b/tests/src/eth/payable.test.ts
@@ -1,7 +1,7 @@
 import {expect} from 'chai';
 import privateKey from '../substrate/privateKey';
 import {submitTransactionAsync} from '../substrate/substrate-api';
-import {createEthAccountWithBalance, deployCollector, GAS_ARGS, itWeb3, subToEth} from './util/helpers';
+import {createEthAccountWithBalance, deployCollector, GAS_ARGS, itWeb3, subToEth, transferBalanceToEth} from './util/helpers';
 import {evmToAddress} from '@polkadot/util-crypto';
 import {getGenericResult} from '../util/helpers';
 import {getBalanceSingle, transferBalanceExpectSuccess} from '../substrate/get-balance';
@@ -23,7 +23,7 @@
 
     // Transaction fee/value will be payed from subToEth(sender) evm balance,
     // which is backed by evmToAddress(subToEth(sender)) substrate balance
-    await transferBalanceExpectSuccess(api, alice, evmToAddress(subToEth(alice.address)), '1000000000000');
+    await transferBalanceToEth(api, alice, subToEth(alice.address));
 
     {
       const tx = api.tx.evm.call(
@@ -32,7 +32,7 @@
         contract.methods.giveMoney().encodeABI(),
         '10000',
         GAS_ARGS.gas,
-        GAS_ARGS.gasPrice,
+        await web3.eth.getGasPrice(),
         null,
       );
       const events = await submitTransactionAsync(alice, tx);
modifiedtests/src/eth/proxy/nonFungibleProxy.test.tsdiffbeforeafterboth
--- a/tests/src/eth/proxy/nonFungibleProxy.test.ts
+++ b/tests/src/eth/proxy/nonFungibleProxy.test.ts
@@ -224,7 +224,7 @@
     const tokenId = await createItemExpectSuccess(alice, collection, 'NFT', {Ethereum: contract.options.address});
 
     {
-      const result = await contract.methods.approve(spender, tokenId).send({from: caller, gas: '0x1000000', gasPrice: '0x01'});
+      const result = await contract.methods.approve(spender, tokenId).send({from: caller, ...GAS_ARGS});
       const events = normalizeEvents(result.events);
 
       expect(events).to.be.deep.equal([
modifiedtests/src/eth/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/eth/util/helpers.ts
+++ b/tests/src/eth/util/helpers.ts
@@ -12,14 +12,14 @@
 import usingApi, {submitTransactionAsync} from '../../substrate/substrate-api';
 import {IKeyringPair} from '@polkadot/types/types';
 import {expect} from 'chai';
-import {getGenericResult} from '../../util/helpers';
+import {getGenericResult, UNIQUE} from '../../util/helpers';
 import * as solc from 'solc';
 import config from '../../config';
 import privateKey from '../../substrate/privateKey';
 import contractHelpersAbi from './contractHelpersAbi.json';
 import getBalance from '../../substrate/get-balance';
 
-export const GAS_ARGS = {gas: 0x1000000, gasPrice: '0x01'};
+export const GAS_ARGS = {gas: 2500000};
 
 let web3Connected = false;
 export async function usingWeb3<T>(cb: (web3: Web3) => Promise<T> | T): Promise<T> {
@@ -63,7 +63,7 @@
   return account;
 }
 
-export async function transferBalanceToEth(api: ApiPromise, source: IKeyringPair, target: string, amount = 999999999999999) {
+export async function transferBalanceToEth(api: ApiPromise, source: IKeyringPair, target: string, amount = 1000n * UNIQUE) {
   const tx = api.tx.balances.transfer(evmToAddress(target), amount);
   const events = await submitTransactionAsync(source, tx);
   const result = getGenericResult(events);
@@ -234,20 +234,20 @@
  * @param mkTx - closure, receiving `contract.methods`, and returning method call,
  * to be used as following (assuming `to` = erc20 contract):
  * `m => m.transfer(to, amount)`
- * 
+ *
  * # Example
  * ```ts
  * executeEthTxOnSub(api, alice, erc20Contract, m => m.transfer(target, amount));
  * ```
  */
-export async function executeEthTxOnSub(api: ApiPromise, from: IKeyringPair, to: any, mkTx: (methods: any) => any, {value = 0}: {value?: bigint | number} = { }) {
+export async function executeEthTxOnSub(web3: Web3, api: ApiPromise, from: IKeyringPair, to: any, mkTx: (methods: any) => any, {value = 0}: {value?: bigint | number} = { }) {
   const tx = api.tx.evm.call(
     subToEth(from.address),
     to.options.address,
     mkTx(to.methods).encodeABI(),
     value,
     GAS_ARGS.gas,
-    GAS_ARGS.gasPrice,
+    await web3.eth.getGasPrice(),
     null,
   );
   const events = await submitTransactionAsync(from, tx);
@@ -260,7 +260,7 @@
 
 /**
  * Measure how much gas given closure consumes
- * 
+ *
  * @param user which user balance will be checked
  */
 export async function recordEthFee(api: ApiPromise, user: string, call: () => Promise<any>): Promise<bigint> {
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -69,7 +69,7 @@
 
 export const U128_MAX = (1n << 128n) - 1n;
 
-const MICROUNIQUE = 1_000_000_000n;
+const MICROUNIQUE = 1_000_000_000_000n;
 const MILLIUNIQUE = 1_000n * MICROUNIQUE;
 const CENTIUNIQUE = 10n * MILLIUNIQUE;
 export const UNIQUE = 100n * CENTIUNIQUE;