git.delta.rocks / unique-network / refs/commits / 447a9ec75406

difftreelog

Merge pull request #120 from usetech-llc/v3.0.0

usetech-llc2021-03-06parents: #1f47f96 #2eedf45.patch.diff
in: master
nft node v3.0.0

14 files changed

modified.devcontainer/Dockerfilediffbeforeafterboth
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -9,6 +9,6 @@
     export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" && \
     [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && \
     nvm install v12.20.1 && \
-    rustup toolchain install nightly-2020-10-01 && \
-    rustup default nightly-2020-10-01 && \
+    rustup toolchain install nightly-2021-03-01 && \
+    rustup default nightly-2021-03-01 && \
     rustup target add wasm32-unknown-unknown
\ No newline at end of file
modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -16,7 +16,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7"
 dependencies = [
- "gimli 0.23.0",
+ "gimli",
 ]
 
 [[package]]
@@ -380,6 +380,12 @@
 ]
 
 [[package]]
+name = "base-x"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
+
+[[package]]
 name = "base58"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -439,12 +445,14 @@
 
 [[package]]
 name = "bitvec"
-version = "0.17.4"
+version = "0.20.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c"
+checksum = "f5011ffc90248764d7005b0e10c7294f5aa1bd87d9dd7248f4ad475b347c294d"
 dependencies = [
- "either",
+ "funty",
  "radium",
+ "tap",
+ "wyz",
 ]
 
 [[package]]
@@ -480,6 +488,32 @@
 ]
 
 [[package]]
+name = "blake2s_simd"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2"
+dependencies = [
+ "arrayref",
+ "arrayvec 0.5.2",
+ "constant_time_eq",
+]
+
+[[package]]
+name = "blake3"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9ff35b701f3914bdb8fad3368d822c766ef2858b2583198e41639b936f09d3f"
+dependencies = [
+ "arrayref",
+ "arrayvec 0.5.2",
+ "cc",
+ "cfg-if 0.1.10",
+ "constant_time_eq",
+ "crypto-mac 0.8.0",
+ "digest 0.9.0",
+]
+
+[[package]]
 name = "block-buffer"
 version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -555,6 +589,15 @@
 ]
 
 [[package]]
+name = "build-helper"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdce191bf3fa4995ce948c8c83b4640a1745457a149e73c6db75b4ffe36aad5f"
+dependencies = [
+ "semver 0.6.0",
+]
+
+[[package]]
 name = "bumpalo"
 version = "3.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -562,9 +605,9 @@
 
 [[package]]
 name = "byte-slice-cast"
-version = "0.3.5"
+version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3"
+checksum = "65c1bf4a04a88c54f589125563643d773f3254b5c38571395e2b591c693bbc81"
 
 [[package]]
 name = "byte-tools"
@@ -608,6 +651,28 @@
 checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
 
 [[package]]
+name = "cargo-platform"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0226944a63d1bf35a3b5f948dd7c59e263db83695c9e8bffc4037de02e30f1d7"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "cargo_metadata"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7714a157da7991e23d90686b9524b9e12e0407a108647f52e9328f4b3d51ac7f"
+dependencies = [
+ "cargo-platform",
+ "semver 0.11.0",
+ "semver-parser 0.10.2",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
 name = "cc"
 version = "1.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -674,6 +739,17 @@
 ]
 
 [[package]]
+name = "cid"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff0e3bc0b6446b3f9663c1a6aba6ef06c5aeaa1bc92bd18077be337198ab9768"
+dependencies = [
+ "multibase",
+ "multihash",
+ "unsigned-varint 0.5.1",
+]
+
+[[package]]
 name = "cipher"
 version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -755,6 +831,16 @@
 checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
 
 [[package]]
+name = "cpp_demangle"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44919ecaf6f99e8e737bc239408931c9a01e9a6c74814fee8242dd2506b65390"
+dependencies = [
+ "cfg-if 1.0.0",
+ "glob",
+]
+
+[[package]]
 name = "cpuid-bool"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -768,25 +854,25 @@
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.66.0"
+version = "0.69.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8dcc286b052ee24a1e5a222e7c1125e6010ad35b0f248709b9b3737a8fedcfdf"
+checksum = "4066fd63b502d73eb8c5fa6bcab9c7962b05cd580f6b149ee83a8e730d8ce7fb"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.66.0"
+version = "0.69.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d9badfe36176cb653506091693bc2bb1970c9bddfcd6ec7fac404f7eaec6f38"
+checksum = "1a54e4beb833a3c873a18a8fe735d73d732044004c7539a072c8faa35ccb0c60"
 dependencies = [
  "byteorder",
  "cranelift-bforest",
  "cranelift-codegen-meta",
  "cranelift-codegen-shared",
  "cranelift-entity",
- "gimli 0.21.0",
+ "gimli",
  "log",
  "regalloc",
  "serde",
@@ -797,9 +883,9 @@
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.66.0"
+version = "0.69.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c3f460031861e4f4ad510be62b2ae50bba6cc886b598a36f9c0a970feab9598"
+checksum = "c54cac7cacb443658d8f0ff36a3545822613fa202c946c0891897843bc933810"
 dependencies = [
  "cranelift-codegen-shared",
  "cranelift-entity",
@@ -807,24 +893,24 @@
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.66.0"
+version = "0.69.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76ad12409e922e7697cd0bdc7dc26992f64a77c31880dfe5e3c7722f4710206d"
+checksum = "a109760aff76788b2cdaeefad6875a73c2b450be13906524f6c2a81e05b8d83c"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.66.0"
+version = "0.69.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d97cdc58972ea065d107872cfb9079f4c92ade78a8af85aaff519a65b5d13f71"
+checksum = "3b044234aa32531f89a08b487630ddc6744696ec04c8123a1ad388de837f5de3"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.66.0"
+version = "0.69.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ef419efb4f94ecc02e5d9fbcc910d2bb7f0040e2de570e63a454f883bc891d6"
+checksum = "5452b3e4e97538ee5ef2cc071301c69a86c7adf2770916b9d04e9727096abd93"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -834,9 +920,9 @@
 
 [[package]]
 name = "cranelift-native"
-version = "0.66.0"
+version = "0.69.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e69d44d59826eef6794066ac2c0f4ad3975f02d97030c60dbc04e3886adf36e"
+checksum = "f68035c10b2e80f26cc29c32fa824380877f38483504c2a47b54e7da311caaf3"
 dependencies = [
  "cranelift-codegen",
  "raw-cpuid",
@@ -845,17 +931,19 @@
 
 [[package]]
 name = "cranelift-wasm"
-version = "0.66.0"
+version = "0.69.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "979df666b1304624abe99738e9e0e7c7479ee5523ba4b8b237df9ff49996acbb"
+checksum = "a530eb9d1c95b3309deb24c3d179d8b0ba5837ed98914a429787c395f614949d"
 dependencies = [
  "cranelift-codegen",
  "cranelift-entity",
  "cranelift-frontend",
+ "itertools",
  "log",
  "serde",
+ "smallvec 1.6.1",
  "thiserror",
- "wasmparser 0.59.0",
+ "wasmparser",
 ]
 
 [[package]]
@@ -1050,6 +1138,26 @@
 checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
 
 [[package]]
+name = "data-encoding-macro"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a94feec3d2ba66c0b6621bca8bc6f68415b1e5c69af3586fdd0af9fd9f29b17"
+dependencies = [
+ "data-encoding",
+ "data-encoding-macro-internal",
+]
+
+[[package]]
+name = "data-encoding-macro-internal"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0f83e699727abca3c56e187945f303389590305ab2f0185ea445aa66e8d5f2a"
+dependencies = [
+ "data-encoding",
+ "syn",
+]
+
+[[package]]
 name = "derive_more"
 version = "0.99.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1080,21 +1188,21 @@
 
 [[package]]
 name = "directories"
-version = "2.0.2"
+version = "3.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c"
+checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f"
 dependencies = [
- "cfg-if 0.1.10",
  "dirs-sys",
 ]
 
 [[package]]
-name = "directories"
-version = "3.0.1"
+name = "directories-next"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f"
+checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc"
 dependencies = [
- "dirs-sys",
+ "cfg-if 1.0.0",
+ "dirs-sys-next",
 ]
 
 [[package]]
@@ -1104,11 +1212,22 @@
 checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
 dependencies = [
  "libc",
- "redox_users",
+ "redox_users 0.3.5",
  "winapi 0.3.9",
 ]
 
 [[package]]
+name = "dirs-sys-next"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
+dependencies = [
+ "libc",
+ "redox_users 0.4.0",
+ "winapi 0.3.9",
+]
+
+[[package]]
 name = "dns-parser"
 version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1322,17 +1441,17 @@
 
 [[package]]
 name = "finality-grandpa"
-version = "0.12.3"
+version = "0.13.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8feb87a63249689640ac9c011742c33139204e3c134293d3054022276869133b"
+checksum = "2cd795898c348a8ec9edc66ec9e014031c764d4c88cc26d09b492cd93eb41339"
 dependencies = [
  "either",
  "futures 0.3.12",
- "futures-timer 2.0.2",
+ "futures-timer 3.0.2",
  "log",
  "num-traits",
  "parity-scale-codec",
- "parking_lot 0.9.0",
+ "parking_lot 0.11.1",
 ]
 
 [[package]]
@@ -1390,8 +1509,9 @@
 
 [[package]]
 name = "fork-tree"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "632b95f97f332b2ff5bc3a42bc8e28772b067e333830e03fd046504f11cd0fb8"
 dependencies = [
  "parity-scale-codec",
 ]
@@ -1408,14 +1528,15 @@
 
 [[package]]
 name = "frame-benchmarking"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70fe99487f84579a3f2c4ba52650fec875492eea41be0e4eea8019187f105052"
 dependencies = [
  "frame-support",
  "frame-system",
  "linregress",
  "parity-scale-codec",
- "paste",
+ "paste 1.0.4",
  "sp-api",
  "sp-io",
  "sp-runtime",
@@ -1426,8 +1547,9 @@
 
 [[package]]
 name = "frame-benchmarking-cli"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2921b7890c5e4421a0b2eafbf835417eed8127b1cec3e1a0389515069f11d219"
 dependencies = [
  "Inflector",
  "chrono",
@@ -1449,8 +1571,9 @@
 
 [[package]]
 name = "frame-executive"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1da8fd471442bee91b9b3f587ec832e3f47800374fdb89b4a66591cd7c42b29f"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -1465,8 +1588,9 @@
 
 [[package]]
 name = "frame-metadata"
-version = "12.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "13.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "073f7bef18421362441a1708f8528e442234954611f95bdc554b313fb321948e"
 dependencies = [
  "parity-scale-codec",
  "serde",
@@ -1476,17 +1600,18 @@
 
 [[package]]
 name = "frame-support"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04e521e6214615bd82ba6b5fc7fd40a9cc14fdeb40f83da5eba12aa2f8179fb8"
 dependencies = [
  "bitflags",
  "frame-metadata",
  "frame-support-procedural",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "log",
  "once_cell",
  "parity-scale-codec",
- "paste",
+ "paste 1.0.4",
  "serde",
  "smallvec 1.6.1",
  "sp-arithmetic",
@@ -1494,6 +1619,7 @@
  "sp-inherents",
  "sp-io",
  "sp-runtime",
+ "sp-staking",
  "sp-state-machine",
  "sp-std",
  "sp-tracing",
@@ -1501,8 +1627,9 @@
 
 [[package]]
 name = "frame-support-procedural"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2668e24cbaba7f0e91d0c92a94bd1ae425a942608ad0b775db32477f5df4da9e"
 dependencies = [
  "Inflector",
  "frame-support-procedural-tools",
@@ -1513,8 +1640,9 @@
 
 [[package]]
 name = "frame-support-procedural-tools"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4f88cfd111e004590f4542b75e6d3302137b9067d7e7219e4ac47a535c3b5c1"
 dependencies = [
  "frame-support-procedural-tools-derive",
  "proc-macro-crate",
@@ -1525,8 +1653,9 @@
 
 [[package]]
 name = "frame-support-procedural-tools-derive"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79285388b120ac96c15a791c56b26b9264f7231324fbe0fd05026acd92bf2e6a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1535,11 +1664,12 @@
 
 [[package]]
 name = "frame-system"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f5fedbff05d665c00bf4e089b4377fcb15b8bd37ebc3e5fc06665474cf6e25d7"
 dependencies = [
  "frame-support",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "serde",
  "sp-core",
@@ -1551,8 +1681,9 @@
 
 [[package]]
 name = "frame-system-benchmarking"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e93602f58cdab9820b6d607b7b50834d9b878efa33405a65c89ebfb5a596b584"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -1565,8 +1696,9 @@
 
 [[package]]
 name = "frame-system-rpc-runtime-api"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5cb9d2f86a903fdee4ca3d660c767e69a743cee8aeb103563a14ea52e9f0001d"
 dependencies = [
  "parity-scale-codec",
  "sp-api",
@@ -1607,6 +1739,12 @@
 checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
 
 [[package]]
+name = "funty"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
+
+[[package]]
 name = "futures"
 version = "0.1.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1841,20 +1979,14 @@
 
 [[package]]
 name = "gimli"
-version = "0.21.0"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c"
+checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
 dependencies = [
  "fallible-iterator",
  "indexmap",
  "stable_deref_trait",
 ]
-
-[[package]]
-name = "gimli"
-version = "0.23.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
 
 [[package]]
 name = "glob"
@@ -2229,9 +2361,9 @@
 
 [[package]]
 name = "impl-codec"
-version = "0.4.2"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53"
+checksum = "df170efa359aebdd5cb7fe78edcc67107748e4737bdca8a8fb40d15ea7a877ed"
 dependencies = [
  "parity-scale-codec",
 ]
@@ -2243,17 +2375,6 @@
 checksum = "b47ca4d2b6931707a55fce5cf66aff80e2178c8b63bbb4ecb5695cbc870ddf6f"
 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]]
@@ -2509,9 +2630,9 @@
 
 [[package]]
 name = "kvdb"
-version = "0.8.0"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92312348daade49976a6dc59263ad39ed54f840aacb5664874f7c9aa16e5f848"
+checksum = "8891bd853eff90e33024195d79d578dc984c82f9e0715fcd2b525a0c19d52811"
 dependencies = [
  "parity-util-mem",
  "smallvec 1.6.1",
@@ -2519,9 +2640,9 @@
 
 [[package]]
 name = "kvdb-memorydb"
-version = "0.8.0"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "986052a8d16c692eaebe775391f9a3ac26714f3907132658500b601dec94c8c2"
+checksum = "30a0da8e08caf08d384a620ec19bb6c9b85c84137248e202617fb91881f25912"
 dependencies = [
  "kvdb",
  "parity-util-mem",
@@ -2530,9 +2651,9 @@
 
 [[package]]
 name = "kvdb-rocksdb"
-version = "0.10.0"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d92c36be64baba5ea549116ff0d7ffd445456a7be8aaee21ec05882b980cd11"
+checksum = "34446c373ccc494c2124439281c198c7636ccdc2752c06722bbffd56d459c1e4"
 dependencies = [
  "fs-swap",
  "kvdb",
@@ -3146,13 +3267,12 @@
 checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
 
 [[package]]
-name = "memmap"
-version = "0.7.0"
+name = "memmap2"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
+checksum = "04e3e85b970d650e2ae6d70592474087051c11c54da7f7b4949725c5735fbcc6"
 dependencies = [
  "libc",
- "winapi 0.3.9",
 ]
 
 [[package]]
@@ -3175,9 +3295,9 @@
 
 [[package]]
 name = "memory-db"
-version = "0.25.0"
+version = "0.26.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6cbd2a22f201c03cc1706a727842490abfea17b7b53260358239828208daba3c"
+checksum = "814bbecfc0451fc314eeea34f05bbcd5b98a7ad7af37faee088b86a1e633f1d4"
 dependencies = [
  "hash-db",
  "hashbrown",
@@ -3315,15 +3435,30 @@
 checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238"
 
 [[package]]
+name = "multibase"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b78c60039650ff12e140ae867ef5299a58e19dded4d334c849dc7177083667e2"
+dependencies = [
+ "base-x",
+ "data-encoding",
+ "data-encoding-macro",
+]
+
+[[package]]
 name = "multihash"
 version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4dac63698b887d2d929306ea48b63760431ff8a24fac40ddb22f9c7f49fb7cab"
 dependencies = [
+ "blake2b_simd",
+ "blake2s_simd",
+ "blake3",
  "digest 0.9.0",
  "generic-array 0.14.4",
  "multihash-derive",
  "sha2 0.9.3",
+ "sha3",
  "unsigned-varint 0.5.1",
 ]
 
@@ -3456,7 +3591,7 @@
 
 [[package]]
 name = "nft-runtime"
-version = "2.1.0"
+version = "3.0.0"
 dependencies = [
  "frame-benchmarking",
  "frame-executive",
@@ -3494,7 +3629,7 @@
  "sp-std",
  "sp-transaction-pool",
  "sp-version",
- "substrate-wasm-builder-runner",
+ "substrate-wasm-builder",
 ]
 
 [[package]]
@@ -3584,19 +3719,12 @@
 
 [[package]]
 name = "object"
-version = "0.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2"
-
-[[package]]
-name = "object"
-version = "0.20.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
+checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
 dependencies = [
  "crc32fast",
  "indexmap",
- "wasmparser 0.57.0",
 ]
 
 [[package]]
@@ -3643,8 +3771,9 @@
 
 [[package]]
 name = "pallet-aura"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73ff6054e982e7841a2519c988680620a85c1da5cd32363998a30302ed47f6f9"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -3654,7 +3783,6 @@
  "serde",
  "sp-application-crypto",
  "sp-consensus-aura",
- "sp-inherents",
  "sp-runtime",
  "sp-std",
  "sp-timestamp",
@@ -3662,12 +3790,13 @@
 
 [[package]]
 name = "pallet-authorship"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47433a94141451e7079aabf3ca28f2bde8c642d84b568be9626e9b7cae8b11b1"
 dependencies = [
  "frame-support",
  "frame-system",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "sp-authorship",
  "sp-inherents",
@@ -3677,8 +3806,9 @@
 
 [[package]]
 name = "pallet-balances"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41aaeaf084e594273f82bcbf96416ef1fcab602e15dd1df04b9930eceb2eb518"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -3691,15 +3821,16 @@
 
 [[package]]
 name = "pallet-contracts"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0979c1dd82fc56a87b37311006fe56f406de027c24591353058e9e9fc56487c"
 dependencies = [
  "frame-support",
  "frame-system",
  "pallet-contracts-primitives",
  "pallet-contracts-proc-macro",
  "parity-scale-codec",
- "parity-wasm",
+ "parity-wasm 0.41.0",
  "pwasm-utils 0.16.0",
  "serde",
  "sp-core",
@@ -3712,8 +3843,9 @@
 
 [[package]]
 name = "pallet-contracts-primitives"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "621d75148763349f72e76e79f62365d28adb51e3f2e0285e4e8b8600ae600978"
 dependencies = [
  "bitflags",
  "parity-scale-codec",
@@ -3723,8 +3855,9 @@
 
 [[package]]
 name = "pallet-contracts-proc-macro"
-version = "0.1.0"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90046017aeee3f77752a6c77cdfb1bc93eb728591dc6edad36e2706f7626fd50"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3733,8 +3866,9 @@
 
 [[package]]
 name = "pallet-contracts-rpc"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22491e3c304819f96c83d02e43bd99128e4e42a57da4d6a9d4b5193778da915b"
 dependencies = [
  "jsonrpc-core",
  "jsonrpc-core-client",
@@ -3752,8 +3886,9 @@
 
 [[package]]
 name = "pallet-contracts-rpc-runtime-api"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb4b410cb148e68256e3827854a67ec34b16157f448e78173219dcd6a8ec7343"
 dependencies = [
  "pallet-contracts-primitives",
  "parity-scale-codec",
@@ -3764,8 +3899,9 @@
 
 [[package]]
 name = "pallet-grandpa"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c012cb0337ce1eaf0685be2777bce1ef8c5d7b7be77ea33916c316b40af43fa"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -3785,12 +3921,11 @@
 
 [[package]]
 name = "pallet-nft"
-version = "2.1.0"
+version = "3.0.0"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
  "frame-system",
- "log",
  "pallet-balances",
  "pallet-contracts",
  "pallet-randomness-collective-flip",
@@ -3806,8 +3941,9 @@
 
 [[package]]
 name = "pallet-randomness-collective-flip"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3ea6fa9aa36735ec11d7ec4d97dd6472650c0656fdc6d4adaca2578bd71134"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -3819,12 +3955,13 @@
 
 [[package]]
 name = "pallet-session"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d243c3ccac56a4c55fade6be5c5af1de07fac374fa7856377980a76b0c193cf"
 dependencies = [
  "frame-support",
  "frame-system",
- "impl-trait-for-tuples 0.1.3",
+ "impl-trait-for-tuples",
  "pallet-timestamp",
  "parity-scale-codec",
  "serde",
@@ -3839,8 +3976,9 @@
 
 [[package]]
 name = "pallet-sudo"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4a96774302e3824b7924c2465935ca4d558ea5f6a762c043fbc45fd2646ce89"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -3853,13 +3991,14 @@
 
 [[package]]
 name = "pallet-timestamp"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b17dd274716a55a2c3e34d9c0ed66aaac3d7e0393ec9fd985e2b8532d697a7f3"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
  "frame-system",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "serde",
  "sp-inherents",
@@ -3871,8 +4010,9 @@
 
 [[package]]
 name = "pallet-transaction-payment"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48e10dc1a10dd3f52edb20d3885cf5b2b16f26273a4d93e61331c6691fb13ab3"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -3887,8 +4027,9 @@
 
 [[package]]
 name = "pallet-transaction-payment-rpc"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7835717b7d8fb59c33dd73f083c68a6d143a1dbe6029364c63ea7f4cb0ba3f9c"
 dependencies = [
  "jsonrpc-core",
  "jsonrpc-core-client",
@@ -3904,8 +4045,9 @@
 
 [[package]]
 name = "pallet-transaction-payment-rpc-runtime-api"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a92d3383260d0d19d9a36f40766d48d779fd19baccba8b20c3e7d2670a26ee1"
 dependencies = [
  "pallet-transaction-payment",
  "parity-scale-codec",
@@ -3915,12 +4057,13 @@
 
 [[package]]
 name = "pallet-treasury"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d19f881664d42d1c33dd67e690d6bddd35d38723fcc099b19304f9723fc3070c"
 dependencies = [
  "frame-support",
  "frame-system",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "pallet-balances",
  "parity-scale-codec",
  "serde",
@@ -3930,8 +4073,9 @@
 
 [[package]]
 name = "pallet-vesting"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e4e1af42bbdf1d477c3762387c74855f24bca47700df3ce7d9428045986b544"
 dependencies = [
  "enumflags2",
  "frame-support",
@@ -3944,16 +4088,18 @@
 
 [[package]]
 name = "parity-db"
-version = "0.1.2"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00d595e372d119261593297debbe4193811a4dc811d2a1ccbb8caaa6666ad7ab"
+checksum = "111e193c96758d476d272093a853882668da17489f76bf4361b8decae0b6c515"
 dependencies = [
  "blake2-rfc",
  "crc32fast",
+ "hex",
  "libc",
  "log",
- "memmap",
- "parking_lot 0.10.2",
+ "memmap2",
+ "parking_lot 0.11.1",
+ "rand 0.8.3",
 ]
 
 [[package]]
@@ -3976,9 +4122,9 @@
 
 [[package]]
 name = "parity-scale-codec"
-version = "1.3.6"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79602888a81ace83e3d1d4b2873286c1f5f906c84db667594e8db8da3506c383"
+checksum = "0cd3dab59b5cf4bc81069ade0fc470341a1ef3ad5fa73e5a8943bed2ec12b2e8"
 dependencies = [
  "arrayvec 0.5.2",
  "bitvec",
@@ -3989,9 +4135,9 @@
 
 [[package]]
 name = "parity-scale-codec-derive"
-version = "1.2.2"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "198db82bb1c18fc00176004462dd809b2a6d851669550aa17af6dacd21ae0c14"
+checksum = "fa04976a81fde04924b40cc4036c4d12841e8bb04325a5cf2ada75731a150a7d"
 dependencies = [
  "proc-macro-crate",
  "proc-macro2",
@@ -4026,13 +4172,13 @@
 
 [[package]]
 name = "parity-util-mem"
-version = "0.8.0"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f17f15cb05897127bf36a240085a1f0bbef7bce3024849eccf7f93f6171bc27"
+checksum = "664a8c6b8e62d8f9f2f937e391982eb433ab285b4cd9545b342441e04a906e42"
 dependencies = [
  "cfg-if 1.0.0",
  "hashbrown",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-util-mem-derive",
  "parking_lot 0.11.1",
  "primitive-types",
@@ -4053,6 +4199,15 @@
 
 [[package]]
 name = "parity-wasm"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16ad52817c4d343339b3bc2e26861bd21478eda0b7509acf83505727000512ac"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "parity-wasm"
 version = "0.41.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865"
@@ -4167,6 +4322,12 @@
 ]
 
 [[package]]
+name = "paste"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1"
+
+[[package]]
 name = "paste-impl"
 version = "0.1.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4337,9 +4498,9 @@
 
 [[package]]
 name = "platforms"
-version = "0.2.1"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "feb3b2b1033b8a60b4da6ee470325f887758c95d5320f52f9ce0df055a55940e"
+checksum = "989d43012e2ca1c4a02507c67282691a0a3207f9dc67cec596b43fe925b3d325"
 
 [[package]]
 name = "polling"
@@ -4383,9 +4544,9 @@
 
 [[package]]
 name = "primitive-types"
-version = "0.8.0"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3824ae2c5e27160113b9e029a10ec9e3f0237bad8029f69c7724393c9fdefd8"
+checksum = "2415937401cb030a2a0a4d922483f945fa068f52a7dbb22ce0fe5f2b6f6adace"
 dependencies = [
  "fixed-hash",
  "impl-codec",
@@ -4449,11 +4610,11 @@
 
 [[package]]
 name = "prometheus"
-version = "0.10.0"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30d70cf4412832bcac9cffe27906f4a66e450d323525e977168c70d1b36120ae"
+checksum = "c8425533e7122f0c3cc7a37e6244b16ad3a2cc32ae7ac6276e2a75da0d9c200d"
 dependencies = [
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "fnv",
  "lazy_static",
  "parking_lot 0.11.1",
@@ -4513,6 +4674,15 @@
 ]
 
 [[package]]
+name = "psm"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3abf49e5417290756acfd26501536358560c4a5cc4a0934d390939acb3e7083a"
+dependencies = [
+ "cc",
+]
+
+[[package]]
 name = "pwasm-utils"
 version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4520,7 +4690,7 @@
 dependencies = [
  "byteorder",
  "log",
- "parity-wasm",
+ "parity-wasm 0.41.0",
 ]
 
 [[package]]
@@ -4531,7 +4701,7 @@
 dependencies = [
  "byteorder",
  "log",
- "parity-wasm",
+ "parity-wasm 0.41.0",
 ]
 
 [[package]]
@@ -4568,9 +4738,9 @@
 
 [[package]]
 name = "radium"
-version = "0.3.0"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac"
+checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb"
 
 [[package]]
 name = "rand"
@@ -4712,9 +4882,9 @@
 
 [[package]]
 name = "raw-cpuid"
-version = "7.0.4"
+version = "8.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "beb71f708fe39b2c5e98076204c3cc094ee5a4c12c4cdb119a2b72dc34164f41"
+checksum = "1fdf7d9dbd43f3d81d94a49c1c3df73cc2b3827995147e6cf7f89d4ec5483e73"
 dependencies = [
  "bitflags",
  "cc",
@@ -4788,6 +4958,16 @@
 ]
 
 [[package]]
+name = "redox_users"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
+dependencies = [
+ "getrandom 0.2.2",
+ "redox_syscall 0.2.5",
+]
+
+[[package]]
 name = "ref-cast"
 version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4809,9 +4989,9 @@
 
 [[package]]
 name = "regalloc"
-version = "0.0.27"
+version = "0.0.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ba8aaf5fe7cf307c6dbdaeed85478961d29e25e3bee5169e11b92fa9f027a8"
+checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5"
 dependencies = [
  "log",
  "rustc-hash",
@@ -4944,7 +5124,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
 dependencies = [
- "semver",
+ "semver 0.9.0",
 ]
 
 [[package]]
@@ -5021,9 +5201,19 @@
 ]
 
 [[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
 name = "sc-basic-authorship"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de86afb63617599821312bda08882451ff2b49d9c45e22513ddff5a07c6d966e"
 dependencies = [
  "futures 0.3.12",
  "futures-timer 3.0.2",
@@ -5045,8 +5235,9 @@
 
 [[package]]
 name = "sc-block-builder"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9862161f9d09d870401c7256c89ad1eb3afa56a61f7d7135c2bac76ff7152955"
 dependencies = [
  "parity-scale-codec",
  "sc-client-api",
@@ -5062,10 +5253,11 @@
 
 [[package]]
 name = "sc-chain-spec"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50d97030776b49bc9c109e2d349212d8f2500637761048e1af5b7ce2dfd994c7"
 dependencies = [
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "sc-chain-spec-derive",
  "sc-consensus-babe",
@@ -5083,8 +5275,9 @@
 
 [[package]]
 name = "sc-chain-spec-derive"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f14985513db9798fcedea58bdc8a08f1c6b3a515d6546ced7467b059b7982c4"
 dependencies = [
  "proc-macro-crate",
  "proc-macro2",
@@ -5094,8 +5287,9 @@
 
 [[package]]
 name = "sc-cli"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ec1647b5c1483fa05f7f32e436d0e378e2f3d5696a5a30bddf66f5faf28acb4"
 dependencies = [
  "chrono",
  "fdlimit",
@@ -5132,8 +5326,9 @@
 
 [[package]]
 name = "sc-client-api"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56d8b2c8dc0cee9ac56e87ad50c980edbdeb35bdd5b5d9da4ae90567423363be"
 dependencies = [
  "derive_more",
  "fnv",
@@ -5166,8 +5361,9 @@
 
 [[package]]
 name = "sc-client-db"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5741e447d71ff36c147f961b2271b6b3fad0cc347e96936bc8b63ddffa594b27"
 dependencies = [
  "blake2-rfc",
  "hash-db",
@@ -5196,8 +5392,9 @@
 
 [[package]]
 name = "sc-consensus"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99f20cc8b8a74e218365ac4187bce26ea631d58d221caa1797bc6ec8056dba33"
 dependencies = [
  "sc-client-api",
  "sp-blockchain",
@@ -5207,8 +5404,9 @@
 
 [[package]]
 name = "sc-consensus-aura"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e0d32ccddef567a0fe373729aa4da51b2d437cbb102b9810400c9e77e040c1d"
 dependencies = [
  "derive_more",
  "futures 0.3.12",
@@ -5226,6 +5424,7 @@
  "sp-blockchain",
  "sp-consensus",
  "sp-consensus-aura",
+ "sp-consensus-slots",
  "sp-core",
  "sp-inherents",
  "sp-io",
@@ -5238,8 +5437,9 @@
 
 [[package]]
 name = "sc-consensus-babe"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98d52048476e0fcb53feae8ca919a602104f1ba0b89a729b496440f36b332961"
 dependencies = [
  "derive_more",
  "fork-tree",
@@ -5269,6 +5469,7 @@
  "sp-blockchain",
  "sp-consensus",
  "sp-consensus-babe",
+ "sp-consensus-slots",
  "sp-consensus-vrf",
  "sp-core",
  "sp-inherents",
@@ -5283,8 +5484,9 @@
 
 [[package]]
 name = "sc-consensus-epochs"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "326313ffb249a526e8ee8e08af9fdf0c4459cebeaa760b934e9df3985b68e4df"
 dependencies = [
  "fork-tree",
  "parity-scale-codec",
@@ -5296,8 +5498,9 @@
 
 [[package]]
 name = "sc-consensus-slots"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76e09ff8b680d449102da9717a70c3bbbbb981fd4cf1bfbafc1739d954eb0898"
 dependencies = [
  "futures 0.3.12",
  "futures-timer 3.0.2",
@@ -5322,8 +5525,9 @@
 
 [[package]]
 name = "sc-consensus-uncles"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37294bae6d787eecf2b15255dc75cd559b4ad813e0efcf28cd4423e218931b80"
 dependencies = [
  "log",
  "sc-client-api",
@@ -5336,15 +5540,16 @@
 
 [[package]]
 name = "sc-executor"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bace6a35999d2da7311d8fb98a29c1e89dbf0d14e50ac14140f2c38089819f46"
 dependencies = [
  "derive_more",
  "lazy_static",
  "libsecp256k1",
  "log",
  "parity-scale-codec",
- "parity-wasm",
+ "parity-wasm 0.41.0",
  "parking_lot 0.11.1",
  "sc-executor-common",
  "sc-executor-wasmi",
@@ -5365,12 +5570,13 @@
 
 [[package]]
 name = "sc-executor-common"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87004102a8e95f432f1c624c7fa7fb0edc5995db2e0fcbabbb697f1955e7c1d2"
 dependencies = [
  "derive_more",
  "parity-scale-codec",
- "parity-wasm",
+ "parity-wasm 0.41.0",
  "sp-allocator",
  "sp-core",
  "sp-serializer",
@@ -5381,8 +5587,9 @@
 
 [[package]]
 name = "sc-executor-wasmi"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d3d7b6db2df5f2c24848883a855a8276363f00cef5b49744974f7e1203bf274"
 dependencies = [
  "log",
  "parity-scale-codec",
@@ -5396,12 +5603,13 @@
 
 [[package]]
 name = "sc-executor-wasmtime"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24673c981fad2dff4398a09a1086579e2774f18d81639fa2bd9cb215e6dd9e36"
 dependencies = [
  "log",
  "parity-scale-codec",
- "parity-wasm",
+ "parity-wasm 0.41.0",
  "pwasm-utils 0.14.0",
  "sc-executor-common",
  "scoped-tls",
@@ -5414,8 +5622,9 @@
 
 [[package]]
 name = "sc-finality-grandpa"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7e87e63c57933e173a8643ff197b579e3fc5c91b16ca006096f482de8159318"
 dependencies = [
  "derive_more",
  "finality-grandpa",
@@ -5426,7 +5635,7 @@
  "log",
  "parity-scale-codec",
  "parking_lot 0.11.1",
- "pin-project 0.4.27",
+ "pin-project 1.0.5",
  "rand 0.7.3",
  "sc-block-builder",
  "sc-client-api",
@@ -5452,8 +5661,9 @@
 
 [[package]]
 name = "sc-informant"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f4c8994853e1158dc4f448b014aa83eef56ced214ec0af316eecf4a6ca3268f"
 dependencies = [
  "ansi_term 0.12.1",
  "futures 0.3.12",
@@ -5470,8 +5680,9 @@
 
 [[package]]
 name = "sc-keystore"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d966ed36c404eced656bd63aad8a30d2c1a14633f07cd1d7d9c11b62f75a7905"
 dependencies = [
  "async-trait",
  "derive_more",
@@ -5490,8 +5701,9 @@
 
 [[package]]
 name = "sc-light"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04e8dbcb2951f7cf76ddf97ed26dcef0dab79d76745de4a8f169d58236ea8704"
 dependencies = [
  "hash-db",
  "lazy_static",
@@ -5509,8 +5721,9 @@
 
 [[package]]
 name = "sc-network"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20fb4ed5d6b86faafb0743c8c2fd1c89b52cde7697373b254c7553800efaebbf"
 dependencies = [
  "async-std",
  "async-trait",
@@ -5518,6 +5731,7 @@
  "bitflags",
  "bs58",
  "bytes 1.0.1",
+ "cid",
  "derive_more",
  "either",
  "erased-serde",
@@ -5535,7 +5749,7 @@
  "nohash-hasher",
  "parity-scale-codec",
  "parking_lot 0.11.1",
- "pin-project 0.4.27",
+ "pin-project 1.0.5",
  "prost",
  "prost-build",
  "rand 0.7.3",
@@ -5561,8 +5775,9 @@
 
 [[package]]
 name = "sc-network-gossip"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2cd5487d6f8051863a186e2aea4c233a07bb691780d3b117c9d6ffe1ff9a8fe"
 dependencies = [
  "futures 0.3.12",
  "futures-timer 3.0.2",
@@ -5577,8 +5792,9 @@
 
 [[package]]
 name = "sc-offchain"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7bc91fc71c128748a3393cb3421e12a7759ccffcc1cc4a9e6ff4ead6cc68ba48"
 dependencies = [
  "bytes 0.5.6",
  "fnv",
@@ -5604,8 +5820,9 @@
 
 [[package]]
 name = "sc-peerset"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce454e528e7797a239e734d0d66bf904d48be47aa92691ac7546a45ec32a64cf"
 dependencies = [
  "futures 0.3.12",
  "libp2p",
@@ -5617,8 +5834,9 @@
 
 [[package]]
 name = "sc-proposer-metrics"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecfc2c6cc5dc0ecb1109cce9773b50ad9a3cdbf239dc702ef9071949244dcf3e"
 dependencies = [
  "log",
  "substrate-prometheus-endpoint",
@@ -5626,8 +5844,9 @@
 
 [[package]]
 name = "sc-rpc"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "750397c6aa5a4f922cac99599ad74a4082e3e87553d51ceb4c48abfa056ff32c"
 dependencies = [
  "futures 0.3.12",
  "hash-db",
@@ -5660,8 +5879,9 @@
 
 [[package]]
 name = "sc-rpc-api"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc8393410297df2885efec20d0629a9833b4fd9e4ad83a92471e1ea0c11a0a54"
 dependencies = [
  "derive_more",
  "futures 0.3.12",
@@ -5684,8 +5904,9 @@
 
 [[package]]
 name = "sc-rpc-server"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17c76164897bd3b0d04c2d6aeeb4d3492c86e324b0b08f408b847ea35421b589"
 dependencies = [
  "futures 0.1.30",
  "jsonrpc-core",
@@ -5702,10 +5923,11 @@
 
 [[package]]
 name = "sc-service"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9315b44eb991ca4f477d889bbd649a2b4b557f963fe48ec5a36c3422518e4a0"
 dependencies = [
- "directories 3.0.1",
+ "directories",
  "exit-future",
  "futures 0.1.30",
  "futures 0.3.12",
@@ -5718,7 +5940,7 @@
  "parity-scale-codec",
  "parity-util-mem",
  "parking_lot 0.11.1",
- "pin-project 0.4.27",
+ "pin-project 1.0.5",
  "rand 0.7.3",
  "sc-block-builder",
  "sc-chain-spec",
@@ -5765,8 +5987,9 @@
 
 [[package]]
 name = "sc-state-db"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f144043d5860ce133f701fa78679d6278f2dfc698686beb5f6d892c267e9d92"
 dependencies = [
  "log",
  "parity-scale-codec",
@@ -5780,15 +6003,16 @@
 
 [[package]]
 name = "sc-telemetry"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d05040c594b331d90d7341e82c6dc6a3eb7bb2afb4e5dc9c36a79a6754166057"
 dependencies = [
  "chrono",
  "futures 0.3.12",
  "libp2p",
  "log",
  "parking_lot 0.11.1",
- "pin-project 0.4.27",
+ "pin-project 1.0.5",
  "rand 0.7.3",
  "serde",
  "serde_json",
@@ -5802,8 +6026,9 @@
 
 [[package]]
 name = "sc-tracing"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef0a4aa327b8bc89d9c5ae57a2f493d8f54ccd706f6763614ab522559fe481d8"
 dependencies = [
  "ansi_term 0.12.1",
  "atty",
@@ -5830,8 +6055,9 @@
 
 [[package]]
 name = "sc-tracing-proc-macro"
-version = "2.0.0"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec18b0506911e6d624d9ea8f8cc5f503e7944a0fe7d37de95ee84033cf160ebc"
 dependencies = [
  "proc-macro-crate",
  "proc-macro2",
@@ -5841,8 +6067,9 @@
 
 [[package]]
 name = "sc-transaction-graph"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87b385b8f66cce185478c500ad3de8f4775ab0e948c31561aeac78a27bedc654"
 dependencies = [
  "derive_more",
  "futures 0.3.12",
@@ -5863,8 +6090,9 @@
 
 [[package]]
 name = "sc-transaction-pool"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09f4331ea8da2ff45a9466637f90f5cc89f9d31fcd1cd20f74f2520b33bff069"
 dependencies = [
  "futures 0.3.12",
  "futures-diagnose",
@@ -5992,11 +6220,30 @@
 
 [[package]]
 name = "semver"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
+dependencies = [
+ "semver-parser 0.7.0",
+]
+
+[[package]]
+name = "semver"
 version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
 dependencies = [
- "semver-parser",
+ "semver-parser 0.7.0",
+]
+
+[[package]]
+name = "semver"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
+dependencies = [
+ "semver-parser 0.10.2",
+ "serde",
 ]
 
 [[package]]
@@ -6006,6 +6253,15 @@
 checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 
 [[package]]
+name = "semver-parser"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
+dependencies = [
+ "pest",
+]
+
+[[package]]
 name = "serde"
 version = "1.0.123"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6147,7 +6403,7 @@
  "approx",
  "num-complex",
  "num-traits",
- "paste",
+ "paste 0.1.18",
 ]
 
 [[package]]
@@ -6218,8 +6474,9 @@
 
 [[package]]
 name = "sp-allocator"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec5f988ad0cabdb646318cb515a91e9d89062debc9728f9b634d73acab3f3f39"
 dependencies = [
  "log",
  "sp-core",
@@ -6230,8 +6487,9 @@
 
 [[package]]
 name = "sp-api"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e63c3460d5daecf67df542c34c2bbd636214a5a200d4bddcfa2ffb9e72c346af"
 dependencies = [
  "hash-db",
  "parity-scale-codec",
@@ -6246,8 +6504,9 @@
 
 [[package]]
 name = "sp-api-proc-macro"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "289624f4fe0f61e63a5019ed26c3bc732b5145eb52796ac6053cd72656d947a1"
 dependencies = [
  "blake2-rfc",
  "proc-macro-crate",
@@ -6258,8 +6517,9 @@
 
 [[package]]
 name = "sp-application-crypto"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c52e2e6d43036b97c4fce1ed87c5262c1ffdc78c655ada4d3024a3f8094bdd2c"
 dependencies = [
  "parity-scale-codec",
  "serde",
@@ -6270,8 +6530,9 @@
 
 [[package]]
 name = "sp-arithmetic"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0f1c69966c192d1dee8521f0b29ece2b14db07b9b44d801a94e295234761645"
 dependencies = [
  "integer-sqrt",
  "num-traits",
@@ -6283,8 +6544,9 @@
 
 [[package]]
 name = "sp-authorship"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ec68fb8e5a37548b06c14ee91a9c574cc330324c86d37810ec29dd4f8bc68d7"
 dependencies = [
  "parity-scale-codec",
  "sp-inherents",
@@ -6294,8 +6556,9 @@
 
 [[package]]
 name = "sp-block-builder"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0adc979dbe619f56d664ebd1293dce13fcad6b8a47bcdd620ed53a454d330d12"
 dependencies = [
  "parity-scale-codec",
  "sp-api",
@@ -6306,8 +6569,9 @@
 
 [[package]]
 name = "sp-blockchain"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8007c1ad8e9fb6cd8eed4e0fc91504a9ca4b228e1315302a2fbb0ac7f509f1b"
 dependencies = [
  "futures 0.3.12",
  "log",
@@ -6324,8 +6588,9 @@
 
 [[package]]
 name = "sp-chain-spec"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a24beb11980d0c755ead0c05f3f966c490e4a3730785c04c03855fada65d697"
 dependencies = [
  "serde",
  "serde_json",
@@ -6333,8 +6598,9 @@
 
 [[package]]
 name = "sp-consensus"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "884db6c4b03f0f2fb2993127a2db95fc740fcd3496746dcaa6829c9868e7dc75"
 dependencies = [
  "futures 0.3.12",
  "futures-timer 3.0.2",
@@ -6359,12 +6625,14 @@
 
 [[package]]
 name = "sp-consensus-aura"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bd00fc95b26393522be1394fb67cc536736cc5a902dec0d3e2827909b7c1118"
 dependencies = [
  "parity-scale-codec",
  "sp-api",
  "sp-application-crypto",
+ "sp-consensus-slots",
  "sp-inherents",
  "sp-runtime",
  "sp-std",
@@ -6373,8 +6641,9 @@
 
 [[package]]
 name = "sp-consensus-babe"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a153085b1542b5cbe23686433cd36d1a634964f1b707671d0ffb01d8d9313047"
 dependencies = [
  "merlin",
  "parity-scale-codec",
@@ -6393,17 +6662,20 @@
 
 [[package]]
 name = "sp-consensus-slots"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32bd501ab76c827d74f145063cd8cb993a9f634dac93c9b0d909111cd5900a6a"
 dependencies = [
  "parity-scale-codec",
+ "sp-arithmetic",
  "sp-runtime",
 ]
 
 [[package]]
 name = "sp-consensus-vrf"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "030895d70bf3095c857f4727a7cce7c43af29efe3413bb547ee28700f7d78766"
 dependencies = [
  "parity-scale-codec",
  "schnorrkel",
@@ -6414,8 +6686,9 @@
 
 [[package]]
 name = "sp-core"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abbc8d4e9b8a7d5819ed26f1374017bb32833ef4890e4ff065e1da30669876bc"
 dependencies = [
  "base58",
  "blake2-rfc",
@@ -6458,8 +6731,9 @@
 
 [[package]]
 name = "sp-database"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8c3f018913eef191d95c824657c5759c459d28670e654fa34f5d9bd5e6f0492"
 dependencies = [
  "kvdb",
  "parking_lot 0.11.1",
@@ -6467,8 +6741,9 @@
 
 [[package]]
 name = "sp-debug-derive"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e80275f23b4e7ba8f54dec5f90f016530e7307d2ee9445f617ab986cbe97f31e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -6477,8 +6752,9 @@
 
 [[package]]
 name = "sp-externalities"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2fdc625f8c7b13b9a136d334888b21b5743d2081cb666cb03efca1dc9b8f74d1"
 dependencies = [
  "environmental",
  "parity-scale-codec",
@@ -6488,8 +6764,9 @@
 
 [[package]]
 name = "sp-finality-grandpa"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "702e0be150e1b557df42326ec9b82c2010366631d03be27c69912d446abbf87a"
 dependencies = [
  "finality-grandpa",
  "log",
@@ -6505,8 +6782,9 @@
 
 [[package]]
 name = "sp-inherents"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2542380b535c6941502a0a3069a657eb5abb70fd67b11afa164d4a4b038ba73a"
 dependencies = [
  "parity-scale-codec",
  "parking_lot 0.11.1",
@@ -6517,8 +6795,9 @@
 
 [[package]]
 name = "sp-io"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33fd69f0a6e91bedc2fb1c5cc3689c212474b6c918274cb4cb14dbbe3c428c14"
 dependencies = [
  "futures 0.3.12",
  "hash-db",
@@ -6541,8 +6820,9 @@
 
 [[package]]
 name = "sp-keyring"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b59f2b0e94b2048d4984aa6eb40eef2e4c05d3adf27a083dd3c9b0fce74ef7a"
 dependencies = [
  "lazy_static",
  "sp-core",
@@ -6552,8 +6832,9 @@
 
 [[package]]
 name = "sp-keystore"
-version = "0.8.0"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db6ccd2baf189112355338e8b224dc513cd239b974dbd717f12b3dc7a7248c3b"
 dependencies = [
  "async-trait",
  "derive_more",
@@ -6569,8 +6850,9 @@
 
 [[package]]
 name = "sp-offchain"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bd80eedcedcc8342e77c26d59ad90b6904715a862731fa16616650773570e63"
 dependencies = [
  "sp-api",
  "sp-core",
@@ -6579,16 +6861,18 @@
 
 [[package]]
 name = "sp-panic-handler"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54702e109f1c8a870dd4065a497d2612d42cec5817126e96cc0658c5ea975784"
 dependencies = [
  "backtrace",
 ]
 
 [[package]]
 name = "sp-rpc"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2e5b1ed655d11449073b914b048895f45241e02b3919d1d0187f315435fee18"
 dependencies = [
  "serde",
  "sp-core",
@@ -6596,16 +6880,17 @@
 
 [[package]]
 name = "sp-runtime"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfa4b353b76f04616dbdb8d269d58dcac47acb31c006d3b70e7b64233e68695e"
 dependencies = [
  "either",
  "hash256-std-hasher",
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "log",
  "parity-scale-codec",
  "parity-util-mem",
- "paste",
+ "paste 1.0.4",
  "rand 0.7.3",
  "serde",
  "sp-application-crypto",
@@ -6617,10 +6902,11 @@
 
 [[package]]
 name = "sp-runtime-interface"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2e5c88b4bc8d607e4e2ff767a85db58cf7101f3dd6064f06929342ea67fe8fb"
 dependencies = [
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "primitive-types",
  "sp-externalities",
@@ -6634,8 +6920,9 @@
 
 [[package]]
 name = "sp-runtime-interface-proc-macro"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19a6c7c2251512c9e533d15db8a863b06ece1cbee778130dd9adbe44b6b39aa9"
 dependencies = [
  "Inflector",
  "proc-macro-crate",
@@ -6646,8 +6933,9 @@
 
 [[package]]
 name = "sp-sandbox"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e92caf4555d676d8f0b67def0041da789f79a5d5f341130496f15a6261926cc"
 dependencies = [
  "parity-scale-codec",
  "sp-core",
@@ -6659,8 +6947,9 @@
 
 [[package]]
 name = "sp-serializer"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "982d793f01eb9eea9f30ffc63b821170068b9f0d9edf715d8ba77dc4de9c300f"
 dependencies = [
  "serde",
  "serde_json",
@@ -6668,8 +6957,9 @@
 
 [[package]]
 name = "sp-session"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c7cf161533725a78083b04f3269effe4c3b4b6ce5f655019b3eec3e729ba4d4"
 dependencies = [
  "parity-scale-codec",
  "sp-api",
@@ -6681,8 +6971,9 @@
 
 [[package]]
 name = "sp-staking"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc729eb10f8809c61a1fe439ac118a4413de004aaf863003ee8752ac0b596e73"
 dependencies = [
  "parity-scale-codec",
  "sp-runtime",
@@ -6691,8 +6982,9 @@
 
 [[package]]
 name = "sp-state-machine"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46fa4143e58e9130f726d4e8a9b86f3530a8bd19a2eedcdcf4af205f4b5a6d4f"
 dependencies = [
  "hash-db",
  "log",
@@ -6713,13 +7005,15 @@
 
 [[package]]
 name = "sp-std"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35391ea974fa5ee869cb094d5b437688fbf3d8127d64d1b9fed5822a1ed39b12"
 
 [[package]]
 name = "sp-storage"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86af458d4a0251c490cdde9dcaaccb88d398f3b97ac6694cdd49ed9337e6b961"
 dependencies = [
  "impl-serde",
  "parity-scale-codec",
@@ -6731,8 +7025,9 @@
 
 [[package]]
 name = "sp-tasks"
-version = "2.0.0"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c585340cbee96c53a9b43fd07d81edf6cebeb80e4ca7c0ee79b856c0b1883a0e"
 dependencies = [
  "log",
  "sp-core",
@@ -6744,10 +7039,11 @@
 
 [[package]]
 name = "sp-timestamp"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27387c541197b9f47f3d9ddcab5649a3ecdca582d2f2ea2b511af24a3d3cbf83"
 dependencies = [
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "sp-api",
  "sp-inherents",
@@ -6758,8 +7054,9 @@
 
 [[package]]
 name = "sp-tracing"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567382d8d4e14fb572752863b5cd57a78f9e9a6583332b590b726f061f3ea957"
 dependencies = [
  "log",
  "parity-scale-codec",
@@ -6771,8 +7068,9 @@
 
 [[package]]
 name = "sp-transaction-pool"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3264d3b7ea31483eddffa2cc7f28c4d9c022598e456a985fd1cb5879a4609853"
 dependencies = [
  "derive_more",
  "futures 0.3.12",
@@ -6787,8 +7085,9 @@
 
 [[package]]
 name = "sp-trie"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b85b7f745da41ef825c6f7b93f1fdc897b03df94a4884adfbb70fbcd0aed1298"
 dependencies = [
  "hash-db",
  "memory-db",
@@ -6801,8 +7100,9 @@
 
 [[package]]
 name = "sp-utils"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ec2a5f924f7affd1e959f8f3c02bd87cdfa0e11c71a4cbc075f955ead8c1a1"
 dependencies = [
  "futures 0.3.12",
  "futures-core",
@@ -6813,8 +7113,9 @@
 
 [[package]]
 name = "sp-version"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbeffa538a13d715d30e01d57a2636ba32845b737a29a3ea32403576588222e7"
 dependencies = [
  "impl-serde",
  "parity-scale-codec",
@@ -6825,10 +7126,11 @@
 
 [[package]]
 name = "sp-wasm-interface"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b214e125666a6416cf30a70cc6a5dacd34a4e5197f8a3d479f714af7e1dc7a47"
 dependencies = [
- "impl-trait-for-tuples 0.2.1",
+ "impl-trait-for-tuples",
  "parity-scale-codec",
  "sp-std",
  "wasmi",
@@ -6912,18 +7214,18 @@
 
 [[package]]
 name = "strum"
-version = "0.16.0"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6138f8f88a16d90134763314e3fc76fa3ed6a7db4725d6acf9a3ef95a3188d22"
+checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c"
 dependencies = [
  "strum_macros",
 ]
 
 [[package]]
 name = "strum_macros"
-version = "0.16.0"
+version = "0.20.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0054a7df764039a6cd8592b9de84be4bec368ff081d203a7d5371cbfa8e65c81"
+checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -6946,16 +7248,18 @@
 
 [[package]]
 name = "substrate-build-script-utils"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd540ba72520174c2c73ce96bf507eeba3cc8a481f58be92525b69110e1fa645"
 dependencies = [
  "platforms",
 ]
 
 [[package]]
 name = "substrate-frame-rpc-system"
-version = "2.0.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e46123ec4a690d91967de07cd6af4dde90d14519a1a8d43f61bd3f78dd3d0ef"
 dependencies = [
  "frame-system-rpc-runtime-api",
  "futures 0.3.12",
@@ -6977,8 +7281,9 @@
 
 [[package]]
 name = "substrate-prometheus-endpoint"
-version = "0.8.1"
-source = "git+https://github.com/usetech-llc/substrate.git?branch=unique#0e070672cf7a7bec72fb3f26188915cfb43c440f"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2eb561c19a121e1c89daa79dbfa67a55080f813caa47fd231833a0669696d508"
 dependencies = [
  "async-std",
  "derive_more",
@@ -6990,10 +7295,20 @@
 ]
 
 [[package]]
-name = "substrate-wasm-builder-runner"
-version = "1.0.6"
+name = "substrate-wasm-builder"
+version = "4.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2a965994514ab35d3893e9260245f2947fd1981cdd4fffd2c6e6d1a9ce02e6a"
+checksum = "93a3d51ad6abbc408b03ea962062bfcc959b438a318d7d4bedd181e1effd0610"
+dependencies = [
+ "ansi_term 0.12.1",
+ "atty",
+ "build-helper",
+ "cargo_metadata",
+ "tempfile",
+ "toml",
+ "walkdir",
+ "wasm-gc-api",
+]
 
 [[package]]
 name = "subtle"
@@ -7037,10 +7352,16 @@
 checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
 
 [[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
+[[package]]
 name = "target-lexicon"
-version = "0.10.0"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"
+checksum = "422045212ea98508ae3d28025bc5aaa2bd4a9cdaecd442a08da2ee620ee9ea95"
 
 [[package]]
 name = "tempfile"
@@ -7752,6 +8073,17 @@
 checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
 
 [[package]]
+name = "walkdir"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
+dependencies = [
+ "same-file",
+ "winapi 0.3.9",
+ "winapi-util",
+]
+
+[[package]]
 name = "want"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -7851,6 +8183,17 @@
 checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64"
 
 [[package]]
+name = "wasm-gc-api"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0c32691b6c7e6c14e7f8fd55361a9088b507aa49620fcd06c09b3a1082186b9"
+dependencies = [
+ "log",
+ "parity-wasm 0.32.0",
+ "rustc-demangle",
+]
+
+[[package]]
 name = "wasm-timer"
 version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -7875,7 +8218,7 @@
  "memory_units",
  "num-rational",
  "num-traits",
- "parity-wasm",
+ "parity-wasm 0.41.0",
  "wasmi-validation",
 ]
 
@@ -7885,38 +8228,36 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ea78c597064ba73596099281e2f4cfc019075122a65cdda3205af94f0b264d93"
 dependencies = [
- "parity-wasm",
+ "parity-wasm 0.41.0",
 ]
 
 [[package]]
 name = "wasmparser"
-version = "0.57.0"
+version = "0.71.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6"
-
-[[package]]
-name = "wasmparser"
-version = "0.59.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a950e6a618f62147fd514ff445b2a0b53120d382751960797f85f058c7eda9b9"
+checksum = "89a30c99437829ede826802bfcf28500cf58df00e66cb9114df98813bc145ff1"
 
 [[package]]
 name = "wasmtime"
-version = "0.19.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cd3c4f449382779ef6e0a7c3ec6752ae614e20a42e4100000c3efdc973100e2"
+checksum = "7426055cb92bd9a1e9469b48154d8d6119cd8c498c8b70284e420342c05dc45d"
 dependencies = [
  "anyhow",
  "backtrace",
- "cfg-if 0.1.10",
- "lazy_static",
+ "bincode",
+ "cfg-if 1.0.0",
+ "cpp_demangle",
+ "indexmap",
  "libc",
  "log",
  "region",
  "rustc-demangle",
+ "serde",
  "smallvec 1.6.1",
  "target-lexicon",
- "wasmparser 0.59.0",
+ "wasmparser",
+ "wasmtime-cache",
  "wasmtime-environ",
  "wasmtime-jit",
  "wasmtime-profiling",
@@ -7926,73 +8267,100 @@
 ]
 
 [[package]]
+name = "wasmtime-cache"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c01d9287e36921e46f5887a47007824ae5dbb9b7517a2d565660ab4471478709"
+dependencies = [
+ "anyhow",
+ "base64 0.13.0",
+ "bincode",
+ "directories-next",
+ "errno",
+ "file-per-thread-logger",
+ "libc",
+ "log",
+ "serde",
+ "sha2 0.9.3",
+ "toml",
+ "winapi 0.3.9",
+ "zstd",
+]
+
+[[package]]
+name = "wasmtime-cranelift"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4134ed3a4316cd0de0e546c6004850afe472b0fa3fcdc2f2c15f8d449562d962"
+dependencies = [
+ "cranelift-codegen",
+ "cranelift-entity",
+ "cranelift-frontend",
+ "cranelift-wasm",
+ "wasmtime-environ",
+]
+
+[[package]]
 name = "wasmtime-debug"
-version = "0.19.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e634af9067a3af6cf2c7d33dc3b84767ddaf5d010ba68e80eecbcea73d4a349"
+checksum = "e91fa931df6dd8af2b02606307674d3bad23f55473d5f4c809dddf7e4c4dc411"
 dependencies = [
  "anyhow",
- "gimli 0.21.0",
+ "gimli",
  "more-asserts",
- "object 0.20.0",
+ "object 0.22.0",
  "target-lexicon",
  "thiserror",
- "wasmparser 0.59.0",
+ "wasmparser",
  "wasmtime-environ",
 ]
 
 [[package]]
 name = "wasmtime-environ"
-version = "0.19.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08f85619a94ee4034bd5bb87fc3dcf71fd2237b81c840809da1201061eec9ab3"
+checksum = "a1098871dc3120aaf8190d79153e470658bb79f63ee9ca31716711e123c28220"
 dependencies = [
  "anyhow",
- "base64 0.12.3",
- "bincode",
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "cranelift-codegen",
  "cranelift-entity",
- "cranelift-frontend",
  "cranelift-wasm",
- "directories 2.0.2",
- "errno",
- "file-per-thread-logger",
+ "gimli",
  "indexmap",
- "libc",
  "log",
  "more-asserts",
- "rayon",
  "serde",
- "sha2 0.8.2",
  "thiserror",
- "toml",
- "wasmparser 0.59.0",
- "winapi 0.3.9",
- "zstd",
+ "wasmparser",
 ]
 
 [[package]]
 name = "wasmtime-jit"
-version = "0.19.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e914c013c7a9f15f4e429d5431f2830fb8adb56e40567661b69c5ec1d645be23"
+checksum = "738bfcd1561ede8bb174215776fd7d9a95d5f0a47ca3deabe0282c55f9a89f68"
 dependencies = [
+ "addr2line",
  "anyhow",
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "cranelift-codegen",
  "cranelift-entity",
  "cranelift-frontend",
  "cranelift-native",
  "cranelift-wasm",
- "gimli 0.21.0",
+ "gimli",
  "log",
  "more-asserts",
- "object 0.20.0",
+ "object 0.22.0",
+ "rayon",
  "region",
+ "serde",
  "target-lexicon",
  "thiserror",
- "wasmparser 0.59.0",
+ "wasmparser",
+ "wasmtime-cranelift",
  "wasmtime-debug",
  "wasmtime-environ",
  "wasmtime-obj",
@@ -8003,13 +8371,13 @@
 
 [[package]]
 name = "wasmtime-obj"
-version = "0.19.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e81d8e02e9bc9fe2da9b6d48bbc217f96e089f7df613f11a28a3958abc44641e"
+checksum = "3e96d77f1801131c5e86d93e42a3cf8a35402107332c202c245c83f34888a906"
 dependencies = [
  "anyhow",
  "more-asserts",
- "object 0.20.0",
+ "object 0.22.0",
  "target-lexicon",
  "wasmtime-debug",
  "wasmtime-environ",
@@ -8017,16 +8385,16 @@
 
 [[package]]
 name = "wasmtime-profiling"
-version = "0.19.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e8d4d1af8dd5f7096cfcc89dd668d358e52980c38cce199643372ffd6590e27"
+checksum = "60bb672c9d894776d7b9250dd9b4fe890f8760201ee4f53e5f2da772b6c4debb"
 dependencies = [
  "anyhow",
- "cfg-if 0.1.10",
- "gimli 0.21.0",
+ "cfg-if 1.0.0",
+ "gimli",
  "lazy_static",
  "libc",
- "object 0.19.0",
+ "object 0.22.0",
  "scroll",
  "serde",
  "target-lexicon",
@@ -8036,19 +8404,20 @@
 
 [[package]]
 name = "wasmtime-runtime"
-version = "0.19.0"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a25f140bbbaadb07c531cba99ce1a966dba216138dc1b2a0ddecec851a01a93"
+checksum = "a978086740949eeedfefcee667b57a9e98d9a7fc0de382fcfa0da30369e3530d"
 dependencies = [
  "backtrace",
  "cc",
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "indexmap",
  "lazy_static",
  "libc",
  "log",
- "memoffset 0.5.6",
+ "memoffset 0.6.1",
  "more-asserts",
+ "psm",
  "region",
  "thiserror",
  "wasmtime-environ",
@@ -8184,6 +8553,12 @@
 ]
 
 [[package]]
+name = "wyz"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
+
+[[package]]
 name = "x25519-dalek"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
modifiedDockerfilediffbeforeafterboth
--- a/Dockerfile
+++ b/Dockerfile
@@ -3,8 +3,8 @@
 FROM phusion/baseimage:18.04-1.0.0 as builder
 LABEL maintainer="UniqueNetwork.io"
 
-ENV WASM_TOOLCHAIN=nightly-2021-01-27
-ENV NATIVE_TOOLCHAIN=1.49.0
+ENV WASM_TOOLCHAIN=nightly-2021-03-01
+# ENV NATIVE_TOOLCHAIN=1.50.0
 
 ARG PROFILE=release
 
@@ -25,10 +25,10 @@
 RUN export PATH="/cargo-home/bin:$PATH" && \
     export CARGO_HOME="/cargo-home" && \
 	rustup toolchain uninstall $(rustup toolchain list) && \
-	rustup toolchain install $NATIVE_TOOLCHAIN && \
+	# rustup toolchain install $NATIVE_TOOLCHAIN && \
 	rustup toolchain install $WASM_TOOLCHAIN && \
 	rustup target add wasm32-unknown-unknown --toolchain $WASM_TOOLCHAIN && \
-	rustup default $NATIVE_TOOLCHAIN && \
+	rustup default $WASM_TOOLCHAIN && \
     rustup target list --installed && \
     rustup show
 
modifiedREADME.mddiffbeforeafterboth
--- a/README.md
+++ b/README.md
@@ -63,18 +63,17 @@
 
 2. Remove all installed toolchains with `rustup toolchain list` and `rustup toolchain uninstall <toolchain>`.
 
-3. Install stable toolchain 1.49.0 and make it default, install nightly 2021-01-27:
+3. Install install nightly 2021-03-01 and make it default:
 
 ```bash
-rustup toolchain install 1.49.0
-rustup toolchain install nightly-2020-01-27
-rustup default nightly-2021-01-27
+rustup toolchain install nightly-2021-03-01
+rustup default nightly-2021-03-01
 ```
 
 4. Add wasm target for nightly toolchain:
 
 ```bash
-rustup target add wasm32-unknown-unknown --toolchain nightly-2021-01-27
+rustup target add wasm32-unknown-unknown --toolchain nightly-2021-03-01
 ```
 
 5. Build:
modifiednode/Cargo.tomldiffbeforeafterboth
--- a/node/Cargo.toml
+++ b/node/Cargo.toml
@@ -1,7 +1,5 @@
-[build-dependencies.substrate-build-script-utils]
-git = 'https://github.com/usetech-llc/substrate.git'
-branch = 'unique'
-version = '2.0.1'
+[build-dependencies]
+substrate-build-script-utils = '3.0.0'
 
 [[bin]]
 name = 'nft'
@@ -29,36 +27,37 @@
 jsonrpc-core = '15.0.0'
 
 # Substrate dependencies
-nft-runtime = { path = '../runtime', version = '2.1.0' }
-frame-benchmarking = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-frame-benchmarking-cli = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-pallet-transaction-payment-rpc = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sc-basic-authorship = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sc-cli = { features = ['wasmtime'], version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sc-client-api = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sc-consensus = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sc-consensus-aura = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sc-executor = { features = ['wasmtime'], version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sc-finality-grandpa = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sc-rpc = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sc-rpc-api = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sc-service = { features = ['wasmtime'], version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sc-transaction-pool = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sp-api = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sp-block-builder = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sp-blockchain = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sp-consensus = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sp-consensus-aura = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sp-core = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sp-finality-grandpa = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sp-inherents = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sp-runtime = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sp-transaction-pool = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-sc-network = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} 
-substrate-frame-rpc-system = {version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'}
-pallet-contracts-rpc = {version = '0.8.0', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique'} 
-sc-keystore = { version = "2.0.0", git = "https://github.com/usetech-llc/substrate.git", branch = 'unique'}
-sc-telemetry = { version = "2.0.0", git = "https://github.com/usetech-llc/substrate.git", branch = 'unique'}
+nft-runtime = { path = '../runtime', version = '3.0.0' }
+frame-benchmarking = '3.0.0'
+frame-benchmarking-cli = '3.0.0'
+pallet-transaction-payment-rpc = '3.0.0'
+sc-basic-authorship = '0.9.0'
+sc-cli = { features = ['wasmtime'], version = '0.9.0' }
+sc-client-api = '3.0.0'
+sc-consensus = '0.9.0'
+sc-consensus-aura = '0.9.0'
+sc-executor = { features = ['wasmtime'], version = '0.9.0' }
+sc-finality-grandpa = '0.9.0'
+
+sc-keystore = '3.0.0'
+sc-rpc = '3.0.0'
+sc-rpc-api = '0.9.0'
+sc-service = { features = ['wasmtime'], version = '0.9.0' }
+sc-transaction-pool = '3.0.0'
+sp-api = '3.0.0'
+sp-block-builder = '3.0.0'
+sp-blockchain = '3.0.0'
+sp-consensus = '0.9.0'
+sp-consensus-aura = '0.9.0'
+sp-core = '3.0.0'
+sp-finality-grandpa = '3.0.0'
+sp-inherents = '3.0.0'
+sp-runtime = '3.0.0'
+sp-transaction-pool = '3.0.0'
+substrate-frame-rpc-system = '3.0.0'
+sc-network = '0.9.0'
+pallet-contracts-rpc = '3.0.0'
+sc-telemetry = '3.0.0'
 
 serde = { version = "1.0.102", features = ["derive"] }
 serde_json = "1.0.41"
modifiednode/src/chain_spec.rsdiffbeforeafterboth
--- a/node/src/chain_spec.rs
+++ b/node/src/chain_spec.rs
@@ -15,6 +15,7 @@
 use sp_finality_grandpa::AuthorityId as GrandpaId;
 use sp_runtime::traits::{IdentifyAccount, Verify};
 use serde_json::map::Map;
+// use crate::chain_spec::api::chain_extension::*;
 
 // Note this is the URL for the telemetry server
 //const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
modifiednode/src/service.rsdiffbeforeafterboth
--- a/node/src/service.rs
+++ b/node/src/service.rs
@@ -16,7 +16,6 @@
 use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair};
 use sc_finality_grandpa::SharedVoterState;
 use sc_keystore::LocalKeystore;
-use sc_telemetry::TelemetrySpan;
 
 // Our native executor instance.
 native_executor_instance!(
@@ -42,7 +41,6 @@
 			AuraPair
 		>,
 		sc_finality_grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
-		Option<TelemetrySpan>,
 	)
 >, ServiceError> {
 	if config.keystore_remote.is_some() {
@@ -51,7 +49,7 @@
 	}
 	let inherent_data_providers = sp_inherents::InherentDataProviders::new();
 
-	let (client, backend, keystore_container, task_manager, telemetry_span) =
+	let (client, backend, keystore_container, task_manager) =
 		sc_service::new_full_parts::<Block, RuntimeApi, Executor>(&config)?;
 	let client = Arc::new(client);
 
@@ -59,6 +57,7 @@
 
 	let transaction_pool = sc_transaction_pool::BasicPool::new_full(
 		config.transaction_pool.clone(),
+		config.role.is_authority().into(),
 		config.prometheus_registry(),
 		task_manager.spawn_handle(),
 		client.clone(),
@@ -84,15 +83,9 @@
 	)?;
 
 	Ok(sc_service::PartialComponents {
-		client,
-		backend,
-		task_manager,
-		import_queue,
-		keystore_container,
-		select_chain,
-		transaction_pool,
+		client, backend, task_manager, import_queue, keystore_container, select_chain, transaction_pool,
 		inherent_data_providers,
-		other: (aura_block_import, grandpa_link, telemetry_span),
+		other: (aura_block_import, grandpa_link),
 	})
 }
 
@@ -106,15 +99,9 @@
 /// Builds a new service for a full client.
 pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError> {
 	let sc_service::PartialComponents {
-		client,
-		backend,
-		mut task_manager,
-		import_queue,
-		mut keystore_container,
-		select_chain,
-		transaction_pool,
+		client, backend, mut task_manager, import_queue, mut keystore_container, select_chain, transaction_pool,
 		inherent_data_providers,
-		other: (block_import, grandpa_link, telemetry_span),
+		other: (block_import, grandpa_link),
 	} = new_partial(&config)?;
 
 	if let Some(url) = &config.keystore_remote {
@@ -182,7 +169,6 @@
 			network_status_sinks,
 			system_rpc_tx,
 			config,
-			telemetry_span,
 		},
 	)?;
 
@@ -197,7 +183,7 @@
 		let can_author_with =
 			sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
 
-		let aura = sc_consensus_aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _,_>(
+		let aura = sc_consensus_aura::start_aura::<_, _, _, _, _, AuraPair, _, _, _, _>(
 			sc_consensus_aura::slot_duration(&*client)?,
 			client.clone(),
 			select_chain,
@@ -262,10 +248,9 @@
 	network_starter.start_network();
 	Ok(task_manager)
 }
-
 /// Builds a new service for a light client.
 pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError> {
-	let (client, backend, keystore_container, mut task_manager, on_demand, telemetry_span) =
+	let (client, backend, keystore_container, mut task_manager, on_demand) =
 		sc_service::new_light_parts::<Block, RuntimeApi, Executor>(&config)?;
 
 	config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config());
@@ -332,7 +317,6 @@
 		network,
 		network_status_sinks,
 		system_rpc_tx,
-		telemetry_span,
 	})?;
 
 	network_starter.start_network();
modifiedpallets/nft/Cargo.tomldiffbeforeafterboth
--- a/pallets/nft/Cargo.toml
+++ b/pallets/nft/Cargo.toml
@@ -6,7 +6,7 @@
 license = 'Unlicense'
 name = 'pallet-nft'
 repository = 'https://github.com/substrate-developer-hub/nft/'
-version = '2.1.0'
+version = '3.0.0'
 
 [package.metadata.docs.rs]
 targets = ['x86_64-unknown-linux-gnu']
@@ -16,101 +16,35 @@
 default-features = false
 features = ['derive']
 package = 'parity-scale-codec'
-version = '1.3.6'
-
-[dependencies.frame-support]
-default-features = false
-git = 'https://github.com/usetech-llc/substrate.git'
-branch = 'unique'
-version = '2.0.1'
-
-[dependencies.frame-system]
-default-features = false
-git = 'https://github.com/usetech-llc/substrate.git'
-branch = 'unique'
-version = '2.0.1'
-
-[dev-dependencies.sp-core]
-default-features = false
-git = 'https://github.com/usetech-llc/substrate.git'
-branch = 'unique'
-version = '2.0.1'
-
-[dev-dependencies.sp-io]
-default-features = false
-git = 'https://github.com/usetech-llc/substrate.git'
-branch = 'unique'
-version = '2.0.1'
+version = '2.0.0'
 
-[dependencies.sp-runtime]
-default-features = false
-git = 'https://github.com/usetech-llc/substrate.git'
-branch = 'unique'
-version = '2.0.1'
-	
 [dependencies]
-# third-party dependencies
-serde = { version = "1.0.102", features = ["derive"] }
-log = "0.4.8"
-
-[dependencies.sp-std]
-default-features = false
-git = 'https://github.com/usetech-llc/substrate.git'
-branch = 'unique'
-version = '2.0.1'
-
-[dependencies.transaction-payment]
-default-features = false
-git = 'https://github.com/usetech-llc/substrate.git'
-package = 'pallet-transaction-payment'
-branch = 'unique'
-version = '2.0.1'
-
-[dependencies.frame-benchmarking]
-version = "2.0.1"
-default-features = false
-git = 'https://github.com/usetech-llc/substrate.git'
-branch = 'unique'
-optional = true
-
-[dependencies.pallet-contracts]
-default-features = false
-git = 'https://github.com/usetech-llc/substrate.git'
-package = 'pallet-contracts'
-branch = 'unique'
-version = '2.0.1'
+serde = { version = "1.0.119" }
+frame-support = { default-features = false, version = '3.0.0' }
+frame-system = { default-features = false, version = '3.0.0' }
+pallet-balances = { default-features = false, version = '3.0.0' }
+pallet-timestamp = { default-features = false, version = '3.0.0' }
+pallet-randomness-collective-flip = { default-features = false, version = '3.0.0' }
+sp-std = { default-features = false, version = '3.0.0' }
+frame-benchmarking = { default-features = false, version = '3.0.0', optional = true }
+sp-core = { default-features = false, version = '3.0.0' }
+sp-io = { default-features = false, version = '3.0.0' }
+sp-runtime = { default-features = false, version = '3.0.0' }
+pallet-contracts = { default-features = false, version = '3.0.0' }
+pallet-transaction-payment = { default-features = false, version = "3.0.0" }
 
-[dependencies.pallet-balances]
-default-features = false
-git = 'https://github.com/usetech-llc/substrate.git'
-package = 'pallet-balances'
-branch = 'unique'
-version = '2.0.1'
-
-[dependencies.pallet-timestamp]
-default-features = false
-git = 'https://github.com/usetech-llc/substrate.git'
-package = 'pallet-timestamp'
-branch = 'unique'
-version = '2.0.1'
-
-[dependencies.pallet-randomness-collective-flip]
-default-features = false
-git = 'https://github.com/usetech-llc/substrate.git'
-package = 'pallet-randomness-collective-flip'
-branch = 'unique'
-version = '2.0.1'
-
 [features]
 default = ['std']
 std = [
     'codec/std',
-    "serde/std",
+    'serde/std',
     'frame-support/std',
     'frame-system/std',
     'pallet-balances/std',
     'pallet-timestamp/std',
+    'pallet-contracts/std',
     'pallet-randomness-collective-flip/std',
+    'pallet-transaction-payment/std',
     'sp-std/std',
     'sp-runtime/std',
     'frame-benchmarking/std',
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
before · pallets/nft/src/lib.rs
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56#![recursion_limit = "1024"]78#![cfg_attr(not(feature = "std"), no_std)]910#[cfg(feature = "std")]11pub use std::*;1213#[cfg(feature = "std")]14pub use serde::*;1516use codec::{Decode, Encode};17pub use frame_support::{18    construct_runtime, decl_event, decl_module, decl_storage, decl_error,19    dispatch::DispatchResult,20    ensure, fail, parameter_types,21    traits::{22        Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,23        Randomness, IsSubType,24    },25    weights::{26        constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},27        DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,28        WeightToFeePolynomial, DispatchClass,29    },30    StorageValue,31};3233use frame_system::{self as system, ensure_signed, ensure_root};34use sp_runtime::sp_std::prelude::Vec;35use sp_runtime::{36    traits::{37        DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion, SignedExtension, Zero,38    },39    transaction_validity::{40        TransactionPriority, InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,41    },42    FixedPointOperand, FixedU128,43};44use sp_runtime::traits::StaticLookup;45use pallet_contracts::chain_extension::UncheckedFrom;46use transaction_payment::OnChargeTransaction;4748#[cfg(test)]49mod mock;5051#[cfg(test)]52mod tests;5354mod default_weights;5556pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;57pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;58pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;59pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;6061// Structs62// #region6364pub type CollectionId = u32;65pub type TokenId = u32;66pub type DecimalPoints = u8;6768#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]69#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]70pub enum CollectionMode {71    Invalid,72    NFT,73    // decimal points74    Fungible(DecimalPoints),75    ReFungible,76}7778impl Default for CollectionMode {79    fn default() -> Self {80        Self::Invalid81    }82}8384impl Into<u8> for CollectionMode {85    fn into(self) -> u8 {86        match self {87            CollectionMode::Invalid => 0,88            CollectionMode::NFT => 1,89            CollectionMode::Fungible(_) => 2,90            CollectionMode::ReFungible => 3,91        }92    }93}9495#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]96#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]97pub enum AccessMode {98    Normal,99    WhiteList,100}101impl Default for AccessMode {102    fn default() -> Self {103        Self::Normal104    }105}106107#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]108#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]109pub enum SchemaVersion {110    ImageURL,111    Unique,112}113impl Default for SchemaVersion {114    fn default() -> Self {115        Self::ImageURL116    }117}118119#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]120#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]121pub struct Ownership<AccountId> {122    pub owner: AccountId,123    pub fraction: u128,124}125126#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]127#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]128pub struct CollectionType<AccountId> {129    pub owner: AccountId,130    pub mode: CollectionMode,131    pub access: AccessMode,132    pub decimal_points: DecimalPoints,133    pub name: Vec<u16>,        // 64 include null escape char134    pub description: Vec<u16>, // 256 include null escape char135    pub token_prefix: Vec<u8>, // 16 include null escape char136    pub mint_mode: bool,137    pub offchain_schema: Vec<u8>,138    pub schema_version: SchemaVersion,139    pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender140    pub sponsor_confirmed: bool, // False if sponsor address has not yet confirmed sponsorship. True otherwise.141    pub limits: CollectionLimits, // Collection private restrictions 142    pub variable_on_chain_schema: Vec<u8>, //143    pub const_on_chain_schema: Vec<u8>, //144}145146#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]147#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]148pub struct NftItemType<AccountId> {149    pub owner: AccountId,150    pub const_data: Vec<u8>,151    pub variable_data: Vec<u8>,152}153154#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]155#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]156pub struct FungibleItemType {157    pub value: u128,158}159160#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]161#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]162pub struct ReFungibleItemType<AccountId> {163    pub owner: Vec<Ownership<AccountId>>,164    pub const_data: Vec<u8>,165    pub variable_data: Vec<u8>,166}167168// #[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]169// #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]170// pub struct VestingItem<AccountId, Moment> {171//     pub sender: AccountId,172//     pub recipient: AccountId,173//     pub collection_id: CollectionId,174//     pub item_id: TokenId,175//     pub amount: u64,176//     pub vesting_date: Moment,177// }178179#[derive(Encode, Decode, Debug, Clone, PartialEq)]180#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]181pub struct CollectionLimits {182    pub account_token_ownership_limit: u32,183    pub sponsored_data_size: u32,184    pub token_limit: u32,185186    // Timeouts for item types in passed blocks187    pub sponsor_transfer_timeout: u32,188    pub owner_can_transfer: bool,189    pub owner_can_destroy: bool,190}191192impl Default for CollectionLimits {193    fn default() -> CollectionLimits {194        CollectionLimits { 195            account_token_ownership_limit: 10_000_000, 196            token_limit: u32::max_value(),197            sponsored_data_size: u32::MAX,198            sponsor_transfer_timeout: 14400,199            owner_can_transfer: true,200            owner_can_destroy: true201        }202    }203}204205#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]206#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]207pub struct ChainLimits {208    pub collection_numbers_limit: u32,209    pub account_token_ownership_limit: u32,210    pub collections_admins_limit: u64,211    pub custom_data_limit: u32,212213    // Timeouts for item types in passed blocks214    pub nft_sponsor_transfer_timeout: u32,215    pub fungible_sponsor_transfer_timeout: u32,216    pub refungible_sponsor_transfer_timeout: u32,217218    // Schema limits219    pub offchain_schema_limit: u32,220    pub variable_on_chain_schema_limit: u32,221    pub const_on_chain_schema_limit: u32,222}223224pub trait WeightInfo {225	fn create_collection() -> Weight;226	fn destroy_collection() -> Weight;227	fn add_to_white_list() -> Weight;228	fn remove_from_white_list() -> Weight;229    fn set_public_access_mode() -> Weight;230    fn set_mint_permission() -> Weight;231    fn change_collection_owner() -> Weight;232    fn add_collection_admin() -> Weight;233    fn remove_collection_admin() -> Weight;234    fn set_collection_sponsor() -> Weight;235    fn confirm_sponsorship() -> Weight;236    fn remove_collection_sponsor() -> Weight;237    fn create_item(s: usize) -> Weight;238    fn burn_item() -> Weight;239    fn transfer() -> Weight;240    fn approve() -> Weight;241    fn transfer_from() -> Weight;242    fn set_offchain_schema() -> Weight;243    fn set_const_on_chain_schema() -> Weight;244    fn set_variable_on_chain_schema() -> Weight;245    fn set_variable_meta_data() -> Weight;246    fn enable_contract_sponsoring() -> Weight;247    fn set_schema_version() -> Weight;248    fn set_chain_limits() -> Weight;249    fn set_contract_sponsoring_rate_limit() -> Weight;250    fn toggle_contract_white_list() -> Weight;251    fn add_to_contract_white_list() -> Weight;252    fn remove_from_contract_white_list() -> Weight;253    fn set_collection_limits() -> Weight;254}255256#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]257#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]258pub struct CreateNftData {259    pub const_data: Vec<u8>,260    pub variable_data: Vec<u8>,261}262263#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]264#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]265pub struct CreateFungibleData {266    pub value: u128,267}268269#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]270#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]271pub struct CreateReFungibleData {272    pub const_data: Vec<u8>,273    pub variable_data: Vec<u8>,274    pub pieces: u128,275}276277#[derive(Encode, Decode, Debug, Clone, PartialEq)]278#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]279pub enum CreateItemData {280    NFT(CreateNftData),281    Fungible(CreateFungibleData),282    ReFungible(CreateReFungibleData),283}284285impl CreateItemData {286    pub fn len(&self) -> usize {287        let len = match self {288            CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),289            CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),290            _ => 0291        };292        293        return len;294    }295}296297impl From<CreateNftData> for CreateItemData {298    fn from(item: CreateNftData) -> Self {299        CreateItemData::NFT(item)300    }301}302303impl From<CreateReFungibleData> for CreateItemData {304    fn from(item: CreateReFungibleData) -> Self {305        CreateItemData::ReFungible(item)306    }307}308309impl From<CreateFungibleData> for CreateItemData {310    fn from(item: CreateFungibleData) -> Self {311        CreateItemData::Fungible(item)312    }313}314315316decl_error! {317	/// Error for non-fungible-token module.318	pub enum Error for Module<T: Config> {319        /// Total collections bound exceeded.320        TotalCollectionsLimitExceeded,321		/// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.322        CollectionDecimalPointLimitExceeded, 323        /// Collection name can not be longer than 63 char.324        CollectionNameLimitExceeded, 325        /// Collection description can not be longer than 255 char.326        CollectionDescriptionLimitExceeded, 327        /// Token prefix can not be longer than 15 char.328        CollectionTokenPrefixLimitExceeded,329        /// This collection does not exist.330        CollectionNotFound,331        /// Item not exists.332        TokenNotFound,333        /// Admin not found334        AdminNotFound,335        /// Arithmetic calculation overflow.336        NumOverflow,       337        /// Account already has admin role.338        AlreadyAdmin,  339        /// You do not own this collection.340        NoPermission,341        /// This address is not set as sponsor, use setCollectionSponsor first.342        ConfirmUnsetSponsorFail,343        /// Collection is not in mint mode.344        PublicMintingNotAllowed,345        /// Sender parameter and item owner must be equal.346        MustBeTokenOwner,347        /// Item balance not enough.348        TokenValueTooLow,349        /// Size of item is too large.350        NftSizeLimitExceeded,351        /// No approve found352        ApproveNotFound,353        /// Requested value more than approved.354        TokenValueNotEnough,355        /// Only approved addresses can call this method.356        ApproveRequired,357        /// Address is not in white list.358        AddresNotInWhiteList,359        /// Number of collection admins bound exceeded.360        CollectionAdminsLimitExceeded,361        /// Owned tokens by a single address bound exceeded.362        AddressOwnershipLimitExceeded,363        /// Length of items properties must be greater than 0.364        EmptyArgument,365        /// const_data exceeded data limit.366        TokenConstDataLimitExceeded,367        /// variable_data exceeded data limit.368        TokenVariableDataLimitExceeded,369        /// Not NFT item data used to mint in NFT collection.370        NotNftDataUsedToMintNftCollectionToken,371        /// Not Fungible item data used to mint in Fungible collection.372        NotFungibleDataUsedToMintFungibleCollectionToken,373        /// Not Re Fungible item data used to mint in Re Fungible collection.374        NotReFungibleDataUsedToMintReFungibleCollectionToken,375        /// Unexpected collection type.376        UnexpectedCollectionType,377        /// Can't store metadata in fungible tokens.378        CantStoreMetadataInFungibleTokens,379        /// Collection token limit exceeded380        CollectionTokenLimitExceeded,381        /// Account token limit exceeded per collection382        AccountTokenLimitExceeded,383        /// Collection limit bounds per collection exceeded384        CollectionLimitBoundsExceeded,385        /// Tried to enable permissions which are only permitted to be disabled386        OwnerPermissionsCantBeReverted,387        /// Schema data size limit bound exceeded388        SchemaDataLimitExceeded,389        /// Maximum refungibility exceeded390        WrongRefungiblePieces391	}392}393394pub trait Config: system::Config + Sized + transaction_payment::Config + pallet_contracts::Config {395    type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;396397    /// Weight information for extrinsics in this pallet.398	type WeightInfo: WeightInfo;399}400401#[cfg(feature = "runtime-benchmarks")]402mod benchmarking;403404// #endregion405406decl_storage! {407    trait Store for Module<T: Config> as Nft {408409        // Private members410        NextCollectionID: CollectionId;411        CreatedCollectionCount: u32;412        ChainVersion: u64;413        ItemListIndex: map hasher(identity) CollectionId => TokenId;414415        // Chain limits struct416        pub ChainLimit get(fn chain_limit) config(): ChainLimits;417418        // Bound counters419        CollectionCount: u32;420        pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;421422        // Basic collections423        pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;424        pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;425        pub WhiteList get(fn white_list): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => bool;426427        /// Balance owner per collection map428        pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;429430        /// second parameter: item id + owner account id + spender account id431        pub Allowances get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId, T::AccountId) => u128;432433        /// Item collections434        pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;435        pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => FungibleItemType;436        pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;437438        /// Index list439        pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;440441        /// Tokens transfer baskets442        pub CreateItemBasket get(fn create_item_basket): map hasher(twox_64_concat) (CollectionId, T::AccountId) => T::BlockNumber;443        pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;444        pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;445        pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;446447        // Contract Sponsorship and Ownership448        pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;449        pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;450        pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;451        pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;452        pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 453        pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId => bool; 454    }455    add_extra_genesis {456        build(|config: &GenesisConfig<T>| {457            // Modification of storage458            for (_num, _c) in &config.collection {459                <Module<T>>::init_collection(_c);460            }461462            for (_num, _c, _i) in &config.nft_item_id {463                <Module<T>>::init_nft_token(*_c, _i);464            }465466            for (collection_id, account_id, fungible_item) in &config.fungible_item_id {467                <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);468            }469470            for (_num, _c, _i) in &config.refungible_item_id {471                <Module<T>>::init_refungible_token(*_c, _i);472            }473        })474    }475}476477decl_event!(478    pub enum Event<T>479    where480        AccountId = <T as system::Config>::AccountId,481    {482        /// New collection was created483        /// 484        /// # Arguments485        /// 486        /// * collection_id: Globally unique identifier of newly created collection.487        /// 488        /// * mode: [CollectionMode] converted into u8.489        /// 490        /// * account_id: Collection owner.491        Created(CollectionId, u8, AccountId),492493        /// New item was created.494        /// 495        /// # Arguments496        /// 497        /// * collection_id: Id of the collection where item was created.498        /// 499        /// * item_id: Id of an item. Unique within the collection.500        ///501        /// * recipient: Owner of newly created item 502        ItemCreated(CollectionId, TokenId, AccountId),503504        /// Collection item was burned.505        /// 506        /// # Arguments507        /// 508        /// collection_id.509        /// 510        /// item_id: Identifier of burned NFT.511        ItemDestroyed(CollectionId, TokenId),512513        /// Item was transferred514        ///515        /// * collection_id: Id of collection to which item is belong516        ///517        /// * item_id: Id of an item518        ///519        /// * sender: Original owner of item520        ///521        /// * recipient: New owner of item522        ///523        /// * amount: Always 1 for NFT524        Transfer(CollectionId, TokenId, AccountId, AccountId, u128),525    }526);527528decl_module! {529    pub struct Module<T: Config> for enum Call 530    where 531        origin: T::Origin532    {533        fn deposit_event() = default;534        type Error = Error<T>;535536        fn on_initialize(now: T::BlockNumber) -> Weight {537538            if ChainVersion::get() < 2539            {540                let value = NextCollectionID::get();541                CreatedCollectionCount::put(value);542                ChainVersion::put(2);543            }544545            0546        }547548        /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner and admin of the collection are set to the address that signed the transaction. Both addresses can be changed later.549        /// 550        /// # Permissions551        /// 552        /// * Anyone.553        /// 554        /// # Arguments555        /// 556        /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.557        /// 558        /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.559        /// 560        /// * token_prefix: UTF-8 string with token prefix.561        /// 562        /// * mode: [CollectionMode] collection type and type dependent data.563        // returns collection ID564        #[weight = <T as Config>::WeightInfo::create_collection()]565        pub fn create_collection(origin,566                                 collection_name: Vec<u16>,567                                 collection_description: Vec<u16>,568                                 token_prefix: Vec<u8>,569                                 mode: CollectionMode) -> DispatchResult {570571            // Anyone can create a collection572            let who = ensure_signed(origin)?;573574            let decimal_points = match mode {575                CollectionMode::Fungible(points) => points,576                _ => 0577            };578579            let chain_limit = ChainLimit::get();580581            // bound Total number of collections582            ensure!(CollectionCount::get() < chain_limit.collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);583584            // check params585            ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);586            ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);587            ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);588            ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);589590            // Generate next collection ID591            let next_id = CreatedCollectionCount::get()592                .checked_add(1)593                .ok_or(Error::<T>::NumOverflow)?;594595            // bound counter596            let total = CollectionCount::get()597                .checked_add(1)598                .ok_or(Error::<T>::NumOverflow)?;599600            CreatedCollectionCount::put(next_id);601            CollectionCount::put(total);602603            let limits = CollectionLimits {604                sponsored_data_size: chain_limit.custom_data_limit,605                ..Default::default()606            };607608            // Create new collection609            let new_collection = CollectionType {610                owner: who.clone(),611                name: collection_name,612                mode: mode.clone(),613                mint_mode: false,614                access: AccessMode::Normal,615                description: collection_description,616                decimal_points: decimal_points,617                token_prefix: token_prefix,618                offchain_schema: Vec::new(),619                schema_version: SchemaVersion::ImageURL,620                sponsor: T::AccountId::default(),621                sponsor_confirmed: false,622                variable_on_chain_schema: Vec::new(),623                const_on_chain_schema: Vec::new(),624                limits,625            };626627            // Add new collection to map628            <Collection<T>>::insert(next_id, new_collection);629630            // call event631            Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));632633            Ok(())634        }635636        /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.637        /// 638        /// # Permissions639        /// 640        /// * Collection Owner.641        /// 642        /// # Arguments643        /// 644        /// * collection_id: collection to destroy.645        #[weight = <T as Config>::WeightInfo::destroy_collection()]646        pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {647648            let sender = ensure_signed(origin)?;649            Self::check_owner_permissions(collection_id, sender)?;650651            let target_collection = <Collection<T>>::get(collection_id);652            if !target_collection.limits.owner_can_destroy {653                fail!(Error::<T>::NoPermission);654            }655656            <AddressTokens<T>>::remove_prefix(collection_id);657            <Allowances<T>>::remove_prefix(collection_id);658            <Balance<T>>::remove_prefix(collection_id);659            <ItemListIndex>::remove(collection_id);660            <AdminList<T>>::remove(collection_id);661            <Collection<T>>::remove(collection_id);662            <WhiteList<T>>::remove_prefix(collection_id);663664            <NftItemList<T>>::remove_prefix(collection_id);665            <FungibleItemList<T>>::remove_prefix(collection_id);666            <ReFungibleItemList<T>>::remove_prefix(collection_id);667668            <NftTransferBasket<T>>::remove_prefix(collection_id);669            <FungibleTransferBasket<T>>::remove_prefix(collection_id);670            <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);671672            if CollectionCount::get() > 0673            {674                // bound couter675                let total = CollectionCount::get()676                    .checked_sub(1)677                    .ok_or(Error::<T>::NumOverflow)?;678679                CollectionCount::put(total);680            }681682            Ok(())683        }684685        /// Add an address to white list.686        /// 687        /// # Permissions688        /// 689        /// * Collection Owner690        /// * Collection Admin691        /// 692        /// # Arguments693        /// 694        /// * collection_id.695        /// 696        /// * address.697        #[weight = <T as Config>::WeightInfo::add_to_white_list()]698        pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{699700            let sender = ensure_signed(origin)?;701            Self::check_owner_or_admin_permissions(collection_id, sender)?;702703            <WhiteList<T>>::insert(collection_id, address, true);704            705            Ok(())706        }707708        /// Remove an address from white list.709        /// 710        /// # Permissions711        /// 712        /// * Collection Owner713        /// * Collection Admin714        /// 715        /// # Arguments716        /// 717        /// * collection_id.718        /// 719        /// * address.720        #[weight = <T as Config>::WeightInfo::remove_from_white_list()]721        pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{722723            let sender = ensure_signed(origin)?;724            Self::check_owner_or_admin_permissions(collection_id, sender)?;725726            <WhiteList<T>>::remove(collection_id, address);727728            Ok(())729        }730731        /// Toggle between normal and white list access for the methods with access for `Anyone`.732        /// 733        /// # Permissions734        /// 735        /// * Collection Owner.736        /// 737        /// # Arguments738        /// 739        /// * collection_id.740        /// 741        /// * mode: [AccessMode]742        #[weight = <T as Config>::WeightInfo::set_public_access_mode()]743        pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult744        {745            let sender = ensure_signed(origin)?;746747            Self::check_owner_permissions(collection_id, sender)?;748            let mut target_collection = <Collection<T>>::get(collection_id);749            target_collection.access = mode;750            <Collection<T>>::insert(collection_id, target_collection);751752            Ok(())753        }754755        /// Allows Anyone to create tokens if:756        /// * White List is enabled, and757        /// * Address is added to white list, and758        /// * This method was called with True parameter759        /// 760        /// # Permissions761        /// * Collection Owner762        ///763        /// # Arguments764        /// 765        /// * collection_id.766        /// 767        /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.768        #[weight = <T as Config>::WeightInfo::set_mint_permission()]769        pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult770        {771            let sender = ensure_signed(origin)?;772773            Self::check_owner_permissions(collection_id, sender)?;774            let mut target_collection = <Collection<T>>::get(collection_id);775            target_collection.mint_mode = mint_permission;776            <Collection<T>>::insert(collection_id, target_collection);777778            Ok(())779        }780781        /// Change the owner of the collection.782        /// 783        /// # Permissions784        /// 785        /// * Collection Owner.786        /// 787        /// # Arguments788        /// 789        /// * collection_id.790        /// 791        /// * new_owner.792        #[weight = <T as Config>::WeightInfo::change_collection_owner()]793        pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {794795            let sender = ensure_signed(origin)?;796            Self::check_owner_permissions(collection_id, sender)?;797            let mut target_collection = <Collection<T>>::get(collection_id);798            target_collection.owner = new_owner;799            <Collection<T>>::insert(collection_id, target_collection);800801            Ok(())802        }803804        /// Adds an admin of the Collection.805        /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership. 806        /// 807        /// # Permissions808        /// 809        /// * Collection Owner.810        /// * Collection Admin.811        /// 812        /// # Arguments813        /// 814        /// * collection_id: ID of the Collection to add admin for.815        /// 816        /// * new_admin_id: Address of new admin to add.817        #[weight = <T as Config>::WeightInfo::add_collection_admin()]818        pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {819820            let sender = ensure_signed(origin)?;821            Self::check_owner_or_admin_permissions(collection_id, sender)?;822            let mut admin_arr: Vec<T::AccountId> = Vec::new();823824            if <AdminList<T>>::contains_key(collection_id)825            {826                admin_arr = <AdminList<T>>::get(collection_id);827                ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);828            }829830            // Number of collection admins831            ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);832833            admin_arr.push(new_admin_id);834            <AdminList<T>>::insert(collection_id, admin_arr);835836            Ok(())837        }838839        /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.840        ///841        /// # Permissions842        /// 843        /// * Collection Owner.844        /// * Collection Admin.845        /// 846        /// # Arguments847        /// 848        /// * collection_id: ID of the Collection to remove admin for.849        /// 850        /// * account_id: Address of admin to remove.851        #[weight = <T as Config>::WeightInfo::remove_collection_admin()]852        pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {853854            let sender = ensure_signed(origin)?;855            Self::check_owner_or_admin_permissions(collection_id, sender)?;856            ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);857858            let mut admin_arr = <AdminList<T>>::get(collection_id);859            admin_arr.retain(|i| *i != account_id);860            <AdminList<T>>::insert(collection_id, admin_arr);861862            Ok(())863        }864865        /// # Permissions866        /// 867        /// * Collection Owner868        /// 869        /// # Arguments870        /// 871        /// * collection_id.872        /// 873        /// * new_sponsor.874        #[weight = <T as Config>::WeightInfo::set_collection_sponsor()]875        pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {876877            let sender = ensure_signed(origin)?;878            ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);879880            let mut target_collection = <Collection<T>>::get(collection_id);881            ensure!(sender == target_collection.owner, Error::<T>::NoPermission);882883            target_collection.sponsor = new_sponsor;884            target_collection.sponsor_confirmed = false;885            <Collection<T>>::insert(collection_id, target_collection);886887            Ok(())888        }889890        /// # Permissions891        /// 892        /// * Sponsor.893        /// 894        /// # Arguments895        /// 896        /// * collection_id.897        #[weight = <T as Config>::WeightInfo::confirm_sponsorship()]898        pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {899900            let sender = ensure_signed(origin)?;901            ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);902903            let mut target_collection = <Collection<T>>::get(collection_id);904            ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);905906            target_collection.sponsor_confirmed = true;907            <Collection<T>>::insert(collection_id, target_collection);908909            Ok(())910        }911912        /// Switch back to pay-per-own-transaction model.913        ///914        /// # Permissions915        ///916        /// * Collection owner.917        /// 918        /// # Arguments919        /// 920        /// * collection_id.921        #[weight = <T as Config>::WeightInfo::remove_collection_sponsor()]922        pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {923924            let sender = ensure_signed(origin)?;925            ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);926927            let mut target_collection = <Collection<T>>::get(collection_id);928            ensure!(sender == target_collection.owner, Error::<T>::NoPermission);929930            target_collection.sponsor = T::AccountId::default();931            target_collection.sponsor_confirmed = false;932            <Collection<T>>::insert(collection_id, target_collection);933934            Ok(())935        }936937        /// This method creates a concrete instance of NFT Collection created with CreateCollection method.938        /// 939        /// # Permissions940        /// 941        /// * Collection Owner.942        /// * Collection Admin.943        /// * Anyone if944        ///     * White List is enabled, and945        ///     * Address is added to white list, and946        ///     * MintPermission is enabled (see SetMintPermission method)947        /// 948        /// # Arguments949        /// 950        /// * collection_id: ID of the collection.951        /// 952        /// * owner: Address, initial owner of the NFT.953        ///954        /// * data: Token data to store on chain.955        // #[weight =956        // (130_000_000 as Weight)957        // .saturating_add((2135 as Weight).saturating_mul((properties.len() as u64) as Weight))958        // .saturating_add(RocksDbWeight::get().reads(10 as Weight))959        // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]960961        #[weight = <T as Config>::WeightInfo::create_item(data.len())]962        pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {963964            let sender = ensure_signed(origin)?;965966            Self::collection_exists(collection_id)?;967968            let target_collection = <Collection<T>>::get(collection_id);969970            Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;971            Self::validate_create_item_args(&target_collection, &data)?;972            Self::create_item_no_validation(collection_id, owner, data)?;973974            Ok(())975        }976977        /// This method creates multiple instances of NFT Collection created with CreateCollection method.978        /// 979        /// # Permissions980        /// 981        /// * Collection Owner.982        /// * Collection Admin.983        /// * Anyone if984        ///     * White List is enabled, and985        ///     * Address is added to white list, and986        ///     * MintPermission is enabled (see SetMintPermission method)987        /// 988        /// # Arguments989        /// 990        /// * collection_id: ID of the collection.991        /// 992        /// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].993        /// 994        /// * owner: Address, initial owner of the NFT.995        #[weight = <T as Config>::WeightInfo::create_item(items_data.into_iter()996                               .map(|data| { data.len() })997                               .sum())]998        pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {9991000            ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);1001            let sender = ensure_signed(origin)?;10021003            Self::collection_exists(collection_id)?;1004            let target_collection = <Collection<T>>::get(collection_id);10051006            Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;10071008            for data in &items_data {1009                Self::validate_create_item_args(&target_collection, data)?;1010            }1011            for data in &items_data {1012                Self::create_item_no_validation(collection_id, owner.clone(), data.clone())?;1013            }10141015            Ok(())1016        }10171018        /// Destroys a concrete instance of NFT.1019        /// 1020        /// # Permissions1021        /// 1022        /// * Collection Owner.1023        /// * Collection Admin.1024        /// * Current NFT Owner.1025        /// 1026        /// # Arguments1027        /// 1028        /// * collection_id: ID of the collection.1029        /// 1030        /// * item_id: ID of NFT to burn.1031        #[weight = <T as Config>::WeightInfo::burn_item()]1032        pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10331034            let sender = ensure_signed(origin)?;1035            Self::collection_exists(collection_id)?;10361037            // Transfer permissions check1038            let target_collection = <Collection<T>>::get(collection_id);1039            ensure!(1040                Self::is_item_owner(sender.clone(), collection_id, item_id) ||1041                (1042                    target_collection.limits.owner_can_transfer &&1043                    Self::is_owner_or_admin_permissions(collection_id, sender.clone())1044                ),1045                Error::<T>::NoPermission1046            );10471048            if target_collection.access == AccessMode::WhiteList {1049                Self::check_white_list(collection_id, &sender)?;1050            }10511052            match target_collection.mode1053            {1054                CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1055                CollectionMode::Fungible(_)  => Self::burn_fungible_item(&sender, collection_id, value)?,1056                CollectionMode::ReFungible  => Self::burn_refungible_item(collection_id, item_id, &sender)?,1057                _ => ()1058            };10591060            // call event1061            Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10621063            Ok(())1064        }10651066        /// Change ownership of the token.1067        /// 1068        /// # Permissions1069        /// 1070        /// * Collection Owner1071        /// * Collection Admin1072        /// * Current NFT owner1073        ///1074        /// # Arguments1075        /// 1076        /// * recipient: Address of token recipient.1077        /// 1078        /// * collection_id.1079        /// 1080        /// * item_id: ID of the item1081        ///     * Non-Fungible Mode: Required.1082        ///     * Fungible Mode: Ignored.1083        ///     * Re-Fungible Mode: Required.1084        /// 1085        /// * value: Amount to transfer.1086        ///     * Non-Fungible Mode: Ignored1087        ///     * Fungible Mode: Must specify transferred amount1088        ///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)1089        #[weight = <T as Config>::WeightInfo::transfer()]1090        pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1091            let sender = ensure_signed(origin)?;1092            Self::transfer_internal(sender, recipient, collection_id, item_id, value)1093        }10941095        /// Set, change, or remove approved address to transfer the ownership of the NFT.1096        /// 1097        /// # Permissions1098        /// 1099        /// * Collection Owner1100        /// * Collection Admin1101        /// * Current NFT owner1102        /// 1103        /// # Arguments1104        /// 1105        /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).1106        /// 1107        /// * collection_id.1108        /// 1109        /// * item_id: ID of the item.1110        #[weight = <T as Config>::WeightInfo::approve()]1111        pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {11121113            let sender = ensure_signed(origin)?;11141115            Self::collection_exists(collection_id)?;1116            Self::token_exists(collection_id, item_id, &sender)?;11171118            // Transfer permissions check1119            let target_collection = <Collection<T>>::get(collection_id);1120            let allowance_limit = if (1121                target_collection.limits.owner_can_transfer &&1122                Self::is_owner_or_admin_permissions(1123                    collection_id,1124                    sender.clone(),1125                )1126            ) {1127                None1128            } else if let Some(amount) = Self::owned_amount(1129                sender.clone(),1130                collection_id,1131                item_id,1132            ) {1133                Some(amount)1134            } else {1135                fail!(Error::<T>::NoPermission);1136            };11371138            if target_collection.access == AccessMode::WhiteList {1139                Self::check_white_list(collection_id, &sender)?;1140                Self::check_white_list(collection_id, &spender)?;1141            }11421143            let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1144            let mut allowance: u128 = amount;1145            if allowance_exists {1146                allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1147            }1148            if let Some(limit) = allowance_limit {1149                ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);1150            }1151            <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);11521153            Ok(())1154        }1155        1156        /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.1157        /// 1158        /// # Permissions1159        /// * Collection Owner1160        /// * Collection Admin1161        /// * Current NFT owner1162        /// * Address approved by current NFT owner1163        /// 1164        /// # Arguments1165        /// 1166        /// * from: Address that owns token.1167        /// 1168        /// * recipient: Address of token recipient.1169        /// 1170        /// * collection_id.1171        /// 1172        /// * item_id: ID of the item.1173        /// 1174        /// * value: Amount to transfer.1175        #[weight = <T as Config>::WeightInfo::transfer_from()]1176        pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11771178            let sender = ensure_signed(origin)?;1179            let mut appoved_transfer = false;11801181            // Check approval1182            let mut approval: u128 = 0;1183            if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &sender)) {1184                approval = <Allowances<T>>::get(collection_id, (item_id, &from, &sender));1185                ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1186                appoved_transfer = true;1187            }11881189            let target_collection = <Collection<T>>::get(collection_id);11901191            // Limits check1192            Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11931194            // Transfer permissions check         1195            ensure!(1196                appoved_transfer || 1197                (1198                    target_collection.limits.owner_can_transfer &&1199                    Self::is_owner_or_admin_permissions(collection_id, sender.clone())1200                ),1201                Error::<T>::NoPermission1202            );12031204            if target_collection.access == AccessMode::WhiteList {1205                Self::check_white_list(collection_id, &sender)?;1206                Self::check_white_list(collection_id, &recipient)?;1207            }12081209            // Reduce approval by transferred amount or remove if remaining approval drops to 01210            if approval.checked_sub(value).unwrap_or(0) > 0 {1211                <Allowances<T>>::insert(collection_id, (item_id, &from, &sender), approval - value);1212            }1213            else {1214                <Allowances<T>>::remove(collection_id, (item_id, &from, &sender));1215            }12161217            match target_collection.mode1218            {1219                CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1220                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1221                CollectionMode::ReFungible  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1222                _ => ()1223            };12241225            Ok(())1226        }12271228        // #[weight = 0]1229        // pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {12301231        //     // let no_perm_mes = "You do not have permissions to modify this collection";1232        //     // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1233        //     // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1234        //     // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);12351236        //     // // on_nft_received  call12371238        //     // Self::transfer(origin, collection_id, item_id, new_owner)?;12391240        //     Ok(())1241        // }12421243        /// Set off-chain data schema.1244        /// 1245        /// # Permissions1246        /// 1247        /// * Collection Owner1248        /// * Collection Admin1249        /// 1250        /// # Arguments1251        /// 1252        /// * collection_id.1253        /// 1254        /// * schema: String representing the offchain data schema.1255        #[weight = <T as Config>::WeightInfo::set_variable_meta_data()]1256        pub fn set_variable_meta_data (1257            origin,1258            collection_id: CollectionId,1259            item_id: TokenId,1260            data: Vec<u8>1261        ) -> DispatchResult {1262            let sender = ensure_signed(origin)?;1263            1264            Self::collection_exists(collection_id)?;1265            Self::token_exists(collection_id, item_id, &sender)?;12661267            ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12681269            // Modify permissions check1270            let target_collection = <Collection<T>>::get(collection_id);1271            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1272                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1273                Error::<T>::NoPermission);12741275            match target_collection.mode1276            {1277                CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1278                CollectionMode::ReFungible  => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1279                CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1280                _ => fail!(Error::<T>::UnexpectedCollectionType)1281            };12821283            Ok(())1284        }1285 1286        /// Set schema standard1287        /// ImageURL1288        /// Unique1289        /// 1290        /// # Permissions1291        /// 1292        /// * Collection Owner1293        /// * Collection Admin1294        /// 1295        /// # Arguments1296        /// 1297        /// * collection_id.1298        /// 1299        /// * schema: SchemaVersion: enum1300        #[weight = <T as Config>::WeightInfo::set_schema_version()]1301        pub fn set_schema_version(1302            origin,1303            collection_id: CollectionId,1304            version: SchemaVersion1305        ) -> DispatchResult {1306            let sender = ensure_signed(origin)?;1307            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1308            let mut target_collection = <Collection<T>>::get(collection_id);1309            target_collection.schema_version = version;1310            <Collection<T>>::insert(collection_id, target_collection);13111312            Ok(())1313        }13141315        /// Set off-chain data schema.1316        /// 1317        /// # Permissions1318        /// 1319        /// * Collection Owner1320        /// * Collection Admin1321        /// 1322        /// # Arguments1323        /// 1324        /// * collection_id.1325        /// 1326        /// * schema: String representing the offchain data schema.1327        #[weight = <T as Config>::WeightInfo::set_offchain_schema()]1328        pub fn set_offchain_schema(1329            origin,1330            collection_id: CollectionId,1331            schema: Vec<u8>1332        ) -> DispatchResult {1333            let sender = ensure_signed(origin)?;1334            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13351336            // check schema limit1337            ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");13381339            let mut target_collection = <Collection<T>>::get(collection_id);1340            target_collection.offchain_schema = schema;1341            <Collection<T>>::insert(collection_id, target_collection);13421343            Ok(())1344        }13451346        /// Set const on-chain data schema.1347        /// 1348        /// # Permissions1349        /// 1350        /// * Collection Owner1351        /// * Collection Admin1352        /// 1353        /// # Arguments1354        /// 1355        /// * collection_id.1356        /// 1357        /// * schema: String representing the const on-chain data schema.1358        #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1359        pub fn set_const_on_chain_schema (1360            origin,1361            collection_id: CollectionId,1362            schema: Vec<u8>1363        ) -> DispatchResult {1364            let sender = ensure_signed(origin)?;1365            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13661367            // check schema limit1368            ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");13691370            let mut target_collection = <Collection<T>>::get(collection_id);1371            target_collection.const_on_chain_schema = schema;1372            <Collection<T>>::insert(collection_id, target_collection);13731374            Ok(())1375        }13761377        /// Set variable on-chain data schema.1378        /// 1379        /// # Permissions1380        /// 1381        /// * Collection Owner1382        /// * Collection Admin1383        /// 1384        /// # Arguments1385        /// 1386        /// * collection_id.1387        /// 1388        /// * schema: String representing the variable on-chain data schema.1389        #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1390        pub fn set_variable_on_chain_schema (1391            origin,1392            collection_id: CollectionId,1393            schema: Vec<u8>1394        ) -> DispatchResult {1395            let sender = ensure_signed(origin)?;1396            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13971398            // check schema limit1399            ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");14001401            let mut target_collection = <Collection<T>>::get(collection_id);1402            target_collection.variable_on_chain_schema = schema;1403            <Collection<T>>::insert(collection_id, target_collection);14041405            Ok(())1406        }14071408        // Sudo permissions function1409        #[weight = <T as Config>::WeightInfo::set_chain_limits()]1410        pub fn set_chain_limits(1411            origin,1412            limits: ChainLimits1413        ) -> DispatchResult {14141415            #[cfg(not(feature = "runtime-benchmarks"))]1416            ensure_root(origin)?;14171418            <ChainLimit>::put(limits);1419            Ok(())1420        }14211422        /// Enable smart contract self-sponsoring.1423        /// 1424        /// # Permissions1425        /// 1426        /// * Contract Owner1427        /// 1428        /// # Arguments1429        /// 1430        /// * contract address1431        /// * enable flag1432        /// 1433        #[weight = <T as Config>::WeightInfo::enable_contract_sponsoring()]1434        pub fn enable_contract_sponsoring(1435            origin,1436            contract_address: T::AccountId,1437            enable: bool1438        ) -> DispatchResult {14391440            let sender = ensure_signed(origin)?;14411442            #[cfg(feature = "runtime-benchmarks")]1443            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14441445            Self::ensure_contract_owned(sender, &contract_address)?;14461447            <ContractSelfSponsoring<T>>::insert(contract_address, enable);1448            Ok(())1449        }14501451        /// Set the rate limit for contract sponsoring to specified number of blocks.1452        /// 1453        /// If not set (has the default value of 0 blocks), the sponsoring will be disabled. 1454        /// If set to the number B (for blocks), the transactions will be sponsored with a rate 1455        /// limit of B, i.e. fees for every transaction sent to this smart contract will be paid 1456        /// from contract endowment if there are at least B blocks between such transactions. 1457        /// Nonetheless, if transactions are sent more frequently, the fees are paid by the sender.1458        /// 1459        /// # Permissions1460        /// 1461        /// * Contract Owner1462        /// 1463        /// # Arguments1464        /// 1465        /// -`contract_address`: Address of the contract to sponsor1466        /// -`rate_limit`: Number of blocks to wait until the next sponsored transaction is allowed1467        /// 1468        #[weight = <T as Config>::WeightInfo::set_contract_sponsoring_rate_limit()]1469        pub fn set_contract_sponsoring_rate_limit(1470            origin,1471            contract_address: T::AccountId,1472            rate_limit: T::BlockNumber1473        ) -> DispatchResult {1474            let sender = ensure_signed(origin)?;14751476            #[cfg(feature = "runtime-benchmarks")]1477            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14781479            Self::ensure_contract_owned(sender, &contract_address)?;1480            <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1481            Ok(())1482        }14831484        /// Enable the white list for a contract. Only addresses added to the white list with addToContractWhiteList will be able to call this smart contract.1485        /// 1486        /// # Permissions1487        /// 1488        /// * Address that deployed smart contract.1489        /// 1490        /// # Arguments1491        /// 1492        /// -`contract_address`: Address of the contract.1493        /// 1494        /// - `enable`: .  1495        #[weight = <T as Config>::WeightInfo::toggle_contract_white_list()]1496        pub fn toggle_contract_white_list(1497            origin,1498            contract_address: T::AccountId,1499            enable: bool1500        ) -> DispatchResult {1501            let sender = ensure_signed(origin)?;15021503            #[cfg(feature = "runtime-benchmarks")]1504            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15051506            Self::ensure_contract_owned(sender, &contract_address)?;1507            <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1508            Ok(())1509        }1510        1511        /// Add an address to smart contract white list.1512        /// 1513        /// # Permissions1514        /// 1515        /// * Address that deployed smart contract.1516        /// 1517        /// # Arguments1518        /// 1519        /// -`contract_address`: Address of the contract.1520        ///1521        /// -`account_address`: Address to add.1522        #[weight = <T as Config>::WeightInfo::add_to_contract_white_list()]1523        pub fn add_to_contract_white_list(1524            origin,1525            contract_address: T::AccountId,1526            account_address: T::AccountId1527        ) -> DispatchResult {1528            let sender = ensure_signed(origin)?;15291530            #[cfg(feature = "runtime-benchmarks")]1531            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1532            1533            Self::ensure_contract_owned(sender, &contract_address)?;      1534            <ContractWhiteList<T>>::insert(contract_address, account_address, true);1535            Ok(())1536        }15371538        /// Remove an address from smart contract white list.1539        /// 1540        /// # Permissions1541        /// 1542        /// * Address that deployed smart contract.1543        /// 1544        /// # Arguments1545        /// 1546        /// -`contract_address`: Address of the contract.1547        ///1548        /// -`account_address`: Address to remove.1549        #[weight = <T as Config>::WeightInfo::remove_from_contract_white_list()]1550        pub fn remove_from_contract_white_list(1551            origin,1552            contract_address: T::AccountId,1553            account_address: T::AccountId1554        ) -> DispatchResult {1555            let sender = ensure_signed(origin)?;15561557            #[cfg(feature = "runtime-benchmarks")]1558            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15591560            Self::ensure_contract_owned(sender, &contract_address)?;1561            <ContractWhiteList<T>>::remove(contract_address, account_address);1562            Ok(())1563        }15641565        #[weight = <T as Config>::WeightInfo::set_collection_limits()]1566        pub fn set_collection_limits(1567            origin,1568            collection_id: u32,1569            new_limits: CollectionLimits,1570        ) -> DispatchResult {1571            let sender = ensure_signed(origin)?;1572            Self::check_owner_permissions(collection_id, sender.clone())?;1573            let mut target_collection = <Collection<T>>::get(collection_id);1574            let old_limits = target_collection.limits;1575            let chain_limits = ChainLimit::get();15761577            // collection bounds1578            ensure!(new_limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1579                new_limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP && 1580                new_limits.sponsored_data_size <= chain_limits.custom_data_limit,1581                Error::<T>::CollectionLimitBoundsExceeded);15821583            // token_limit   check  prev1584            ensure!(old_limits.token_limit >= new_limits.token_limit, Error::<T>::CollectionTokenLimitExceeded);1585            ensure!(new_limits.token_limit > 0, Error::<T>::CollectionTokenLimitExceeded);15861587            ensure!(1588                (old_limits.owner_can_transfer || !new_limits.owner_can_transfer) &&1589                (old_limits.owner_can_destroy || !new_limits.owner_can_destroy),1590                Error::<T>::OwnerPermissionsCantBeReverted,1591            );15921593            target_collection.limits = new_limits;1594            <Collection<T>>::insert(collection_id, target_collection);15951596            Ok(())1597        } 1598    }1599}16001601impl<T: Config> Module<T> {16021603    pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {16041605        let target_collection = <Collection<T>>::get(collection_id);16061607        // Limits check1608        Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;16091610        // Transfer permissions check1611        ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1612            Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1613            Error::<T>::NoPermission);16141615        if target_collection.access == AccessMode::WhiteList {1616            Self::check_white_list(collection_id, &sender)?;1617            Self::check_white_list(collection_id, &recipient)?;1618        }16191620        match target_collection.mode1621        {1622            CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient.clone())?,1623            CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1624            CollectionMode::ReFungible  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient.clone())?,1625            _ => ()1626        };16271628        Self::deposit_event(RawEvent::Transfer(collection_id, item_id, sender, recipient, value));16291630        Ok(())1631    }163216331634    fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {16351636        // check token limit and account token limit1637        let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1638        ensure!(collection.limits.account_token_ownership_limit > account_items,  Error::<T>::AccountTokenLimitExceeded);1639        1640        Ok(())1641    }16421643    fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {16441645        // check token limit and account token limit1646        let total_items: u32 = ItemListIndex::get(collection_id);1647        let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1648        ensure!(collection.limits.token_limit > total_items,  Error::<T>::CollectionTokenLimitExceeded);1649        ensure!(collection.limits.account_token_ownership_limit > account_items,  Error::<T>::AccountTokenLimitExceeded);16501651        if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1652            ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1653            Self::check_white_list(collection_id, owner)?;1654            Self::check_white_list(collection_id, sender)?;1655        }16561657        Ok(())1658    }16591660    fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1661        match target_collection.mode1662        {1663            CollectionMode::NFT => {1664                if let CreateItemData::NFT(data) = data {1665                    // check sizes1666                    ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1667                    ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1668                } else {1669                    fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1670                }1671            },1672            CollectionMode::Fungible(_) => {1673                if let CreateItemData::Fungible(_) = data {1674                } else {1675                    fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1676                }1677            },1678            CollectionMode::ReFungible => {1679                if let CreateItemData::ReFungible(data) = data {16801681                    // check sizes1682                    ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1683                    ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);16841685                    // Check refungibility limits1686                    ensure!(data.pieces <= MAX_REFUNGIBLE_PIECES, Error::<T>::WrongRefungiblePieces);1687                    ensure!(data.pieces > 0, Error::<T>::WrongRefungiblePieces);1688                } else {1689                    fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1690                }1691            },1692            _ => { fail!(Error::<T>::UnexpectedCollectionType); }1693        };16941695        Ok(())1696    }16971698    fn create_item_no_validation(collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1699        match data1700        {1701            CreateItemData::NFT(data) => {1702                let item = NftItemType {1703                    owner: owner.clone(),1704                    const_data: data.const_data,1705                    variable_data: data.variable_data1706                };17071708                Self::add_nft_item(collection_id, item)?;1709            },1710            CreateItemData::Fungible(data) => {1711                Self::add_fungible_item(collection_id, &owner, data.value)?;1712            },1713            CreateItemData::ReFungible(data) => {1714                let mut owner_list = Vec::new();1715                owner_list.push(Ownership {owner: owner.clone(), fraction: data.pieces});17161717                let item = ReFungibleItemType {1718                    owner: owner_list,1719                    const_data: data.const_data,1720                    variable_data: data.variable_data1721                };17221723                Self::add_refungible_item(collection_id, item)?;1724            }1725        };17261727        // call event1728        Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id), owner));17291730        Ok(())1731    }17321733    fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {17341735        // Does new owner already have an account?1736        let mut balance: u128 = 0;1737        if <FungibleItemList<T>>::contains_key(collection_id, owner) {1738            balance = <FungibleItemList<T>>::get(collection_id, owner).value;1739        } 17401741        // Mint 1742        let item = FungibleItemType {1743            value: balance + value1744        };1745        <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);17461747        // Update balance1748        let new_balance = <Balance<T>>::get(collection_id, owner)1749            .checked_add(value)1750            .ok_or(Error::<T>::NumOverflow)?;1751        <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);17521753        Ok(())1754    }17551756    fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1757        let current_index = <ItemListIndex>::get(collection_id)1758            .checked_add(1)1759            .ok_or(Error::<T>::NumOverflow)?;1760        let itemcopy = item.clone();17611762        let value = item.owner.first().unwrap().fraction;1763        let owner = item.owner.first().unwrap().owner.clone();17641765        Self::add_token_index(collection_id, current_index, &owner)?;17661767        <ItemListIndex>::insert(collection_id, current_index);1768        <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);17691770        // Update balance1771        let new_balance = <Balance<T>>::get(collection_id, &owner)1772            .checked_add(value)1773            .ok_or(Error::<T>::NumOverflow)?;1774        <Balance<T>>::insert(collection_id, owner.clone(), new_balance);17751776        Ok(())1777    }17781779    fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1780        let current_index = <ItemListIndex>::get(collection_id)1781            .checked_add(1)1782            .ok_or(Error::<T>::NumOverflow)?;17831784        let item_owner = item.owner.clone();1785        Self::add_token_index(collection_id, current_index, &item.owner)?;17861787        <ItemListIndex>::insert(collection_id, current_index);1788        <NftItemList<T>>::insert(collection_id, current_index, item);17891790        // Update balance1791        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1792            .checked_add(1)1793            .ok_or(Error::<T>::NumOverflow)?;1794        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);17951796        Ok(())1797    }17981799    fn burn_refungible_item(1800        collection_id: CollectionId,1801        item_id: TokenId,1802        owner: &T::AccountId,1803    ) -> DispatchResult {1804        ensure!(1805            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1806            Error::<T>::TokenNotFound1807        );1808        let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id);1809        let rft_balance = token1810            .owner1811            .iter()1812            .filter(|&i| i.owner == *owner)1813            .next()1814            .unwrap();1815        Self::remove_token_index(collection_id, item_id, owner)?;18161817        // update balance1818        let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.clone())1819            .checked_sub(rft_balance.fraction)1820            .ok_or(Error::<T>::NumOverflow)?;1821        <Balance<T>>::insert(collection_id, rft_balance.owner.clone(), new_balance);18221823        // Re-create owners list with sender removed1824        let index = token1825            .owner1826            .iter()1827            .position(|i| i.owner == *owner)1828            .unwrap();1829        token.owner.remove(index);1830        let owner_count = token.owner.len();18311832        // Burn the token completely if this was the last (only) owner1833        if owner_count == 0 {1834            <ReFungibleItemList<T>>::remove(collection_id, item_id);1835        }1836        else {1837            <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1838        }18391840        Ok(())1841    }18421843    fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1844        ensure!(1845            <NftItemList<T>>::contains_key(collection_id, item_id),1846            Error::<T>::TokenNotFound1847        );1848        let item = <NftItemList<T>>::get(collection_id, item_id);1849        Self::remove_token_index(collection_id, item_id, &item.owner)?;18501851        // update balance1852        let new_balance = <Balance<T>>::get(collection_id, &item.owner)1853            .checked_sub(1)1854            .ok_or(Error::<T>::NumOverflow)?;1855        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1856        <NftItemList<T>>::remove(collection_id, item_id);18571858        Ok(())1859    }18601861    fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1862        ensure!(1863            <FungibleItemList<T>>::contains_key(collection_id, owner),1864            Error::<T>::TokenNotFound1865        );1866        let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1867        ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);18681869        // update balance1870        let new_balance = <Balance<T>>::get(collection_id, owner)1871            .checked_sub(value)1872            .ok_or(Error::<T>::NumOverflow)?;1873        <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);18741875        if balance.value - value > 0 {1876            balance.value -= value;1877            <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1878        }1879        else {1880            <FungibleItemList<T>>::remove(collection_id, owner);1881        }18821883        Ok(())1884    }18851886    fn collection_exists(collection_id: CollectionId) -> DispatchResult {1887        ensure!(1888            <Collection<T>>::contains_key(collection_id),1889            Error::<T>::CollectionNotFound1890        );1891        Ok(())1892    }18931894    fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1895        Self::collection_exists(collection_id)?;18961897        let target_collection = <Collection<T>>::get(collection_id);1898        ensure!(1899            subject == target_collection.owner,1900            Error::<T>::NoPermission1901        );19021903        Ok(())1904    }19051906    fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1907        let target_collection = <Collection<T>>::get(collection_id);1908        let mut result: bool = subject == target_collection.owner;1909        let exists = <AdminList<T>>::contains_key(collection_id);19101911        if !result & exists {1912            if <AdminList<T>>::get(collection_id).contains(&subject) {1913                result = true1914            }1915        }19161917        result1918    }19191920    fn check_owner_or_admin_permissions(1921        collection_id: CollectionId,1922        subject: T::AccountId,1923    ) -> DispatchResult {1924        Self::collection_exists(collection_id)?;1925        let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());19261927        ensure!(1928            result,1929            Error::<T>::NoPermission1930        );1931        Ok(())1932    }19331934    fn owned_amount(1935        subject: T::AccountId,1936        collection_id: CollectionId,1937        item_id: TokenId,1938    ) -> Option<u128> {1939        let target_collection = <Collection<T>>::get(collection_id);19401941        match target_collection.mode {1942            CollectionMode::NFT => {1943                if <NftItemList<T>>::get(collection_id, item_id).owner == subject {1944                    return Some(1)1945                }1946                None1947            },1948            CollectionMode::Fungible(_) => {1949                if <FungibleItemList<T>>::contains_key(collection_id, &subject) {1950                    return Some(<FungibleItemList<T>>::get(collection_id, &subject)1951                        .value);1952                }1953                None1954            },1955            CollectionMode::ReFungible => <ReFungibleItemList<T>>::get(collection_id, item_id)1956                .owner1957                .iter()1958                .find(|i| i.owner == subject)1959                .map(|i| i.fraction),1960            CollectionMode::Invalid => None,1961        }1962    }19631964    fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1965        let target_collection = <Collection<T>>::get(collection_id);19661967        match target_collection.mode {1968            CollectionMode::NFT => {1969                <NftItemList<T>>::get(collection_id, item_id).owner == subject1970            }1971            CollectionMode::Fungible(_) => {1972                <FungibleItemList<T>>::contains_key(collection_id, &subject)1973            }1974            CollectionMode::ReFungible => {1975                <ReFungibleItemList<T>>::get(collection_id, item_id)1976                    .owner1977                    .iter()1978                    .any(|i| i.owner == subject)1979            }1980            CollectionMode::Invalid => false,1981        }1982    }19831984    fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1985        let mes = Error::<T>::AddresNotInWhiteList;1986        ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);19871988        Ok(())1989    }19901991    /// Check if token exists. In case of Fungible, check if there is an entry for 1992    /// the owner in fungible balances double map1993    fn token_exists(1994        collection_id: CollectionId,1995        item_id: TokenId,1996        owner: &T::AccountId1997    ) -> DispatchResult {1998        let target_collection = <Collection<T>>::get(collection_id);1999        let exists = match target_collection.mode2000        {2001            CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),2002            CollectionMode::Fungible(_)  => <FungibleItemList<T>>::contains_key(collection_id, owner),2003            CollectionMode::ReFungible  => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),2004            _ => false2005        };20062007        ensure!(exists == true, Error::<T>::TokenNotFound);2008        Ok(())2009    }20102011    fn transfer_fungible(2012        collection_id: CollectionId,2013        value: u128,2014        owner: &T::AccountId,2015        recipient: &T::AccountId,2016    ) -> DispatchResult {2017        Self::token_exists(collection_id, 0, owner)?;20182019        let mut balance = <FungibleItemList<T>>::get(collection_id, owner);2020        ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);20212022        // Send balance to recipient (updates balanceOf of recipient)2023        Self::add_fungible_item(collection_id, recipient, value)?;20242025        // update balanceOf of sender2026        <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);20272028        // Reduce or remove sender2029        if balance.value == value {2030            <FungibleItemList<T>>::remove(collection_id, owner);2031        }2032        else {2033            balance.value -= value;2034            <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);2035        }20362037        Ok(())2038    }20392040    fn transfer_refungible(2041        collection_id: CollectionId,2042        item_id: TokenId,2043        value: u128,2044        owner: T::AccountId,2045        new_owner: T::AccountId,2046    ) -> DispatchResult {2047        Self::token_exists(collection_id, item_id, &owner)?;20482049        let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);2050        let item = full_item2051            .owner2052            .iter()2053            .filter(|i| i.owner == owner)2054            .next()2055            .ok_or(Error::<T>::NumOverflow)?;2056        let amount = item.fraction;20572058        ensure!(amount >= value, Error::<T>::TokenValueTooLow);20592060        // update balance2061        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2062            .checked_sub(value)2063            .ok_or(Error::<T>::NumOverflow)?;2064        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20652066        let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2067            .checked_add(value)2068            .ok_or(Error::<T>::NumOverflow)?;2069        <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);20702071        let old_owner = item.owner.clone();2072        let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);20732074        // transfer2075        if amount == value && !new_owner_has_account {2076            // change owner2077            // new owner do not have account2078            let mut new_full_item = full_item.clone();2079            new_full_item2080                .owner2081                .iter_mut()2082                .find(|i| i.owner == owner)2083                .unwrap()2084                .owner = new_owner.clone();2085            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);20862087            // update index collection2088            Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;2089        } else {2090            let mut new_full_item = full_item.clone();2091            new_full_item2092                .owner2093                .iter_mut()2094                .find(|i| i.owner == owner)2095                .unwrap()2096                .fraction -= value;20972098            // separate amount2099            if new_owner_has_account {2100                // new owner has account2101                new_full_item2102                    .owner2103                    .iter_mut()2104                    .find(|i| i.owner == new_owner)2105                    .unwrap()2106                    .fraction += value;2107            } else {2108                // new owner do not have account2109                new_full_item.owner.push(Ownership {2110                    owner: new_owner.clone(),2111                    fraction: value,2112                });2113                Self::add_token_index(collection_id, item_id, &new_owner)?;2114            }21152116            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2117        }21182119        Ok(())2120    }21212122    fn transfer_nft(2123        collection_id: CollectionId,2124        item_id: TokenId,2125        sender: T::AccountId,2126        new_owner: T::AccountId,2127    ) -> DispatchResult {2128        Self::token_exists(collection_id, item_id, &sender)?;21292130        let mut item = <NftItemList<T>>::get(collection_id, item_id);21312132        ensure!(2133            sender == item.owner,2134            Error::<T>::MustBeTokenOwner2135        );21362137        // update balance2138        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2139            .checked_sub(1)2140            .ok_or(Error::<T>::NumOverflow)?;2141        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);21422143        let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2144            .checked_add(1)2145            .ok_or(Error::<T>::NumOverflow)?;2146        <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);21472148        // change owner2149        let old_owner = item.owner.clone();2150        item.owner = new_owner.clone();2151        <NftItemList<T>>::insert(collection_id, item_id, item);21522153        // update index collection2154        Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;21552156        Ok(())2157    }2158    2159    fn set_re_fungible_variable_data(2160        collection_id: CollectionId,2161        item_id: TokenId,2162        data: Vec<u8>2163    ) -> DispatchResult {2164        let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);21652166        item.variable_data = data;21672168        <ReFungibleItemList<T>>::insert(collection_id, item_id, item);21692170        Ok(())2171    }21722173    fn set_nft_variable_data(2174        collection_id: CollectionId,2175        item_id: TokenId,2176        data: Vec<u8>2177    ) -> DispatchResult {2178        let mut item = <NftItemList<T>>::get(collection_id, item_id);2179        2180        item.variable_data = data;21812182        <NftItemList<T>>::insert(collection_id, item_id, item);2183        2184        Ok(())2185    }21862187    fn init_collection(item: &CollectionType<T::AccountId>) {2188        // check params2189        assert!(2190            item.decimal_points <= MAX_DECIMAL_POINTS,2191            "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2192        );2193        assert!(2194            item.name.len() <= 64,2195            "Collection name can not be longer than 63 char"2196        );2197        assert!(2198            item.name.len() <= 256,2199            "Collection description can not be longer than 255 char"2200        );2201        assert!(2202            item.token_prefix.len() <= 16,2203            "Token prefix can not be longer than 15 char"2204        );22052206        // Generate next collection ID2207        let next_id = CreatedCollectionCount::get()2208            .checked_add(1)2209            .unwrap();22102211        CreatedCollectionCount::put(next_id);2212    }22132214    fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2215        let current_index = <ItemListIndex>::get(collection_id)2216            .checked_add(1)2217            .unwrap();22182219        let item_owner = item.owner.clone();2220        Self::add_token_index(collection_id, current_index, &item.owner).unwrap();22212222        <ItemListIndex>::insert(collection_id, current_index);22232224        // Update balance2225        let new_balance = <Balance<T>>::get(collection_id, &item_owner)2226            .checked_add(1)2227            .unwrap();2228        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2229    }22302231    fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2232        let current_index = <ItemListIndex>::get(collection_id)2233            .checked_add(1)2234            .unwrap();22352236        Self::add_token_index(collection_id, current_index, owner).unwrap();22372238        <ItemListIndex>::insert(collection_id, current_index);22392240        // Update balance2241        let new_balance = <Balance<T>>::get(collection_id, owner)2242            .checked_add(item.value)2243            .unwrap();2244        <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2245    }22462247    fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2248        let current_index = <ItemListIndex>::get(collection_id)2249            .checked_add(1)2250            .unwrap();22512252        let value = item.owner.first().unwrap().fraction;2253        let owner = item.owner.first().unwrap().owner.clone();22542255        Self::add_token_index(collection_id, current_index, &owner).unwrap();22562257        <ItemListIndex>::insert(collection_id, current_index);22582259        // Update balance2260        let new_balance = <Balance<T>>::get(collection_id, &owner)2261            .checked_add(value)2262            .unwrap();2263        <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2264    }22652266    fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {22672268        // add to account limit2269        if <AccountItemCount<T>>::contains_key(owner) {22702271            // bound Owned tokens by a single address2272            let count = <AccountItemCount<T>>::get(owner);2273            ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);22742275            <AccountItemCount<T>>::insert(owner.clone(), count2276                .checked_add(1)2277                .ok_or(Error::<T>::NumOverflow)?);2278        }2279        else {2280            <AccountItemCount<T>>::insert(owner.clone(), 1);2281        }22822283        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2284        if list_exists {2285            let mut list = <AddressTokens<T>>::get(collection_id, owner);2286            let item_contains = list.contains(&item_index.clone());22872288            if !item_contains {2289                list.push(item_index.clone());2290            }22912292            <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2293        } else {2294            let mut itm = Vec::new();2295            itm.push(item_index.clone());2296            <AddressTokens<T>>::insert(collection_id, owner.clone(), itm);2297        }22982299        Ok(())2300    }23012302    fn remove_token_index(2303        collection_id: CollectionId,2304        item_index: TokenId,2305        owner: &T::AccountId,2306    ) -> DispatchResult {23072308        // update counter2309        <AccountItemCount<T>>::insert(owner.clone(), 2310            <AccountItemCount<T>>::get(owner)2311            .checked_sub(1)2312            .ok_or(Error::<T>::NumOverflow)?);231323142315        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2316        if list_exists {2317            let mut list = <AddressTokens<T>>::get(collection_id, owner);2318            let item_contains = list.contains(&item_index.clone());23192320            if item_contains {2321                list.retain(|&item| item != item_index);2322                <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2323            }2324        }23252326        Ok(())2327    }23282329    fn move_token_index(2330        collection_id: CollectionId,2331        item_index: TokenId,2332        old_owner: &T::AccountId,2333        new_owner: &T::AccountId,2334    ) -> DispatchResult {2335        Self::remove_token_index(collection_id, item_index, old_owner)?;2336        Self::add_token_index(collection_id, item_index, new_owner)?;23372338        Ok(())2339    }2340    2341    fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2342        if <ContractOwner<T>>::contains_key(contract.clone()) {2343            let owner = <ContractOwner<T>>::get(contract);2344            ensure!(account == owner, Error::<T>::NoPermission);2345        } else {2346            fail!(Error::<T>::NoPermission);2347        }23482349        Ok(())2350    }2351}23522353////////////////////////////////////////////////////////////////////////////////////////////////////2354// Economic models2355// #region23562357/// Fee multiplier.2358pub type Multiplier = FixedU128;23592360type BalanceOf<T> = <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::Balance;23612362/// Require the transactor pay for themselves and maybe include a tip to gain additional priority2363/// in the queue.2364#[derive(Encode, Decode, Clone, Eq, PartialEq)]2365pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);23662367impl<T: Config + Send + Sync> sp_std::fmt::Debug 2368    for ChargeTransactionPayment<T>2369{2370	#[cfg(feature = "std")]2371	fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2372		write!(f, "ChargeTransactionPayment<{:?}>", self.0)2373	}2374	#[cfg(not(feature = "std"))]2375	fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2376		Ok(())2377	}2378}23792380impl<T: Config> ChargeTransactionPayment<T>2381where2382    T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2383    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2384    T::AccountId: AsRef<[u8]>,2385    T::AccountId: UncheckedFrom<T::Hash>,2386{2387    fn traditional_fee(2388        len: usize,2389        info: &DispatchInfoOf<T::Call>,2390        tip: BalanceOf<T>,2391    ) -> BalanceOf<T>2392    where2393        T::Call: Dispatchable<Info = DispatchInfo>,2394    {2395        <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2396    }23972398	fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2399        let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1);2400        let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal);2401        let len_saturation = max_block_length as u64 / (len as u64).max(1);2402        let coefficient: BalanceOf<T> = weight_saturation2403            .min(len_saturation)2404            .saturated_into::<BalanceOf<T>>();2405        final_fee2406            .saturating_mul(coefficient)2407            .saturated_into::<TransactionPriority>()2408    }24092410    fn withdraw_fee(2411        &self,2412        who: &T::AccountId,2413        call: &T::Call,2414        info: &DispatchInfoOf<T::Call>,2415        len: usize,2416	) -> Result<2417		(2418			BalanceOf<T>,2419			<<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2420		),2421		TransactionValidityError,2422	> {2423        let tip = self.0;24242425        // Set fee based on call type. Creating collection costs 1 Unique.2426        // All other transactions have traditional fees so far2427        // let fee = match call.is_sub_type() {2428        //     Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),2429        //     _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes2430        //                                                 // _ => <BalanceOf<T>>::from(100)2431        // };2432        let fee = Self::traditional_fee(len, info, tip);24332434        // Only mess with balances if fee is not zero.2435        if fee.is_zero() {2436            return <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::withdraw_fee(who, call, info, fee, tip)2437			.map(|i| (fee, i));2438        }24392440        // Determine who is paying transaction fee based on ecnomic model2441        // Parse call to extract collection ID and access collection sponsor2442        let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2443            Some(Call::create_item(collection_id, _owner, _properties)) => {24442445                // sponsor timeout2446                let block_number = <system::Module<T>>::block_number() as T::BlockNumber;24472448                let limit = <Collection<T>>::get(collection_id).limits.sponsor_transfer_timeout;2449                let mut sponsored = true;2450                if <CreateItemBasket<T>>::contains_key((collection_id, &who)) {2451                    let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2452                    let limit_time = last_tx_block + limit.into();2453                    if block_number <= limit_time {2454                        sponsored = false;2455                    }2456                }2457                if sponsored {2458                    <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2459                }24602461                // check free create limit2462                if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2463                   (<Collection<T>>::get(collection_id).sponsor_confirmed) &&2464                   (sponsored)2465                {2466                    <Collection<T>>::get(collection_id).sponsor2467                } else {2468                    T::AccountId::default()2469                }2470            }2471            Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2472                2473                let mut sponsor_transfer = false;2474                if <Collection<T>>::get(collection_id).sponsor_confirmed {24752476                    let collection_limits = <Collection<T>>::get(collection_id).limits;2477                    let collection_mode = <Collection<T>>::get(collection_id).mode;2478    2479                    // sponsor timeout2480                    let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2481                    sponsor_transfer = match collection_mode {2482                        CollectionMode::NFT => {2483    2484                            // get correct limit2485                            let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2486                                collection_limits.sponsor_transfer_timeout2487                            } else {2488                                ChainLimit::get().nft_sponsor_transfer_timeout2489                            };2490    2491                            let mut sponsored = true;2492                            if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2493                                let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2494                                let limit_time = last_tx_block + limit.into();2495                                if block_number <= limit_time {2496                                    sponsored = false;2497                                }2498                            }2499                            if sponsored {2500                                <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2501                            }25022503                            sponsored2504                        }2505                        CollectionMode::Fungible(_) => {2506    2507                            // get correct limit2508                            let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2509                                collection_limits.sponsor_transfer_timeout2510                            } else {2511                                ChainLimit::get().fungible_sponsor_transfer_timeout2512                            };2513    2514                            let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2515                            let mut sponsored = true;2516                            if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2517                                let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2518                                let limit_time = last_tx_block + limit.into();2519                                if block_number <= limit_time {2520                                    sponsored = false;2521                                }2522                            }2523                            if sponsored {2524                                <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2525                            }25262527                            sponsored2528                        }2529                        CollectionMode::ReFungible => {2530    2531                            // get correct limit2532                            let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2533                                collection_limits.sponsor_transfer_timeout2534                            } else {2535                                ChainLimit::get().refungible_sponsor_transfer_timeout2536                            };2537    2538                            let mut sponsored = true;2539                            if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2540                                let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2541                                let limit_time = last_tx_block + limit.into();2542                                if block_number <= limit_time {2543                                    sponsored = false;2544                                }2545                            }2546                            if sponsored {2547                                <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2548                            }25492550                            sponsored2551                        }2552                        _ => {2553                            false2554                        },2555                    };2556                }25572558                if !sponsor_transfer {2559                    T::AccountId::default()2560                } else {2561                    <Collection<T>>::get(collection_id).sponsor2562                }2563            }25642565            _ => T::AccountId::default(),2566        };25672568        // Sponsor smart contracts2569        sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {25702571            // On instantiation: set the contract owner2572            Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => {25732574                let new_contract_address = <pallet_contracts::Module<T>>::contract_address(2575                    &who,2576                    code_hash,2577                    salt,2578                );2579                <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());25802581                T::AccountId::default()2582            },25832584            // When the contract is called, check if the sponsoring is enabled and pay fees from contract endowment if it is2585            Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {25862587                let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());25882589                let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2590                  && <ContractOwner<T>>::get(called_contract.clone()) == *who;2591                let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2592                  2593                if !owned_contract && white_list_enabled {2594                    if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2595                        return Err(InvalidTransaction::Call.into());2596                    }2597                }25982599                let mut sponsor_transfer = false;2600                if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2601                    let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2602                    let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2603                    let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2604                    let limit_time = last_tx_block + rate_limit;26052606                    if block_number >= limit_time {2607                        <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2608                        sponsor_transfer = true;2609                    }2610                } else {2611                    sponsor_transfer = false;2612                }2613               2614                2615                let mut sp = T::AccountId::default();2616                if sponsor_transfer {2617                    if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2618                        if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2619                            sp = called_contract;2620                        }2621                    }2622                }26232624                sp2625            },26262627            _ => sponsor,2628        };26292630        let mut who_pays_fee: T::AccountId = sponsor.clone();2631        if sponsor == T::AccountId::default() {2632            who_pays_fee = who.clone();2633        }26342635		<<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)2636			.map(|i| (fee, i))2637    }2638}263926402641impl<T: Config + Send + Sync> SignedExtension2642    for ChargeTransactionPayment<T>2643where2644    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2645    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2646    T::AccountId: AsRef<[u8]>,2647    T::AccountId: UncheckedFrom<T::Hash>,2648{2649    const IDENTIFIER: &'static str = "ChargeTransactionPayment";2650    type AccountId = T::AccountId;2651    type Call = T::Call;2652    type AdditionalSigned = ();2653    type Pre = (2654        // tip2655        BalanceOf<T>,2656        // who pays fee2657        Self::AccountId,2658		// imbalance resulting from withdrawing the fee2659		<<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2660    );2661    fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2662        Ok(())2663    }26642665    fn validate(2666        &self,2667        who: &Self::AccountId,2668        call: &Self::Call,2669        info: &DispatchInfoOf<Self::Call>,2670        len: usize,2671    ) -> TransactionValidity {2672		let (fee, _) = self.withdraw_fee(who, call, info, len)?;2673		Ok(ValidTransaction {2674			priority: Self::get_priority(len, info, fee),2675			..Default::default()2676		})2677    }26782679    fn pre_dispatch(2680        self,2681        who: &Self::AccountId,2682        call: &Self::Call,2683        info: &DispatchInfoOf<Self::Call>,2684        len: usize,2685    ) -> Result<Self::Pre, TransactionValidityError> {2686        let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2687        Ok((self.0, who.clone(), imbalance))2688    }26892690    fn post_dispatch(2691        pre: Self::Pre,2692        info: &DispatchInfoOf<Self::Call>,2693        post_info: &PostDispatchInfoOf<Self::Call>,2694        len: usize,2695        _result: &DispatchResult,2696    ) -> Result<(), TransactionValidityError> {2697		let (tip, who, imbalance) = pre;2698		let actual_fee = transaction_payment::Module::<T>::compute_actual_fee(2699			len as u32,2700			info,2701			post_info,2702			tip,2703		);2704		<T as transaction_payment::Config>::OnChargeTransaction::correct_and_deposit_fee(&who, info, post_info, actual_fee, tip, imbalance)?;2705		Ok(())2706    }2707}27082709// #endregion
after · pallets/nft/src/lib.rs
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56#![recursion_limit = "1024"]78#![cfg_attr(not(feature = "std"), no_std)]910#[cfg(feature = "std")]11pub use std::*;1213#[cfg(feature = "std")]14pub use serde::*;1516use codec::{Decode, Encode};17pub use frame_support::{18    construct_runtime, decl_event, decl_module, decl_storage, decl_error,19    dispatch::DispatchResult,20    ensure, fail, parameter_types,21    traits::{22        Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,23        Randomness, IsSubType,24    },25    weights::{26        constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},27        DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,28        WeightToFeePolynomial, DispatchClass,29    },30    StorageValue,31};3233use frame_system::{self as system, ensure_signed, ensure_root};34use sp_runtime::sp_std::prelude::Vec;35use sp_runtime::{36    traits::{37        Hash, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion, SignedExtension, Zero,38    },39    transaction_validity::{40        TransactionPriority, InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,41    },42    FixedPointOperand, FixedU128,43};44use sp_runtime::traits::StaticLookup;45use pallet_contracts::chain_extension::UncheckedFrom;46use pallet_transaction_payment::OnChargeTransaction;4748#[cfg(test)]49mod mock;5051#[cfg(test)]52mod tests;5354mod default_weights;5556pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;57pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;58pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;59pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;6061// Structs62// #region6364pub type CollectionId = u32;65pub type TokenId = u32;66pub type DecimalPoints = u8;6768#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]69#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]70pub enum CollectionMode {71    Invalid,72    NFT,73    // decimal points74    Fungible(DecimalPoints),75    ReFungible,76}7778impl Default for CollectionMode {79    fn default() -> Self {80        Self::Invalid81    }82}8384impl Into<u8> for CollectionMode {85    fn into(self) -> u8 {86        match self {87            CollectionMode::Invalid => 0,88            CollectionMode::NFT => 1,89            CollectionMode::Fungible(_) => 2,90            CollectionMode::ReFungible => 3,91        }92    }93}9495#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]96#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]97pub enum AccessMode {98    Normal,99    WhiteList,100}101impl Default for AccessMode {102    fn default() -> Self {103        Self::Normal104    }105}106107#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]108#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]109pub enum SchemaVersion {110    ImageURL,111    Unique,112}113impl Default for SchemaVersion {114    fn default() -> Self {115        Self::ImageURL116    }117}118119#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]120#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]121pub struct Ownership<AccountId> {122    pub owner: AccountId,123    pub fraction: u128,124}125126#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]127#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]128pub struct CollectionType<AccountId> {129    pub owner: AccountId,130    pub mode: CollectionMode,131    pub access: AccessMode,132    pub decimal_points: DecimalPoints,133    pub name: Vec<u16>,        // 64 include null escape char134    pub description: Vec<u16>, // 256 include null escape char135    pub token_prefix: Vec<u8>, // 16 include null escape char136    pub mint_mode: bool,137    pub offchain_schema: Vec<u8>,138    pub schema_version: SchemaVersion,139    pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender140    pub sponsor_confirmed: bool, // False if sponsor address has not yet confirmed sponsorship. True otherwise.141    pub limits: CollectionLimits, // Collection private restrictions 142    pub variable_on_chain_schema: Vec<u8>, //143    pub const_on_chain_schema: Vec<u8>, //144}145146#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]147#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]148pub struct NftItemType<AccountId> {149    pub owner: AccountId,150    pub const_data: Vec<u8>,151    pub variable_data: Vec<u8>,152}153154#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]155#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]156pub struct FungibleItemType {157    pub value: u128,158}159160#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]161#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]162pub struct ReFungibleItemType<AccountId> {163    pub owner: Vec<Ownership<AccountId>>,164    pub const_data: Vec<u8>,165    pub variable_data: Vec<u8>,166}167168// #[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]169// #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]170// pub struct VestingItem<AccountId, Moment> {171//     pub sender: AccountId,172//     pub recipient: AccountId,173//     pub collection_id: CollectionId,174//     pub item_id: TokenId,175//     pub amount: u64,176//     pub vesting_date: Moment,177// }178179#[derive(Encode, Decode, Debug, Clone, PartialEq)]180#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]181pub struct CollectionLimits {182    pub account_token_ownership_limit: u32,183    pub sponsored_data_size: u32,184    pub token_limit: u32,185186    // Timeouts for item types in passed blocks187    pub sponsor_transfer_timeout: u32,188    pub owner_can_transfer: bool,189    pub owner_can_destroy: bool,190}191192impl Default for CollectionLimits {193    fn default() -> CollectionLimits {194        CollectionLimits { 195            account_token_ownership_limit: 10_000_000, 196            token_limit: u32::max_value(),197            sponsored_data_size: u32::MAX,198            sponsor_transfer_timeout: 14400,199            owner_can_transfer: true,200            owner_can_destroy: true201        }202    }203}204205#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]206#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]207pub struct ChainLimits {208    pub collection_numbers_limit: u32,209    pub account_token_ownership_limit: u32,210    pub collections_admins_limit: u64,211    pub custom_data_limit: u32,212213    // Timeouts for item types in passed blocks214    pub nft_sponsor_transfer_timeout: u32,215    pub fungible_sponsor_transfer_timeout: u32,216    pub refungible_sponsor_transfer_timeout: u32,217218    // Schema limits219    pub offchain_schema_limit: u32,220    pub variable_on_chain_schema_limit: u32,221    pub const_on_chain_schema_limit: u32,222}223224pub trait WeightInfo {225	fn create_collection() -> Weight;226	fn destroy_collection() -> Weight;227	fn add_to_white_list() -> Weight;228	fn remove_from_white_list() -> Weight;229    fn set_public_access_mode() -> Weight;230    fn set_mint_permission() -> Weight;231    fn change_collection_owner() -> Weight;232    fn add_collection_admin() -> Weight;233    fn remove_collection_admin() -> Weight;234    fn set_collection_sponsor() -> Weight;235    fn confirm_sponsorship() -> Weight;236    fn remove_collection_sponsor() -> Weight;237    fn create_item(s: usize) -> Weight;238    fn burn_item() -> Weight;239    fn transfer() -> Weight;240    fn approve() -> Weight;241    fn transfer_from() -> Weight;242    fn set_offchain_schema() -> Weight;243    fn set_const_on_chain_schema() -> Weight;244    fn set_variable_on_chain_schema() -> Weight;245    fn set_variable_meta_data() -> Weight;246    fn enable_contract_sponsoring() -> Weight;247    fn set_schema_version() -> Weight;248    fn set_chain_limits() -> Weight;249    fn set_contract_sponsoring_rate_limit() -> Weight;250    fn toggle_contract_white_list() -> Weight;251    fn add_to_contract_white_list() -> Weight;252    fn remove_from_contract_white_list() -> Weight;253    fn set_collection_limits() -> Weight;254}255256#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]257#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]258pub struct CreateNftData {259    pub const_data: Vec<u8>,260    pub variable_data: Vec<u8>,261}262263#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]264#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]265pub struct CreateFungibleData {266    pub value: u128,267}268269#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]270#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]271pub struct CreateReFungibleData {272    pub const_data: Vec<u8>,273    pub variable_data: Vec<u8>,274    pub pieces: u128,275}276277#[derive(Encode, Decode, Debug, Clone, PartialEq)]278#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]279pub enum CreateItemData {280    NFT(CreateNftData),281    Fungible(CreateFungibleData),282    ReFungible(CreateReFungibleData),283}284285impl CreateItemData {286    pub fn len(&self) -> usize {287        let len = match self {288            CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),289            CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),290            _ => 0291        };292        293        return len;294    }295}296297impl From<CreateNftData> for CreateItemData {298    fn from(item: CreateNftData) -> Self {299        CreateItemData::NFT(item)300    }301}302303impl From<CreateReFungibleData> for CreateItemData {304    fn from(item: CreateReFungibleData) -> Self {305        CreateItemData::ReFungible(item)306    }307}308309impl From<CreateFungibleData> for CreateItemData {310    fn from(item: CreateFungibleData) -> Self {311        CreateItemData::Fungible(item)312    }313}314315316decl_error! {317	/// Error for non-fungible-token module.318	pub enum Error for Module<T: Config> {319        /// Total collections bound exceeded.320        TotalCollectionsLimitExceeded,321		/// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.322        CollectionDecimalPointLimitExceeded, 323        /// Collection name can not be longer than 63 char.324        CollectionNameLimitExceeded, 325        /// Collection description can not be longer than 255 char.326        CollectionDescriptionLimitExceeded, 327        /// Token prefix can not be longer than 15 char.328        CollectionTokenPrefixLimitExceeded,329        /// This collection does not exist.330        CollectionNotFound,331        /// Item not exists.332        TokenNotFound,333        /// Admin not found334        AdminNotFound,335        /// Arithmetic calculation overflow.336        NumOverflow,       337        /// Account already has admin role.338        AlreadyAdmin,  339        /// You do not own this collection.340        NoPermission,341        /// This address is not set as sponsor, use setCollectionSponsor first.342        ConfirmUnsetSponsorFail,343        /// Collection is not in mint mode.344        PublicMintingNotAllowed,345        /// Sender parameter and item owner must be equal.346        MustBeTokenOwner,347        /// Item balance not enough.348        TokenValueTooLow,349        /// Size of item is too large.350        NftSizeLimitExceeded,351        /// No approve found352        ApproveNotFound,353        /// Requested value more than approved.354        TokenValueNotEnough,355        /// Only approved addresses can call this method.356        ApproveRequired,357        /// Address is not in white list.358        AddresNotInWhiteList,359        /// Number of collection admins bound exceeded.360        CollectionAdminsLimitExceeded,361        /// Owned tokens by a single address bound exceeded.362        AddressOwnershipLimitExceeded,363        /// Length of items properties must be greater than 0.364        EmptyArgument,365        /// const_data exceeded data limit.366        TokenConstDataLimitExceeded,367        /// variable_data exceeded data limit.368        TokenVariableDataLimitExceeded,369        /// Not NFT item data used to mint in NFT collection.370        NotNftDataUsedToMintNftCollectionToken,371        /// Not Fungible item data used to mint in Fungible collection.372        NotFungibleDataUsedToMintFungibleCollectionToken,373        /// Not Re Fungible item data used to mint in Re Fungible collection.374        NotReFungibleDataUsedToMintReFungibleCollectionToken,375        /// Unexpected collection type.376        UnexpectedCollectionType,377        /// Can't store metadata in fungible tokens.378        CantStoreMetadataInFungibleTokens,379        /// Collection token limit exceeded380        CollectionTokenLimitExceeded,381        /// Account token limit exceeded per collection382        AccountTokenLimitExceeded,383        /// Collection limit bounds per collection exceeded384        CollectionLimitBoundsExceeded,385        /// Tried to enable permissions which are only permitted to be disabled386        OwnerPermissionsCantBeReverted,387        /// Schema data size limit bound exceeded388        SchemaDataLimitExceeded,389        /// Maximum refungibility exceeded390        WrongRefungiblePieces391	}392}393394pub trait Config: system::Config + Sized + pallet_transaction_payment::Config + pallet_contracts::Config {395    type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;396397    /// Weight information for extrinsics in this pallet.398	type WeightInfo: WeightInfo;399}400401#[cfg(feature = "runtime-benchmarks")]402mod benchmarking;403404// #endregion405406decl_storage! {407    trait Store for Module<T: Config> as Nft {408409        // Private members410        NextCollectionID: CollectionId;411        CreatedCollectionCount: u32;412        ChainVersion: u64;413        ItemListIndex: map hasher(identity) CollectionId => TokenId;414415        // Chain limits struct416        pub ChainLimit get(fn chain_limit) config(): ChainLimits;417418        // Bound counters419        CollectionCount: u32;420        pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;421422        // Basic collections423        pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;424        pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;425        pub WhiteList get(fn white_list): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => bool;426427        /// Balance owner per collection map428        pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;429430        /// second parameter: item id + owner account id + spender account id431        pub Allowances get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId, T::AccountId) => u128;432433        /// Item collections434        pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;435        pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => FungibleItemType;436        pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;437438        /// Index list439        pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;440441        /// Tokens transfer baskets442        pub CreateItemBasket get(fn create_item_basket): map hasher(twox_64_concat) (CollectionId, T::AccountId) => T::BlockNumber;443        pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;444        pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;445        pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;446447        // Contract Sponsorship and Ownership448        pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;449        pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;450        pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;451        pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;452        pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 453        pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId => bool; 454    }455    add_extra_genesis {456        build(|config: &GenesisConfig<T>| {457            // Modification of storage458            for (_num, _c) in &config.collection {459                <Module<T>>::init_collection(_c);460            }461462            for (_num, _c, _i) in &config.nft_item_id {463                <Module<T>>::init_nft_token(*_c, _i);464            }465466            for (collection_id, account_id, fungible_item) in &config.fungible_item_id {467                <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);468            }469470            for (_num, _c, _i) in &config.refungible_item_id {471                <Module<T>>::init_refungible_token(*_c, _i);472            }473        })474    }475}476477decl_event!(478    pub enum Event<T>479    where480        AccountId = <T as system::Config>::AccountId,481    {482        /// New collection was created483        /// 484        /// # Arguments485        /// 486        /// * collection_id: Globally unique identifier of newly created collection.487        /// 488        /// * mode: [CollectionMode] converted into u8.489        /// 490        /// * account_id: Collection owner.491        Created(CollectionId, u8, AccountId),492493        /// New item was created.494        /// 495        /// # Arguments496        /// 497        /// * collection_id: Id of the collection where item was created.498        /// 499        /// * item_id: Id of an item. Unique within the collection.500        ///501        /// * recipient: Owner of newly created item 502        ItemCreated(CollectionId, TokenId, AccountId),503504        /// Collection item was burned.505        /// 506        /// # Arguments507        /// 508        /// collection_id.509        /// 510        /// item_id: Identifier of burned NFT.511        ItemDestroyed(CollectionId, TokenId),512513        /// Item was transferred514        ///515        /// * collection_id: Id of collection to which item is belong516        ///517        /// * item_id: Id of an item518        ///519        /// * sender: Original owner of item520        ///521        /// * recipient: New owner of item522        ///523        /// * amount: Always 1 for NFT524        Transfer(CollectionId, TokenId, AccountId, AccountId, u128),525    }526);527528decl_module! {529    pub struct Module<T: Config> for enum Call 530    where 531        origin: T::Origin532    {533        fn deposit_event() = default;534        type Error = Error<T>;535536        fn on_initialize(now: T::BlockNumber) -> Weight {537538            if ChainVersion::get() < 2539            {540                let value = NextCollectionID::get();541                CreatedCollectionCount::put(value);542                ChainVersion::put(2);543            }544545            0546        }547548        /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner and admin of the collection are set to the address that signed the transaction. Both addresses can be changed later.549        /// 550        /// # Permissions551        /// 552        /// * Anyone.553        /// 554        /// # Arguments555        /// 556        /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.557        /// 558        /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.559        /// 560        /// * token_prefix: UTF-8 string with token prefix.561        /// 562        /// * mode: [CollectionMode] collection type and type dependent data.563        // returns collection ID564        #[weight = <T as Config>::WeightInfo::create_collection()]565        pub fn create_collection(origin,566                                 collection_name: Vec<u16>,567                                 collection_description: Vec<u16>,568                                 token_prefix: Vec<u8>,569                                 mode: CollectionMode) -> DispatchResult {570571            // Anyone can create a collection572            let who = ensure_signed(origin)?;573574            let decimal_points = match mode {575                CollectionMode::Fungible(points) => points,576                _ => 0577            };578579            let chain_limit = ChainLimit::get();580581            // bound Total number of collections582            ensure!(CollectionCount::get() < chain_limit.collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);583584            // check params585            ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);586            ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);587            ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);588            ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);589590            // Generate next collection ID591            let next_id = CreatedCollectionCount::get()592                .checked_add(1)593                .ok_or(Error::<T>::NumOverflow)?;594595            // bound counter596            let total = CollectionCount::get()597                .checked_add(1)598                .ok_or(Error::<T>::NumOverflow)?;599600            CreatedCollectionCount::put(next_id);601            CollectionCount::put(total);602603            let limits = CollectionLimits {604                sponsored_data_size: chain_limit.custom_data_limit,605                ..Default::default()606            };607608            // Create new collection609            let new_collection = CollectionType {610                owner: who.clone(),611                name: collection_name,612                mode: mode.clone(),613                mint_mode: false,614                access: AccessMode::Normal,615                description: collection_description,616                decimal_points: decimal_points,617                token_prefix: token_prefix,618                offchain_schema: Vec::new(),619                schema_version: SchemaVersion::ImageURL,620                sponsor: T::AccountId::default(),621                sponsor_confirmed: false,622                variable_on_chain_schema: Vec::new(),623                const_on_chain_schema: Vec::new(),624                limits,625            };626627            // Add new collection to map628            <Collection<T>>::insert(next_id, new_collection);629630            // call event631            Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));632633            Ok(())634        }635636        /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.637        /// 638        /// # Permissions639        /// 640        /// * Collection Owner.641        /// 642        /// # Arguments643        /// 644        /// * collection_id: collection to destroy.645        #[weight = <T as Config>::WeightInfo::destroy_collection()]646        pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {647648            let sender = ensure_signed(origin)?;649            Self::check_owner_permissions(collection_id, sender)?;650651            let target_collection = <Collection<T>>::get(collection_id);652            if !target_collection.limits.owner_can_destroy {653                fail!(Error::<T>::NoPermission);654            }655656            <AddressTokens<T>>::remove_prefix(collection_id);657            <Allowances<T>>::remove_prefix(collection_id);658            <Balance<T>>::remove_prefix(collection_id);659            <ItemListIndex>::remove(collection_id);660            <AdminList<T>>::remove(collection_id);661            <Collection<T>>::remove(collection_id);662            <WhiteList<T>>::remove_prefix(collection_id);663664            <NftItemList<T>>::remove_prefix(collection_id);665            <FungibleItemList<T>>::remove_prefix(collection_id);666            <ReFungibleItemList<T>>::remove_prefix(collection_id);667668            <NftTransferBasket<T>>::remove_prefix(collection_id);669            <FungibleTransferBasket<T>>::remove_prefix(collection_id);670            <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);671672            if CollectionCount::get() > 0673            {674                // bound couter675                let total = CollectionCount::get()676                    .checked_sub(1)677                    .ok_or(Error::<T>::NumOverflow)?;678679                CollectionCount::put(total);680            }681682            Ok(())683        }684685        /// Add an address to white list.686        /// 687        /// # Permissions688        /// 689        /// * Collection Owner690        /// * Collection Admin691        /// 692        /// # Arguments693        /// 694        /// * collection_id.695        /// 696        /// * address.697        #[weight = <T as Config>::WeightInfo::add_to_white_list()]698        pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{699700            let sender = ensure_signed(origin)?;701            Self::check_owner_or_admin_permissions(collection_id, sender)?;702703            <WhiteList<T>>::insert(collection_id, address, true);704            705            Ok(())706        }707708        /// Remove an address from white list.709        /// 710        /// # Permissions711        /// 712        /// * Collection Owner713        /// * Collection Admin714        /// 715        /// # Arguments716        /// 717        /// * collection_id.718        /// 719        /// * address.720        #[weight = <T as Config>::WeightInfo::remove_from_white_list()]721        pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{722723            let sender = ensure_signed(origin)?;724            Self::check_owner_or_admin_permissions(collection_id, sender)?;725726            <WhiteList<T>>::remove(collection_id, address);727728            Ok(())729        }730731        /// Toggle between normal and white list access for the methods with access for `Anyone`.732        /// 733        /// # Permissions734        /// 735        /// * Collection Owner.736        /// 737        /// # Arguments738        /// 739        /// * collection_id.740        /// 741        /// * mode: [AccessMode]742        #[weight = <T as Config>::WeightInfo::set_public_access_mode()]743        pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult744        {745            let sender = ensure_signed(origin)?;746747            Self::check_owner_permissions(collection_id, sender)?;748            let mut target_collection = <Collection<T>>::get(collection_id);749            target_collection.access = mode;750            <Collection<T>>::insert(collection_id, target_collection);751752            Ok(())753        }754755        /// Allows Anyone to create tokens if:756        /// * White List is enabled, and757        /// * Address is added to white list, and758        /// * This method was called with True parameter759        /// 760        /// # Permissions761        /// * Collection Owner762        ///763        /// # Arguments764        /// 765        /// * collection_id.766        /// 767        /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.768        #[weight = <T as Config>::WeightInfo::set_mint_permission()]769        pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult770        {771            let sender = ensure_signed(origin)?;772773            Self::check_owner_permissions(collection_id, sender)?;774            let mut target_collection = <Collection<T>>::get(collection_id);775            target_collection.mint_mode = mint_permission;776            <Collection<T>>::insert(collection_id, target_collection);777778            Ok(())779        }780781        /// Change the owner of the collection.782        /// 783        /// # Permissions784        /// 785        /// * Collection Owner.786        /// 787        /// # Arguments788        /// 789        /// * collection_id.790        /// 791        /// * new_owner.792        #[weight = <T as Config>::WeightInfo::change_collection_owner()]793        pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {794795            let sender = ensure_signed(origin)?;796            Self::check_owner_permissions(collection_id, sender)?;797            let mut target_collection = <Collection<T>>::get(collection_id);798            target_collection.owner = new_owner;799            <Collection<T>>::insert(collection_id, target_collection);800801            Ok(())802        }803804        /// Adds an admin of the Collection.805        /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership. 806        /// 807        /// # Permissions808        /// 809        /// * Collection Owner.810        /// * Collection Admin.811        /// 812        /// # Arguments813        /// 814        /// * collection_id: ID of the Collection to add admin for.815        /// 816        /// * new_admin_id: Address of new admin to add.817        #[weight = <T as Config>::WeightInfo::add_collection_admin()]818        pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {819820            let sender = ensure_signed(origin)?;821            Self::check_owner_or_admin_permissions(collection_id, sender)?;822            let mut admin_arr: Vec<T::AccountId> = Vec::new();823824            if <AdminList<T>>::contains_key(collection_id)825            {826                admin_arr = <AdminList<T>>::get(collection_id);827                ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);828            }829830            // Number of collection admins831            ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);832833            admin_arr.push(new_admin_id);834            <AdminList<T>>::insert(collection_id, admin_arr);835836            Ok(())837        }838839        /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.840        ///841        /// # Permissions842        /// 843        /// * Collection Owner.844        /// * Collection Admin.845        /// 846        /// # Arguments847        /// 848        /// * collection_id: ID of the Collection to remove admin for.849        /// 850        /// * account_id: Address of admin to remove.851        #[weight = <T as Config>::WeightInfo::remove_collection_admin()]852        pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {853854            let sender = ensure_signed(origin)?;855            Self::check_owner_or_admin_permissions(collection_id, sender)?;856            ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);857858            let mut admin_arr = <AdminList<T>>::get(collection_id);859            admin_arr.retain(|i| *i != account_id);860            <AdminList<T>>::insert(collection_id, admin_arr);861862            Ok(())863        }864865        /// # Permissions866        /// 867        /// * Collection Owner868        /// 869        /// # Arguments870        /// 871        /// * collection_id.872        /// 873        /// * new_sponsor.874        #[weight = <T as Config>::WeightInfo::set_collection_sponsor()]875        pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {876877            let sender = ensure_signed(origin)?;878            ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);879880            let mut target_collection = <Collection<T>>::get(collection_id);881            ensure!(sender == target_collection.owner, Error::<T>::NoPermission);882883            target_collection.sponsor = new_sponsor;884            target_collection.sponsor_confirmed = false;885            <Collection<T>>::insert(collection_id, target_collection);886887            Ok(())888        }889890        /// # Permissions891        /// 892        /// * Sponsor.893        /// 894        /// # Arguments895        /// 896        /// * collection_id.897        #[weight = <T as Config>::WeightInfo::confirm_sponsorship()]898        pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {899900            let sender = ensure_signed(origin)?;901            ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);902903            let mut target_collection = <Collection<T>>::get(collection_id);904            ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);905906            target_collection.sponsor_confirmed = true;907            <Collection<T>>::insert(collection_id, target_collection);908909            Ok(())910        }911912        /// Switch back to pay-per-own-transaction model.913        ///914        /// # Permissions915        ///916        /// * Collection owner.917        /// 918        /// # Arguments919        /// 920        /// * collection_id.921        #[weight = <T as Config>::WeightInfo::remove_collection_sponsor()]922        pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {923924            let sender = ensure_signed(origin)?;925            ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);926927            let mut target_collection = <Collection<T>>::get(collection_id);928            ensure!(sender == target_collection.owner, Error::<T>::NoPermission);929930            target_collection.sponsor = T::AccountId::default();931            target_collection.sponsor_confirmed = false;932            <Collection<T>>::insert(collection_id, target_collection);933934            Ok(())935        }936937        /// This method creates a concrete instance of NFT Collection created with CreateCollection method.938        /// 939        /// # Permissions940        /// 941        /// * Collection Owner.942        /// * Collection Admin.943        /// * Anyone if944        ///     * White List is enabled, and945        ///     * Address is added to white list, and946        ///     * MintPermission is enabled (see SetMintPermission method)947        /// 948        /// # Arguments949        /// 950        /// * collection_id: ID of the collection.951        /// 952        /// * owner: Address, initial owner of the NFT.953        ///954        /// * data: Token data to store on chain.955        // #[weight =956        // (130_000_000 as Weight)957        // .saturating_add((2135 as Weight).saturating_mul((properties.len() as u64) as Weight))958        // .saturating_add(RocksDbWeight::get().reads(10 as Weight))959        // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]960961        #[weight = <T as Config>::WeightInfo::create_item(data.len())]962        pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {963964            let sender = ensure_signed(origin)?;965966            Self::collection_exists(collection_id)?;967968            let target_collection = <Collection<T>>::get(collection_id);969970            Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;971            Self::validate_create_item_args(&target_collection, &data)?;972            Self::create_item_no_validation(collection_id, owner, data)?;973974            Ok(())975        }976977        /// This method creates multiple instances of NFT Collection created with CreateCollection method.978        /// 979        /// # Permissions980        /// 981        /// * Collection Owner.982        /// * Collection Admin.983        /// * Anyone if984        ///     * White List is enabled, and985        ///     * Address is added to white list, and986        ///     * MintPermission is enabled (see SetMintPermission method)987        /// 988        /// # Arguments989        /// 990        /// * collection_id: ID of the collection.991        /// 992        /// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].993        /// 994        /// * owner: Address, initial owner of the NFT.995        #[weight = <T as Config>::WeightInfo::create_item(items_data.into_iter()996                               .map(|data| { data.len() })997                               .sum())]998        pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {9991000            ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);1001            let sender = ensure_signed(origin)?;10021003            Self::collection_exists(collection_id)?;1004            let target_collection = <Collection<T>>::get(collection_id);10051006            Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;10071008            for data in &items_data {1009                Self::validate_create_item_args(&target_collection, data)?;1010            }1011            for data in &items_data {1012                Self::create_item_no_validation(collection_id, owner.clone(), data.clone())?;1013            }10141015            Ok(())1016        }10171018        /// Destroys a concrete instance of NFT.1019        /// 1020        /// # Permissions1021        /// 1022        /// * Collection Owner.1023        /// * Collection Admin.1024        /// * Current NFT Owner.1025        /// 1026        /// # Arguments1027        /// 1028        /// * collection_id: ID of the collection.1029        /// 1030        /// * item_id: ID of NFT to burn.1031        #[weight = <T as Config>::WeightInfo::burn_item()]1032        pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10331034            let sender = ensure_signed(origin)?;1035            Self::collection_exists(collection_id)?;10361037            // Transfer permissions check1038            let target_collection = <Collection<T>>::get(collection_id);1039            ensure!(1040                Self::is_item_owner(sender.clone(), collection_id, item_id) ||1041                (1042                    target_collection.limits.owner_can_transfer &&1043                    Self::is_owner_or_admin_permissions(collection_id, sender.clone())1044                ),1045                Error::<T>::NoPermission1046            );10471048            if target_collection.access == AccessMode::WhiteList {1049                Self::check_white_list(collection_id, &sender)?;1050            }10511052            match target_collection.mode1053            {1054                CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1055                CollectionMode::Fungible(_)  => Self::burn_fungible_item(&sender, collection_id, value)?,1056                CollectionMode::ReFungible  => Self::burn_refungible_item(collection_id, item_id, &sender)?,1057                _ => ()1058            };10591060            // call event1061            Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10621063            Ok(())1064        }10651066        /// Change ownership of the token.1067        /// 1068        /// # Permissions1069        /// 1070        /// * Collection Owner1071        /// * Collection Admin1072        /// * Current NFT owner1073        ///1074        /// # Arguments1075        /// 1076        /// * recipient: Address of token recipient.1077        /// 1078        /// * collection_id.1079        /// 1080        /// * item_id: ID of the item1081        ///     * Non-Fungible Mode: Required.1082        ///     * Fungible Mode: Ignored.1083        ///     * Re-Fungible Mode: Required.1084        /// 1085        /// * value: Amount to transfer.1086        ///     * Non-Fungible Mode: Ignored1087        ///     * Fungible Mode: Must specify transferred amount1088        ///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)1089        #[weight = <T as Config>::WeightInfo::transfer()]1090        pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1091            let sender = ensure_signed(origin)?;1092            Self::transfer_internal(sender, recipient, collection_id, item_id, value)1093        }10941095        /// Set, change, or remove approved address to transfer the ownership of the NFT.1096        /// 1097        /// # Permissions1098        /// 1099        /// * Collection Owner1100        /// * Collection Admin1101        /// * Current NFT owner1102        /// 1103        /// # Arguments1104        /// 1105        /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).1106        /// 1107        /// * collection_id.1108        /// 1109        /// * item_id: ID of the item.1110        #[weight = <T as Config>::WeightInfo::approve()]1111        pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {11121113            let sender = ensure_signed(origin)?;11141115            Self::collection_exists(collection_id)?;1116            Self::token_exists(collection_id, item_id, &sender)?;11171118            // Transfer permissions check1119            let target_collection = <Collection<T>>::get(collection_id);1120            let allowance_limit = if target_collection.limits.owner_can_transfer &&1121                Self::is_owner_or_admin_permissions(1122                    collection_id,1123                    sender.clone(),1124                ) {1125                None1126            } else if let Some(amount) = Self::owned_amount(1127                sender.clone(),1128                collection_id,1129                item_id,1130            ) {1131                Some(amount)1132            } else {1133                fail!(Error::<T>::NoPermission);1134            };11351136            if target_collection.access == AccessMode::WhiteList {1137                Self::check_white_list(collection_id, &sender)?;1138                Self::check_white_list(collection_id, &spender)?;1139            }11401141            let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1142            let mut allowance: u128 = amount;1143            if allowance_exists {1144                allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1145            }1146            if let Some(limit) = allowance_limit {1147                ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);1148            }1149            <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);11501151            Ok(())1152        }1153        1154        /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.1155        /// 1156        /// # Permissions1157        /// * Collection Owner1158        /// * Collection Admin1159        /// * Current NFT owner1160        /// * Address approved by current NFT owner1161        /// 1162        /// # Arguments1163        /// 1164        /// * from: Address that owns token.1165        /// 1166        /// * recipient: Address of token recipient.1167        /// 1168        /// * collection_id.1169        /// 1170        /// * item_id: ID of the item.1171        /// 1172        /// * value: Amount to transfer.1173        #[weight = <T as Config>::WeightInfo::transfer_from()]1174        pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11751176            let sender = ensure_signed(origin)?;1177            let mut appoved_transfer = false;11781179            // Check approval1180            let mut approval: u128 = 0;1181            if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &sender)) {1182                approval = <Allowances<T>>::get(collection_id, (item_id, &from, &sender));1183                ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1184                appoved_transfer = true;1185            }11861187            let target_collection = <Collection<T>>::get(collection_id);11881189            // Limits check1190            Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11911192            // Transfer permissions check         1193            ensure!(1194                appoved_transfer || 1195                (1196                    target_collection.limits.owner_can_transfer &&1197                    Self::is_owner_or_admin_permissions(collection_id, sender.clone())1198                ),1199                Error::<T>::NoPermission1200            );12011202            if target_collection.access == AccessMode::WhiteList {1203                Self::check_white_list(collection_id, &sender)?;1204                Self::check_white_list(collection_id, &recipient)?;1205            }12061207            // Reduce approval by transferred amount or remove if remaining approval drops to 01208            if approval.checked_sub(value).unwrap_or(0) > 0 {1209                <Allowances<T>>::insert(collection_id, (item_id, &from, &sender), approval - value);1210            }1211            else {1212                <Allowances<T>>::remove(collection_id, (item_id, &from, &sender));1213            }12141215            match target_collection.mode1216            {1217                CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1218                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1219                CollectionMode::ReFungible  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1220                _ => ()1221            };12221223            Ok(())1224        }12251226        // #[weight = 0]1227        // pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {12281229        //     // let no_perm_mes = "You do not have permissions to modify this collection";1230        //     // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1231        //     // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1232        //     // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);12331234        //     // // on_nft_received  call12351236        //     // Self::transfer(origin, collection_id, item_id, new_owner)?;12371238        //     Ok(())1239        // }12401241        /// Set off-chain data schema.1242        /// 1243        /// # Permissions1244        /// 1245        /// * Collection Owner1246        /// * Collection Admin1247        /// 1248        /// # Arguments1249        /// 1250        /// * collection_id.1251        /// 1252        /// * schema: String representing the offchain data schema.1253        #[weight = <T as Config>::WeightInfo::set_variable_meta_data()]1254        pub fn set_variable_meta_data (1255            origin,1256            collection_id: CollectionId,1257            item_id: TokenId,1258            data: Vec<u8>1259        ) -> DispatchResult {1260            let sender = ensure_signed(origin)?;1261            1262            Self::collection_exists(collection_id)?;1263            Self::token_exists(collection_id, item_id, &sender)?;12641265            ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12661267            // Modify permissions check1268            let target_collection = <Collection<T>>::get(collection_id);1269            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1270                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1271                Error::<T>::NoPermission);12721273            match target_collection.mode1274            {1275                CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1276                CollectionMode::ReFungible  => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1277                CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1278                _ => fail!(Error::<T>::UnexpectedCollectionType)1279            };12801281            Ok(())1282        }1283 1284        /// Set schema standard1285        /// ImageURL1286        /// Unique1287        /// 1288        /// # Permissions1289        /// 1290        /// * Collection Owner1291        /// * Collection Admin1292        /// 1293        /// # Arguments1294        /// 1295        /// * collection_id.1296        /// 1297        /// * schema: SchemaVersion: enum1298        #[weight = <T as Config>::WeightInfo::set_schema_version()]1299        pub fn set_schema_version(1300            origin,1301            collection_id: CollectionId,1302            version: SchemaVersion1303        ) -> DispatchResult {1304            let sender = ensure_signed(origin)?;1305            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1306            let mut target_collection = <Collection<T>>::get(collection_id);1307            target_collection.schema_version = version;1308            <Collection<T>>::insert(collection_id, target_collection);13091310            Ok(())1311        }13121313        /// Set off-chain data schema.1314        /// 1315        /// # Permissions1316        /// 1317        /// * Collection Owner1318        /// * Collection Admin1319        /// 1320        /// # Arguments1321        /// 1322        /// * collection_id.1323        /// 1324        /// * schema: String representing the offchain data schema.1325        #[weight = <T as Config>::WeightInfo::set_offchain_schema()]1326        pub fn set_offchain_schema(1327            origin,1328            collection_id: CollectionId,1329            schema: Vec<u8>1330        ) -> DispatchResult {1331            let sender = ensure_signed(origin)?;1332            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13331334            // check schema limit1335            ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");13361337            let mut target_collection = <Collection<T>>::get(collection_id);1338            target_collection.offchain_schema = schema;1339            <Collection<T>>::insert(collection_id, target_collection);13401341            Ok(())1342        }13431344        /// Set const on-chain data schema.1345        /// 1346        /// # Permissions1347        /// 1348        /// * Collection Owner1349        /// * Collection Admin1350        /// 1351        /// # Arguments1352        /// 1353        /// * collection_id.1354        /// 1355        /// * schema: String representing the const on-chain data schema.1356        #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1357        pub fn set_const_on_chain_schema (1358            origin,1359            collection_id: CollectionId,1360            schema: Vec<u8>1361        ) -> DispatchResult {1362            let sender = ensure_signed(origin)?;1363            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13641365            // check schema limit1366            ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");13671368            let mut target_collection = <Collection<T>>::get(collection_id);1369            target_collection.const_on_chain_schema = schema;1370            <Collection<T>>::insert(collection_id, target_collection);13711372            Ok(())1373        }13741375        /// Set variable on-chain data schema.1376        /// 1377        /// # Permissions1378        /// 1379        /// * Collection Owner1380        /// * Collection Admin1381        /// 1382        /// # Arguments1383        /// 1384        /// * collection_id.1385        /// 1386        /// * schema: String representing the variable on-chain data schema.1387        #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1388        pub fn set_variable_on_chain_schema (1389            origin,1390            collection_id: CollectionId,1391            schema: Vec<u8>1392        ) -> DispatchResult {1393            let sender = ensure_signed(origin)?;1394            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13951396            // check schema limit1397            ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");13981399            let mut target_collection = <Collection<T>>::get(collection_id);1400            target_collection.variable_on_chain_schema = schema;1401            <Collection<T>>::insert(collection_id, target_collection);14021403            Ok(())1404        }14051406        // Sudo permissions function1407        #[weight = <T as Config>::WeightInfo::set_chain_limits()]1408        pub fn set_chain_limits(1409            origin,1410            limits: ChainLimits1411        ) -> DispatchResult {14121413            #[cfg(not(feature = "runtime-benchmarks"))]1414            ensure_root(origin)?;14151416            <ChainLimit>::put(limits);1417            Ok(())1418        }14191420        /// Enable smart contract self-sponsoring.1421        /// 1422        /// # Permissions1423        /// 1424        /// * Contract Owner1425        /// 1426        /// # Arguments1427        /// 1428        /// * contract address1429        /// * enable flag1430        /// 1431        #[weight = <T as Config>::WeightInfo::enable_contract_sponsoring()]1432        pub fn enable_contract_sponsoring(1433            origin,1434            contract_address: T::AccountId,1435            enable: bool1436        ) -> DispatchResult {14371438            let sender = ensure_signed(origin)?;14391440            #[cfg(feature = "runtime-benchmarks")]1441            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14421443            Self::ensure_contract_owned(sender, &contract_address)?;14441445            <ContractSelfSponsoring<T>>::insert(contract_address, enable);1446            Ok(())1447        }14481449        /// Set the rate limit for contract sponsoring to specified number of blocks.1450        /// 1451        /// If not set (has the default value of 0 blocks), the sponsoring will be disabled. 1452        /// If set to the number B (for blocks), the transactions will be sponsored with a rate 1453        /// limit of B, i.e. fees for every transaction sent to this smart contract will be paid 1454        /// from contract endowment if there are at least B blocks between such transactions. 1455        /// Nonetheless, if transactions are sent more frequently, the fees are paid by the sender.1456        /// 1457        /// # Permissions1458        /// 1459        /// * Contract Owner1460        /// 1461        /// # Arguments1462        /// 1463        /// -`contract_address`: Address of the contract to sponsor1464        /// -`rate_limit`: Number of blocks to wait until the next sponsored transaction is allowed1465        /// 1466        #[weight = <T as Config>::WeightInfo::set_contract_sponsoring_rate_limit()]1467        pub fn set_contract_sponsoring_rate_limit(1468            origin,1469            contract_address: T::AccountId,1470            rate_limit: T::BlockNumber1471        ) -> DispatchResult {1472            let sender = ensure_signed(origin)?;14731474            #[cfg(feature = "runtime-benchmarks")]1475            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14761477            Self::ensure_contract_owned(sender, &contract_address)?;1478            <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1479            Ok(())1480        }14811482        /// Enable the white list for a contract. Only addresses added to the white list with addToContractWhiteList will be able to call this smart contract.1483        /// 1484        /// # Permissions1485        /// 1486        /// * Address that deployed smart contract.1487        /// 1488        /// # Arguments1489        /// 1490        /// -`contract_address`: Address of the contract.1491        /// 1492        /// - `enable`: .  1493        #[weight = <T as Config>::WeightInfo::toggle_contract_white_list()]1494        pub fn toggle_contract_white_list(1495            origin,1496            contract_address: T::AccountId,1497            enable: bool1498        ) -> DispatchResult {1499            let sender = ensure_signed(origin)?;15001501            #[cfg(feature = "runtime-benchmarks")]1502            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15031504            Self::ensure_contract_owned(sender, &contract_address)?;1505            <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1506            Ok(())1507        }1508        1509        /// Add an address to smart contract white list.1510        /// 1511        /// # Permissions1512        /// 1513        /// * Address that deployed smart contract.1514        /// 1515        /// # Arguments1516        /// 1517        /// -`contract_address`: Address of the contract.1518        ///1519        /// -`account_address`: Address to add.1520        #[weight = <T as Config>::WeightInfo::add_to_contract_white_list()]1521        pub fn add_to_contract_white_list(1522            origin,1523            contract_address: T::AccountId,1524            account_address: T::AccountId1525        ) -> DispatchResult {1526            let sender = ensure_signed(origin)?;15271528            #[cfg(feature = "runtime-benchmarks")]1529            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1530            1531            Self::ensure_contract_owned(sender, &contract_address)?;      1532            <ContractWhiteList<T>>::insert(contract_address, account_address, true);1533            Ok(())1534        }15351536        /// Remove an address from smart contract white list.1537        /// 1538        /// # Permissions1539        /// 1540        /// * Address that deployed smart contract.1541        /// 1542        /// # Arguments1543        /// 1544        /// -`contract_address`: Address of the contract.1545        ///1546        /// -`account_address`: Address to remove.1547        #[weight = <T as Config>::WeightInfo::remove_from_contract_white_list()]1548        pub fn remove_from_contract_white_list(1549            origin,1550            contract_address: T::AccountId,1551            account_address: T::AccountId1552        ) -> DispatchResult {1553            let sender = ensure_signed(origin)?;15541555            #[cfg(feature = "runtime-benchmarks")]1556            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15571558            Self::ensure_contract_owned(sender, &contract_address)?;1559            <ContractWhiteList<T>>::remove(contract_address, account_address);1560            Ok(())1561        }15621563        #[weight = <T as Config>::WeightInfo::set_collection_limits()]1564        pub fn set_collection_limits(1565            origin,1566            collection_id: u32,1567            new_limits: CollectionLimits,1568        ) -> DispatchResult {1569            let sender = ensure_signed(origin)?;1570            Self::check_owner_permissions(collection_id, sender.clone())?;1571            let mut target_collection = <Collection<T>>::get(collection_id);1572            let old_limits = target_collection.limits;1573            let chain_limits = ChainLimit::get();15741575            // collection bounds1576            ensure!(new_limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1577                new_limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP && 1578                new_limits.sponsored_data_size <= chain_limits.custom_data_limit,1579                Error::<T>::CollectionLimitBoundsExceeded);15801581            // token_limit   check  prev1582            ensure!(old_limits.token_limit >= new_limits.token_limit, Error::<T>::CollectionTokenLimitExceeded);1583            ensure!(new_limits.token_limit > 0, Error::<T>::CollectionTokenLimitExceeded);15841585            ensure!(1586                (old_limits.owner_can_transfer || !new_limits.owner_can_transfer) &&1587                (old_limits.owner_can_destroy || !new_limits.owner_can_destroy),1588                Error::<T>::OwnerPermissionsCantBeReverted,1589            );15901591            target_collection.limits = new_limits;1592            <Collection<T>>::insert(collection_id, target_collection);15931594            Ok(())1595        } 1596    }1597}15981599impl<T: Config> Module<T> {16001601    pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {16021603        let target_collection = <Collection<T>>::get(collection_id);16041605        // Limits check1606        Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;16071608        // Transfer permissions check1609        ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1610            Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1611            Error::<T>::NoPermission);16121613        if target_collection.access == AccessMode::WhiteList {1614            Self::check_white_list(collection_id, &sender)?;1615            Self::check_white_list(collection_id, &recipient)?;1616        }16171618        match target_collection.mode1619        {1620            CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient.clone())?,1621            CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1622            CollectionMode::ReFungible  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient.clone())?,1623            _ => ()1624        };16251626        Self::deposit_event(RawEvent::Transfer(collection_id, item_id, sender, recipient, value));16271628        Ok(())1629    }163016311632    fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {16331634        // check token limit and account token limit1635        let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1636        ensure!(collection.limits.account_token_ownership_limit > account_items,  Error::<T>::AccountTokenLimitExceeded);1637        1638        Ok(())1639    }16401641    fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {16421643        // check token limit and account token limit1644        let total_items: u32 = ItemListIndex::get(collection_id);1645        let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1646        ensure!(collection.limits.token_limit > total_items,  Error::<T>::CollectionTokenLimitExceeded);1647        ensure!(collection.limits.account_token_ownership_limit > account_items,  Error::<T>::AccountTokenLimitExceeded);16481649        if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1650            ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1651            Self::check_white_list(collection_id, owner)?;1652            Self::check_white_list(collection_id, sender)?;1653        }16541655        Ok(())1656    }16571658    fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1659        match target_collection.mode1660        {1661            CollectionMode::NFT => {1662                if let CreateItemData::NFT(data) = data {1663                    // check sizes1664                    ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1665                    ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1666                } else {1667                    fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1668                }1669            },1670            CollectionMode::Fungible(_) => {1671                if let CreateItemData::Fungible(_) = data {1672                } else {1673                    fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1674                }1675            },1676            CollectionMode::ReFungible => {1677                if let CreateItemData::ReFungible(data) = data {16781679                    // check sizes1680                    ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1681                    ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);16821683                    // Check refungibility limits1684                    ensure!(data.pieces <= MAX_REFUNGIBLE_PIECES, Error::<T>::WrongRefungiblePieces);1685                    ensure!(data.pieces > 0, Error::<T>::WrongRefungiblePieces);1686                } else {1687                    fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1688                }1689            },1690            _ => { fail!(Error::<T>::UnexpectedCollectionType); }1691        };16921693        Ok(())1694    }16951696    fn create_item_no_validation(collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1697        match data1698        {1699            CreateItemData::NFT(data) => {1700                let item = NftItemType {1701                    owner: owner.clone(),1702                    const_data: data.const_data,1703                    variable_data: data.variable_data1704                };17051706                Self::add_nft_item(collection_id, item)?;1707            },1708            CreateItemData::Fungible(data) => {1709                Self::add_fungible_item(collection_id, &owner, data.value)?;1710            },1711            CreateItemData::ReFungible(data) => {1712                let mut owner_list = Vec::new();1713                owner_list.push(Ownership {owner: owner.clone(), fraction: data.pieces});17141715                let item = ReFungibleItemType {1716                    owner: owner_list,1717                    const_data: data.const_data,1718                    variable_data: data.variable_data1719                };17201721                Self::add_refungible_item(collection_id, item)?;1722            }1723        };17241725        // call event1726        Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id), owner));17271728        Ok(())1729    }17301731    fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {17321733        // Does new owner already have an account?1734        let mut balance: u128 = 0;1735        if <FungibleItemList<T>>::contains_key(collection_id, owner) {1736            balance = <FungibleItemList<T>>::get(collection_id, owner).value;1737        } 17381739        // Mint 1740        let item = FungibleItemType {1741            value: balance + value1742        };1743        <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);17441745        // Update balance1746        let new_balance = <Balance<T>>::get(collection_id, owner)1747            .checked_add(value)1748            .ok_or(Error::<T>::NumOverflow)?;1749        <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);17501751        Ok(())1752    }17531754    fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1755        let current_index = <ItemListIndex>::get(collection_id)1756            .checked_add(1)1757            .ok_or(Error::<T>::NumOverflow)?;1758        let itemcopy = item.clone();17591760        let value = item.owner.first().unwrap().fraction;1761        let owner = item.owner.first().unwrap().owner.clone();17621763        Self::add_token_index(collection_id, current_index, &owner)?;17641765        <ItemListIndex>::insert(collection_id, current_index);1766        <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);17671768        // Update balance1769        let new_balance = <Balance<T>>::get(collection_id, &owner)1770            .checked_add(value)1771            .ok_or(Error::<T>::NumOverflow)?;1772        <Balance<T>>::insert(collection_id, owner.clone(), new_balance);17731774        Ok(())1775    }17761777    fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1778        let current_index = <ItemListIndex>::get(collection_id)1779            .checked_add(1)1780            .ok_or(Error::<T>::NumOverflow)?;17811782        let item_owner = item.owner.clone();1783        Self::add_token_index(collection_id, current_index, &item.owner)?;17841785        <ItemListIndex>::insert(collection_id, current_index);1786        <NftItemList<T>>::insert(collection_id, current_index, item);17871788        // Update balance1789        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1790            .checked_add(1)1791            .ok_or(Error::<T>::NumOverflow)?;1792        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);17931794        Ok(())1795    }17961797    fn burn_refungible_item(1798        collection_id: CollectionId,1799        item_id: TokenId,1800        owner: &T::AccountId,1801    ) -> DispatchResult {1802        ensure!(1803            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1804            Error::<T>::TokenNotFound1805        );1806        let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id);1807        let rft_balance = token1808            .owner1809            .iter()1810            .filter(|&i| i.owner == *owner)1811            .next()1812            .unwrap();1813        Self::remove_token_index(collection_id, item_id, owner)?;18141815        // update balance1816        let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.clone())1817            .checked_sub(rft_balance.fraction)1818            .ok_or(Error::<T>::NumOverflow)?;1819        <Balance<T>>::insert(collection_id, rft_balance.owner.clone(), new_balance);18201821        // Re-create owners list with sender removed1822        let index = token1823            .owner1824            .iter()1825            .position(|i| i.owner == *owner)1826            .unwrap();1827        token.owner.remove(index);1828        let owner_count = token.owner.len();18291830        // Burn the token completely if this was the last (only) owner1831        if owner_count == 0 {1832            <ReFungibleItemList<T>>::remove(collection_id, item_id);1833        }1834        else {1835            <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1836        }18371838        Ok(())1839    }18401841    fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1842        ensure!(1843            <NftItemList<T>>::contains_key(collection_id, item_id),1844            Error::<T>::TokenNotFound1845        );1846        let item = <NftItemList<T>>::get(collection_id, item_id);1847        Self::remove_token_index(collection_id, item_id, &item.owner)?;18481849        // update balance1850        let new_balance = <Balance<T>>::get(collection_id, &item.owner)1851            .checked_sub(1)1852            .ok_or(Error::<T>::NumOverflow)?;1853        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1854        <NftItemList<T>>::remove(collection_id, item_id);18551856        Ok(())1857    }18581859    fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1860        ensure!(1861            <FungibleItemList<T>>::contains_key(collection_id, owner),1862            Error::<T>::TokenNotFound1863        );1864        let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1865        ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);18661867        // update balance1868        let new_balance = <Balance<T>>::get(collection_id, owner)1869            .checked_sub(value)1870            .ok_or(Error::<T>::NumOverflow)?;1871        <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);18721873        if balance.value - value > 0 {1874            balance.value -= value;1875            <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1876        }1877        else {1878            <FungibleItemList<T>>::remove(collection_id, owner);1879        }18801881        Ok(())1882    }18831884    fn collection_exists(collection_id: CollectionId) -> DispatchResult {1885        ensure!(1886            <Collection<T>>::contains_key(collection_id),1887            Error::<T>::CollectionNotFound1888        );1889        Ok(())1890    }18911892    fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1893        Self::collection_exists(collection_id)?;18941895        let target_collection = <Collection<T>>::get(collection_id);1896        ensure!(1897            subject == target_collection.owner,1898            Error::<T>::NoPermission1899        );19001901        Ok(())1902    }19031904    fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1905        let target_collection = <Collection<T>>::get(collection_id);1906        let mut result: bool = subject == target_collection.owner;1907        let exists = <AdminList<T>>::contains_key(collection_id);19081909        if !result & exists {1910            if <AdminList<T>>::get(collection_id).contains(&subject) {1911                result = true1912            }1913        }19141915        result1916    }19171918    fn check_owner_or_admin_permissions(1919        collection_id: CollectionId,1920        subject: T::AccountId,1921    ) -> DispatchResult {1922        Self::collection_exists(collection_id)?;1923        let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());19241925        ensure!(1926            result,1927            Error::<T>::NoPermission1928        );1929        Ok(())1930    }19311932    fn owned_amount(1933        subject: T::AccountId,1934        collection_id: CollectionId,1935        item_id: TokenId,1936    ) -> Option<u128> {1937        let target_collection = <Collection<T>>::get(collection_id);19381939        match target_collection.mode {1940            CollectionMode::NFT => {1941                if <NftItemList<T>>::get(collection_id, item_id).owner == subject {1942                    return Some(1)1943                }1944                None1945            },1946            CollectionMode::Fungible(_) => {1947                if <FungibleItemList<T>>::contains_key(collection_id, &subject) {1948                    return Some(<FungibleItemList<T>>::get(collection_id, &subject)1949                        .value);1950                }1951                None1952            },1953            CollectionMode::ReFungible => <ReFungibleItemList<T>>::get(collection_id, item_id)1954                .owner1955                .iter()1956                .find(|i| i.owner == subject)1957                .map(|i| i.fraction),1958            CollectionMode::Invalid => None,1959        }1960    }19611962    fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1963        let target_collection = <Collection<T>>::get(collection_id);19641965        match target_collection.mode {1966            CollectionMode::NFT => {1967                <NftItemList<T>>::get(collection_id, item_id).owner == subject1968            }1969            CollectionMode::Fungible(_) => {1970                <FungibleItemList<T>>::contains_key(collection_id, &subject)1971            }1972            CollectionMode::ReFungible => {1973                <ReFungibleItemList<T>>::get(collection_id, item_id)1974                    .owner1975                    .iter()1976                    .any(|i| i.owner == subject)1977            }1978            CollectionMode::Invalid => false,1979        }1980    }19811982    fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1983        let mes = Error::<T>::AddresNotInWhiteList;1984        ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);19851986        Ok(())1987    }19881989    /// Check if token exists. In case of Fungible, check if there is an entry for 1990    /// the owner in fungible balances double map1991    fn token_exists(1992        collection_id: CollectionId,1993        item_id: TokenId,1994        owner: &T::AccountId1995    ) -> DispatchResult {1996        let target_collection = <Collection<T>>::get(collection_id);1997        let exists = match target_collection.mode1998        {1999            CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),2000            CollectionMode::Fungible(_)  => <FungibleItemList<T>>::contains_key(collection_id, owner),2001            CollectionMode::ReFungible  => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),2002            _ => false2003        };20042005        ensure!(exists == true, Error::<T>::TokenNotFound);2006        Ok(())2007    }20082009    fn transfer_fungible(2010        collection_id: CollectionId,2011        value: u128,2012        owner: &T::AccountId,2013        recipient: &T::AccountId,2014    ) -> DispatchResult {2015        Self::token_exists(collection_id, 0, owner)?;20162017        let mut balance = <FungibleItemList<T>>::get(collection_id, owner);2018        ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);20192020        // Send balance to recipient (updates balanceOf of recipient)2021        Self::add_fungible_item(collection_id, recipient, value)?;20222023        // update balanceOf of sender2024        <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);20252026        // Reduce or remove sender2027        if balance.value == value {2028            <FungibleItemList<T>>::remove(collection_id, owner);2029        }2030        else {2031            balance.value -= value;2032            <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);2033        }20342035        Ok(())2036    }20372038    fn transfer_refungible(2039        collection_id: CollectionId,2040        item_id: TokenId,2041        value: u128,2042        owner: T::AccountId,2043        new_owner: T::AccountId,2044    ) -> DispatchResult {2045        Self::token_exists(collection_id, item_id, &owner)?;20462047        let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);2048        let item = full_item2049            .owner2050            .iter()2051            .filter(|i| i.owner == owner)2052            .next()2053            .ok_or(Error::<T>::NumOverflow)?;2054        let amount = item.fraction;20552056        ensure!(amount >= value, Error::<T>::TokenValueTooLow);20572058        // update balance2059        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2060            .checked_sub(value)2061            .ok_or(Error::<T>::NumOverflow)?;2062        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20632064        let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2065            .checked_add(value)2066            .ok_or(Error::<T>::NumOverflow)?;2067        <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);20682069        let old_owner = item.owner.clone();2070        let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);20712072        // transfer2073        if amount == value && !new_owner_has_account {2074            // change owner2075            // new owner do not have account2076            let mut new_full_item = full_item.clone();2077            new_full_item2078                .owner2079                .iter_mut()2080                .find(|i| i.owner == owner)2081                .unwrap()2082                .owner = new_owner.clone();2083            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);20842085            // update index collection2086            Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;2087        } else {2088            let mut new_full_item = full_item.clone();2089            new_full_item2090                .owner2091                .iter_mut()2092                .find(|i| i.owner == owner)2093                .unwrap()2094                .fraction -= value;20952096            // separate amount2097            if new_owner_has_account {2098                // new owner has account2099                new_full_item2100                    .owner2101                    .iter_mut()2102                    .find(|i| i.owner == new_owner)2103                    .unwrap()2104                    .fraction += value;2105            } else {2106                // new owner do not have account2107                new_full_item.owner.push(Ownership {2108                    owner: new_owner.clone(),2109                    fraction: value,2110                });2111                Self::add_token_index(collection_id, item_id, &new_owner)?;2112            }21132114            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2115        }21162117        Ok(())2118    }21192120    fn transfer_nft(2121        collection_id: CollectionId,2122        item_id: TokenId,2123        sender: T::AccountId,2124        new_owner: T::AccountId,2125    ) -> DispatchResult {2126        Self::token_exists(collection_id, item_id, &sender)?;21272128        let mut item = <NftItemList<T>>::get(collection_id, item_id);21292130        ensure!(2131            sender == item.owner,2132            Error::<T>::MustBeTokenOwner2133        );21342135        // update balance2136        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2137            .checked_sub(1)2138            .ok_or(Error::<T>::NumOverflow)?;2139        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);21402141        let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2142            .checked_add(1)2143            .ok_or(Error::<T>::NumOverflow)?;2144        <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);21452146        // change owner2147        let old_owner = item.owner.clone();2148        item.owner = new_owner.clone();2149        <NftItemList<T>>::insert(collection_id, item_id, item);21502151        // update index collection2152        Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;21532154        Ok(())2155    }2156    2157    fn set_re_fungible_variable_data(2158        collection_id: CollectionId,2159        item_id: TokenId,2160        data: Vec<u8>2161    ) -> DispatchResult {2162        let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);21632164        item.variable_data = data;21652166        <ReFungibleItemList<T>>::insert(collection_id, item_id, item);21672168        Ok(())2169    }21702171    fn set_nft_variable_data(2172        collection_id: CollectionId,2173        item_id: TokenId,2174        data: Vec<u8>2175    ) -> DispatchResult {2176        let mut item = <NftItemList<T>>::get(collection_id, item_id);2177        2178        item.variable_data = data;21792180        <NftItemList<T>>::insert(collection_id, item_id, item);2181        2182        Ok(())2183    }21842185    fn init_collection(item: &CollectionType<T::AccountId>) {2186        // check params2187        assert!(2188            item.decimal_points <= MAX_DECIMAL_POINTS,2189            "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2190        );2191        assert!(2192            item.name.len() <= 64,2193            "Collection name can not be longer than 63 char"2194        );2195        assert!(2196            item.name.len() <= 256,2197            "Collection description can not be longer than 255 char"2198        );2199        assert!(2200            item.token_prefix.len() <= 16,2201            "Token prefix can not be longer than 15 char"2202        );22032204        // Generate next collection ID2205        let next_id = CreatedCollectionCount::get()2206            .checked_add(1)2207            .unwrap();22082209        CreatedCollectionCount::put(next_id);2210    }22112212    fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2213        let current_index = <ItemListIndex>::get(collection_id)2214            .checked_add(1)2215            .unwrap();22162217        let item_owner = item.owner.clone();2218        Self::add_token_index(collection_id, current_index, &item.owner).unwrap();22192220        <ItemListIndex>::insert(collection_id, current_index);22212222        // Update balance2223        let new_balance = <Balance<T>>::get(collection_id, &item_owner)2224            .checked_add(1)2225            .unwrap();2226        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2227    }22282229    fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2230        let current_index = <ItemListIndex>::get(collection_id)2231            .checked_add(1)2232            .unwrap();22332234        Self::add_token_index(collection_id, current_index, owner).unwrap();22352236        <ItemListIndex>::insert(collection_id, current_index);22372238        // Update balance2239        let new_balance = <Balance<T>>::get(collection_id, owner)2240            .checked_add(item.value)2241            .unwrap();2242        <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2243    }22442245    fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2246        let current_index = <ItemListIndex>::get(collection_id)2247            .checked_add(1)2248            .unwrap();22492250        let value = item.owner.first().unwrap().fraction;2251        let owner = item.owner.first().unwrap().owner.clone();22522253        Self::add_token_index(collection_id, current_index, &owner).unwrap();22542255        <ItemListIndex>::insert(collection_id, current_index);22562257        // Update balance2258        let new_balance = <Balance<T>>::get(collection_id, &owner)2259            .checked_add(value)2260            .unwrap();2261        <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2262    }22632264    fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {22652266        // add to account limit2267        if <AccountItemCount<T>>::contains_key(owner) {22682269            // bound Owned tokens by a single address2270            let count = <AccountItemCount<T>>::get(owner);2271            ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);22722273            <AccountItemCount<T>>::insert(owner.clone(), count2274                .checked_add(1)2275                .ok_or(Error::<T>::NumOverflow)?);2276        }2277        else {2278            <AccountItemCount<T>>::insert(owner.clone(), 1);2279        }22802281        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2282        if list_exists {2283            let mut list = <AddressTokens<T>>::get(collection_id, owner);2284            let item_contains = list.contains(&item_index.clone());22852286            if !item_contains {2287                list.push(item_index.clone());2288            }22892290            <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2291        } else {2292            let mut itm = Vec::new();2293            itm.push(item_index.clone());2294            <AddressTokens<T>>::insert(collection_id, owner.clone(), itm);2295        }22962297        Ok(())2298    }22992300    fn remove_token_index(2301        collection_id: CollectionId,2302        item_index: TokenId,2303        owner: &T::AccountId,2304    ) -> DispatchResult {23052306        // update counter2307        <AccountItemCount<T>>::insert(owner.clone(), 2308            <AccountItemCount<T>>::get(owner)2309            .checked_sub(1)2310            .ok_or(Error::<T>::NumOverflow)?);231123122313        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2314        if list_exists {2315            let mut list = <AddressTokens<T>>::get(collection_id, owner);2316            let item_contains = list.contains(&item_index.clone());23172318            if item_contains {2319                list.retain(|&item| item != item_index);2320                <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2321            }2322        }23232324        Ok(())2325    }23262327    fn move_token_index(2328        collection_id: CollectionId,2329        item_index: TokenId,2330        old_owner: &T::AccountId,2331        new_owner: &T::AccountId,2332    ) -> DispatchResult {2333        Self::remove_token_index(collection_id, item_index, old_owner)?;2334        Self::add_token_index(collection_id, item_index, new_owner)?;23352336        Ok(())2337    }2338    2339    fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2340        if <ContractOwner<T>>::contains_key(contract.clone()) {2341            let owner = <ContractOwner<T>>::get(contract);2342            ensure!(account == owner, Error::<T>::NoPermission);2343        } else {2344            fail!(Error::<T>::NoPermission);2345        }23462347        Ok(())2348    }2349}23502351////////////////////////////////////////////////////////////////////////////////////////////////////2352// Economic models2353// #region23542355/// Fee multiplier.2356pub type Multiplier = FixedU128;23572358type BalanceOf<T> = <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::Balance;23592360/// Require the transactor pay for themselves and maybe include a tip to gain additional priority2361/// in the queue.2362#[derive(Encode, Decode, Clone, Eq, PartialEq)]2363pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);23642365impl<T: Config + Send + Sync> sp_std::fmt::Debug 2366    for ChargeTransactionPayment<T>2367{2368	#[cfg(feature = "std")]2369	fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2370		write!(f, "ChargeTransactionPayment<{:?}>", self.0)2371	}2372	#[cfg(not(feature = "std"))]2373	fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2374		Ok(())2375	}2376}23772378impl<T: Config> ChargeTransactionPayment<T>2379where2380    T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2381    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2382    T::AccountId: AsRef<[u8]>,2383    T::AccountId: UncheckedFrom<T::Hash>,2384{2385    fn traditional_fee(2386        len: usize,2387        info: &DispatchInfoOf<T::Call>,2388        tip: BalanceOf<T>,2389    ) -> BalanceOf<T>2390    where2391        T::Call: Dispatchable<Info = DispatchInfo>,2392    {2393        <pallet_transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2394    }23952396	fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2397        let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1);2398        let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal);2399        let len_saturation = max_block_length as u64 / (len as u64).max(1);2400        let coefficient: BalanceOf<T> = weight_saturation2401            .min(len_saturation)2402            .saturated_into::<BalanceOf<T>>();2403        final_fee2404            .saturating_mul(coefficient)2405            .saturated_into::<TransactionPriority>()2406    }24072408    fn withdraw_fee(2409        &self,2410        who: &T::AccountId,2411        call: &T::Call,2412        info: &DispatchInfoOf<T::Call>,2413        len: usize,2414	) -> Result<2415		(2416			BalanceOf<T>,2417			<<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2418		),2419		TransactionValidityError,2420	> {2421        let tip = self.0;24222423        // Set fee based on call type. Creating collection costs 1 Unique.2424        // All other transactions have traditional fees so far2425        // let fee = match call.is_sub_type() {2426        //     Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),2427        //     _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes2428        //                                                 // _ => <BalanceOf<T>>::from(100)2429        // };2430        let fee = Self::traditional_fee(len, info, tip);24312432        // Only mess with balances if fee is not zero.2433        if fee.is_zero() {2434            return <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(who, call, info, fee, tip)2435			.map(|i| (fee, i));2436        }24372438        // Determine who is paying transaction fee based on ecnomic model2439        // Parse call to extract collection ID and access collection sponsor2440        let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2441            Some(Call::create_item(collection_id, _owner, _properties)) => {24422443                // sponsor timeout2444                let block_number = <system::Module<T>>::block_number() as T::BlockNumber;24452446                let limit = <Collection<T>>::get(collection_id).limits.sponsor_transfer_timeout;2447                let mut sponsored = true;2448                if <CreateItemBasket<T>>::contains_key((collection_id, &who)) {2449                    let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2450                    let limit_time = last_tx_block + limit.into();2451                    if block_number <= limit_time {2452                        sponsored = false;2453                    }2454                }2455                if sponsored {2456                    <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2457                }24582459                // check free create limit2460                if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2461                   (<Collection<T>>::get(collection_id).sponsor_confirmed) &&2462                   (sponsored)2463                {2464                    <Collection<T>>::get(collection_id).sponsor2465                } else {2466                    T::AccountId::default()2467                }2468            }2469            Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2470                2471                let mut sponsor_transfer = false;2472                if <Collection<T>>::get(collection_id).sponsor_confirmed {24732474                    let collection_limits = <Collection<T>>::get(collection_id).limits;2475                    let collection_mode = <Collection<T>>::get(collection_id).mode;2476    2477                    // sponsor timeout2478                    let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2479                    sponsor_transfer = match collection_mode {2480                        CollectionMode::NFT => {2481    2482                            // get correct limit2483                            let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2484                                collection_limits.sponsor_transfer_timeout2485                            } else {2486                                ChainLimit::get().nft_sponsor_transfer_timeout2487                            };2488    2489                            let mut sponsored = true;2490                            if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2491                                let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2492                                let limit_time = last_tx_block + limit.into();2493                                if block_number <= limit_time {2494                                    sponsored = false;2495                                }2496                            }2497                            if sponsored {2498                                <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2499                            }25002501                            sponsored2502                        }2503                        CollectionMode::Fungible(_) => {2504    2505                            // get correct limit2506                            let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2507                                collection_limits.sponsor_transfer_timeout2508                            } else {2509                                ChainLimit::get().fungible_sponsor_transfer_timeout2510                            };2511    2512                            let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2513                            let mut sponsored = true;2514                            if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2515                                let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2516                                let limit_time = last_tx_block + limit.into();2517                                if block_number <= limit_time {2518                                    sponsored = false;2519                                }2520                            }2521                            if sponsored {2522                                <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2523                            }25242525                            sponsored2526                        }2527                        CollectionMode::ReFungible => {2528    2529                            // get correct limit2530                            let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2531                                collection_limits.sponsor_transfer_timeout2532                            } else {2533                                ChainLimit::get().refungible_sponsor_transfer_timeout2534                            };2535    2536                            let mut sponsored = true;2537                            if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2538                                let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2539                                let limit_time = last_tx_block + limit.into();2540                                if block_number <= limit_time {2541                                    sponsored = false;2542                                }2543                            }2544                            if sponsored {2545                                <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2546                            }25472548                            sponsored2549                        }2550                        _ => {2551                            false2552                        },2553                    };2554                }25552556                if !sponsor_transfer {2557                    T::AccountId::default()2558                } else {2559                    <Collection<T>>::get(collection_id).sponsor2560                }2561            }25622563            _ => T::AccountId::default(),2564        };25652566        // Sponsor smart contracts2567        sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {25682569            // On instantiation: set the contract owner2570            Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => {25712572                let new_contract_address = <pallet_contracts::Module<T>>::contract_address(2573                    &who,2574                    code_hash,2575                    salt,2576                );2577                <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());25782579                T::AccountId::default()2580            },25812582            // On instantiation with code: set the contract owner2583            Some(pallet_contracts::Call::instantiate_with_code(_endowment, _gas_limit, _code, _data, _salt))  => {25842585                let new_contract_address = <pallet_contracts::Module<T>>::contract_address(2586                    &who,2587                    &T::Hashing::hash(&_code),2588                    _salt,2589                );25902591                <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());25922593                T::AccountId::default()2594            }25952596            // When the contract is called, check if the sponsoring is enabled and pay fees from contract endowment if it is2597            Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {25982599                let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());26002601                let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2602                  && <ContractOwner<T>>::get(called_contract.clone()) == *who;2603                let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2604                  2605                if !owned_contract && white_list_enabled {2606                    if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2607                        return Err(InvalidTransaction::Call.into());2608                    }2609                }26102611                let mut sponsor_transfer = false;2612                if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2613                    let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2614                    let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2615                    let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2616                    let limit_time = last_tx_block + rate_limit;26172618                    if block_number >= limit_time {2619                        <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2620                        sponsor_transfer = true;2621                    }2622                } else {2623                    sponsor_transfer = false;2624                }2625               2626                2627                let mut sp = T::AccountId::default();2628                if sponsor_transfer {2629                    if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2630                        if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2631                            sp = called_contract;2632                        }2633                    }2634                }26352636                sp2637            },26382639            _ => sponsor,2640        };26412642        let mut who_pays_fee: T::AccountId = sponsor.clone();2643        if sponsor == T::AccountId::default() {2644            who_pays_fee = who.clone();2645        }26462647		<<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)2648			.map(|i| (fee, i))2649    }2650}265126522653impl<T: Config + Send + Sync> SignedExtension2654    for ChargeTransactionPayment<T>2655where2656    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2657    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2658    T::AccountId: AsRef<[u8]>,2659    T::AccountId: UncheckedFrom<T::Hash>,2660{2661    const IDENTIFIER: &'static str = "ChargeTransactionPayment";2662    type AccountId = T::AccountId;2663    type Call = T::Call;2664    type AdditionalSigned = ();2665    type Pre = (2666        // tip2667        BalanceOf<T>,2668        // who pays fee2669        Self::AccountId,2670		// imbalance resulting from withdrawing the fee2671		<<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2672    );2673    fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2674        Ok(())2675    }26762677    fn validate(2678        &self,2679        who: &Self::AccountId,2680        call: &Self::Call,2681        info: &DispatchInfoOf<Self::Call>,2682        len: usize,2683    ) -> TransactionValidity {2684		let (fee, _) = self.withdraw_fee(who, call, info, len)?;2685		Ok(ValidTransaction {2686			priority: Self::get_priority(len, info, fee),2687			..Default::default()2688		})2689    }26902691    fn pre_dispatch(2692        self,2693        who: &Self::AccountId,2694        call: &Self::Call,2695        info: &DispatchInfoOf<Self::Call>,2696        len: usize,2697    ) -> Result<Self::Pre, TransactionValidityError> {2698        let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2699        Ok((self.0, who.clone(), imbalance))2700    }27012702    fn post_dispatch(2703        pre: Self::Pre,2704        info: &DispatchInfoOf<Self::Call>,2705        post_info: &PostDispatchInfoOf<Self::Call>,2706        len: usize,2707        _result: &DispatchResult,2708    ) -> Result<(), TransactionValidityError> {2709		let (tip, who, imbalance) = pre;2710		let actual_fee = pallet_transaction_payment::Module::<T>::compute_actual_fee(2711			len as u32,2712			info,2713			post_info,2714			tip,2715		);2716		<T as pallet_transaction_payment::Config>::OnChargeTransaction::correct_and_deposit_fee(&who, info, post_info, actual_fee, tip, imbalance)?;2717		Ok(())2718    }2719}27202721// #endregion
modifiedruntime/Cargo.tomldiffbeforeafterboth
--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -5,60 +5,60 @@
 license = 'All Rights Reserved'
 name = 'nft-runtime'
 repository = 'https://github.com/usetech-llc/nft_parachain/'
-version = '2.1.0'
+version = '3.0.0'
 
 [package.metadata.docs.rs]
 targets = ['x86_64-unknown-linux-gnu']
 
 [build-dependencies]
-wasm-builder-runner = { package = 'substrate-wasm-builder-runner', version = '1.0.5' }
+substrate-wasm-builder = '4.0.0'
 
 # alias "parity-scale-code" to "codec"
 [dependencies.codec]
 default-features = false
 features = ['derive']
 package = 'parity-scale-codec'
-version = '1.3.4'
+version = '2.0.0'
 
 [dependencies]
 hex-literal = { optional = true, version = '0.3.1' }
-serde = { features = ['derive'], optional = true, version = '1.0.101' }
+serde = { features = ['derive'], optional = true, version = '1.0.119' }
 
 # local dependencies
-pallet-nft = { path = '../pallets/nft', default-features = false, version = '2.1.0' }
+pallet-nft = { path = '../pallets/nft', default-features = false, version = '3.0.0' }
 
 # Substrate dependencies
-frame-benchmarking = { default-features = false, optional = true, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-frame-executive = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-frame-support = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-frame-system = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-frame-system-benchmarking = { default-features = false, optional = true, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-frame-system-rpc-runtime-api = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-pallet-aura = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-pallet-balances = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-pallet-contracts = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-pallet-contracts-primitives = { default-features = false, version = '2.0.1', git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-pallet-contracts-rpc-runtime-api = { default-features = false, version = '0.8.0' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-pallet-grandpa = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-pallet-randomness-collective-flip = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-pallet-sudo = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-pallet-timestamp = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-pallet-transaction-payment = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-pallet-transaction-payment-rpc-runtime-api = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-pallet-treasury = { version = "2.0.1", default-features = false, git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-pallet-vesting = { version = "2.0.1", default-features = false, git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sp-api = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sp-arithmetic = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sp-block-builder = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sp-consensus-aura = { default-features = false, version = '0.8.0' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sp-core = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sp-inherents = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sp-offchain = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sp-runtime = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sp-session = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sp-std = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sp-transaction-pool = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
-sp-version = { default-features = false, version = '2.0.1' , git = 'https://github.com/usetech-llc/substrate.git', branch = 'unique' }
+frame-benchmarking = { default-features = false, optional = true, version = '3.0.0' }
+frame-executive = { default-features = false, version = '3.0.0' }
+frame-support = { default-features = false, version = '3.0.0' }
+frame-system = { default-features = false, version = '3.0.0' }
+frame-system-benchmarking = { default-features = false, optional = true, version = '3.0.0' }
+frame-system-rpc-runtime-api = { default-features = false, version = '3.0.0' }
+pallet-aura = { default-features = false, version = '3.0.0' }
+pallet-balances = { default-features = false, version = '3.0.0' }
+pallet-contracts = { default-features = false, version = '3.0.0' }
+pallet-contracts-primitives = { default-features = false, version = '3.0.0' }
+pallet-contracts-rpc-runtime-api = { default-features = false, version = '3.0.0' }
+pallet-grandpa = { default-features = false, version = '3.0.0' }
+pallet-randomness-collective-flip = { default-features = false, version = '3.0.0' }
+pallet-sudo = { default-features = false, version = '3.0.0' }
+pallet-timestamp = { default-features = false, version = '3.0.0' }
+pallet-transaction-payment = { default-features = false, version = '3.0.0' }
+pallet-transaction-payment-rpc-runtime-api = { default-features = false, version = '3.0.0' }
+pallet-treasury = { default-features = false, version = "3.0.0" }
+pallet-vesting = {  default-features = false, version = "3.0.0" }
+sp-arithmetic = { default-features = false, version = '3.0.0' }
+sp-api = { default-features = false, version = '3.0.0' }
+sp-block-builder = { default-features = false, version = '3.0.0' }
+sp-consensus-aura = { default-features = false, version = '0.9.0' }
+sp-core = { default-features = false, version = '3.0.0' }
+sp-inherents = { default-features = false, version = '3.0.0' }
+sp-offchain = { default-features = false, version = '3.0.0' }
+sp-runtime = { default-features = false, version = '3.0.0' }
+sp-session = { default-features = false, version = '3.0.0' }
+sp-std = { default-features = false, version = '3.0.0' }
+sp-transaction-pool = { default-features = false, version = '3.0.0' }
+sp-version = { default-features = false, version = '3.0.0' }
 smallvec = "1.4.1"
 
 [features]
modifiedruntime/build.rsdiffbeforeafterboth
--- a/runtime/build.rs
+++ b/runtime/build.rs
@@ -1,10 +1,9 @@
-use wasm_builder_runner::WasmBuilder;
+use substrate_wasm_builder::WasmBuilder;
 
 fn main() {
     WasmBuilder::new()
         .with_current_project()
-        .with_wasm_builder_from_crates("2.0.0")
-        .export_heap_base()
         .import_memory()
+        .export_heap_base()
         .build()
-}
+}
\ No newline at end of file
modifiedruntime/src/chain_extension.rsdiffbeforeafterboth
--- a/runtime/src/chain_extension.rs
+++ b/runtime/src/chain_extension.rs
@@ -33,7 +33,7 @@
 /// The chain Extension of NFT pallet
 pub struct NFTExtension;
 
-impl ChainExtension for NFTExtension {
+impl<C: Config> ChainExtension<C> for NFTExtension {
     fn call<E: Ext>(func_id: u32, env: Environment<E, InitState>) -> Result<RetVal, DispatchError>
     where
         <E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
@@ -71,4 +71,3 @@
         }
     }
 }
-
modifiedruntime/src/lib.rsdiffbeforeafterboth
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -35,7 +35,7 @@
 pub use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment, CurrencyAdapter, FeeDetails, RuntimeDispatchInfo};
 // A few exports that help ease life for downstream crates.
 pub use pallet_balances::Call as BalancesCall;
-pub use pallet_contracts::{Schedule as ContractsSchedule, WeightInfo};
+pub use pallet_contracts::{Schedule as ContractsSchedule };
 pub use frame_support::{
     construct_runtime,
     dispatch::DispatchResult,
@@ -47,10 +47,11 @@
     },
     weights::{
         constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
-        DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, Weight,
+        DispatchClass, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, Weight,
         WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients
     },
 };
+use pallet_contracts::weights::WeightInfo;
 // #[cfg(any(feature = "std", test))]
 use frame_system::{
     self as system,
@@ -64,7 +65,7 @@
 pub use pallet_timestamp::Call as TimestampCall;
 
 mod chain_extension;
-use crate::chain_extension::NFTExtension;
+use crate::chain_extension::{ NFTExtension, Imbalance };
 
 /// Struct that handles the conversion of Balance -> `u64`. This is used for
 /// staking's election calculation.
@@ -229,6 +230,21 @@
 	}
 }
 
+// impl OnUnbalanced<NegativeImbalance> for DealWithFees {
+// 	fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item=NegativeImbalance>) {
+// 		if let Some(fees) = fees_then_tips.next() {
+// 			// for fees, 100% to treasury
+// 			let mut split = fees.ration(100, 0);
+// 			if let Some(tips) = fees_then_tips.next() {
+// 				// for tips, if any, 100% to treasury
+// 				tips.ration_merge_into(100, 0, &mut split);
+// 			}
+// 			Treasury::on_unbalanced(split.0);
+// 			// Author::on_unbalanced(split.1);
+// 		}
+// 	}
+// }
+
 /// We assume that ~10% of the block weight is consumed by `on_initalize` handlers.
 /// This is used to limit the maximal weight of a single extrinsic.
 const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10);
@@ -388,6 +404,7 @@
 	pub const SignedClaimHandicap: u32 = 2;
 	pub const MaxDepth: u32 = 32;
 	pub const MaxValueSize: u32 = 16 * 1024;
+	pub const MaxCodeSize: u32 = 1024 * 1024 * 25; // 25 Mb 
 	// The lazy deletion runs inside on_initialize.
 	pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO *
 		RuntimeBlockWeights::get().max_block;
@@ -420,6 +437,7 @@
 	type ChainExtension = NFTExtension;
 	type DeletionQueueDepth = DeletionQueueDepth;
 	type DeletionWeightLimit = DeletionWeightLimit;
+	type MaxCodeSize = MaxCodeSize;
 }
 
 parameter_types! {
@@ -518,7 +536,7 @@
         RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage},
         Contracts: pallet_contracts::{Module, Call, Config<T>, Storage, Event<T>},
         Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent},
-        Aura: pallet_aura::{Module, Config<T>, Inherent},
+        Aura: pallet_aura::{Module, Config<T> },
         Grandpa: pallet_grandpa::{Module, Call, Storage, Config, Event},
         Balances: pallet_balances::{Module, Call, Storage, Config<T>, Event<T>},
         TransactionPayment: pallet_transaction_payment::{Module, Storage},
@@ -738,4 +756,4 @@
 			Ok(batches)
 		}
 	}
-}
+}
\ No newline at end of file
modifiedtests/src/util/contracthelpers.tsdiffbeforeafterboth
--- a/tests/src/util/contracthelpers.ts
+++ b/tests/src/util/contracthelpers.ts
@@ -20,35 +20,20 @@
 const gasLimit = '200000000000';
 const endowment = '100000000000000000';
 
-function deployBlueprint(alice: IKeyringPair, code: CodePromise): Promise<Blueprint> {
-  return new Promise<Blueprint>(async (resolve, reject) => {
+function deployContract(alice: IKeyringPair, code: CodePromise, constructor: string = 'default', ...args: any[]): Promise<Contract> {
+  return new Promise<Contract>(async (resolve, reject) => {
     const unsub = await code
-      .createBlueprint()
+      .tx[constructor]({value: endowment, gasLimit}, ...args)
       .signAndSend(alice, (result) => {
         if (result.status.isInBlock || result.status.isFinalized) {
           // here we have an additional field in the result, containing the blueprint
-          resolve(result.blueprint);
+          resolve((result as any).contract);
           unsub();
         }
       })
   });
 }
 
-function deployContract(alice: IKeyringPair, blueprint: Blueprint) : Promise<any> {
-  return new Promise<any>(async (resolve, reject) => {
-    const initValue = true;
-
-    const unsub = await blueprint.tx
-    .new(endowment, gasLimit, initValue)
-    .signAndSend(alice, (result) => {
-      if (result.status.isInBlock || result.status.isFinalized) {
-        unsub();
-        resolve(result);
-      }
-    });    
-  });
-}
-
 async function prepareDeployer(api: ApiPromise) {
   // Find unused address
   const deployer = await findUnusedAddress(api);
@@ -74,8 +59,7 @@
 
   const code = new CodePromise(api, abi, wasm);
 
-  const blueprint = await deployBlueprint(deployer, code);
-  const contract = (await deployContract(deployer, blueprint))['contract'] as Contract;
+  const contract = (await deployContract(deployer, code, 'new', true)) as Contract;
 
   const initialGetResponse = await getFlipValue(contract, deployer);
   expect(initialGetResponse).to.be.true;
@@ -128,8 +112,7 @@
 
   const code = new CodePromise(api, abi, wasm);
 
-  const blueprint = await deployBlueprint(deployer, code);
-  const contract = (await instantiateTransferContract(deployer, blueprint))['contract'] as Contract;
+  const contract = await deployContract(deployer, code);
 
   return [contract, deployer];
 }