git.delta.rocks / unique-network / refs/commits / 3e2337f86885

difftreelog

Merge pull request #1040 from UniqueNetwork/feature/update-polkadot-v1.3.0

Yaroslav Bolyukin2023-11-22parents: #f02a706 #82da160.patch.diff
in: master
Update polkadot to v1.3.0

70 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -110,7 +110,7 @@
  "cipher 0.3.0",
  "ctr 0.8.0",
  "ghash 0.4.4",
- "subtle",
+ "subtle 2.4.1",
 ]
 
 [[package]]
@@ -124,7 +124,7 @@
  "cipher 0.4.4",
  "ctr 0.9.2",
  "ghash 0.5.0",
- "subtle",
+ "subtle 2.4.1",
 ]
 
 [[package]]
@@ -149,32 +149,33 @@
 
 [[package]]
 name = "ahash"
-version = "0.7.6"
+version = "0.7.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
+checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd"
 dependencies = [
- "getrandom 0.2.10",
+ "getrandom 0.2.11",
  "once_cell",
  "version_check",
 ]
 
 [[package]]
 name = "ahash"
-version = "0.8.3"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
+checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
 dependencies = [
  "cfg-if",
- "getrandom 0.2.10",
+ "getrandom 0.2.11",
  "once_cell",
  "version_check",
+ "zerocopy",
 ]
 
 [[package]]
 name = "aho-corasick"
-version = "1.1.1"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
 dependencies = [
  "memchr",
 ]
@@ -310,6 +311,17 @@
 checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
 
 [[package]]
+name = "ark-bls12-377"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb00293ba84f51ce3bd026bd0de55899c4e68f0a39a5728cebae3a73ffdc0a4f"
+dependencies = [
+ "ark-ec",
+ "ark-ff",
+ "ark-std",
+]
+
+[[package]]
 name = "ark-bls12-381"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -336,18 +348,6 @@
  "itertools 0.10.5",
  "num-traits",
  "zeroize",
-]
-
-[[package]]
-name = "ark-ed-on-bls12-381-bandersnatch"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9cde0f2aa063a2a5c28d39b47761aa102bda7c13c84fc118a61b87c7b2f785c"
-dependencies = [
- "ark-bls12-381",
- "ark-ec",
- "ark-ff",
- "ark-std",
 ]
 
 [[package]]
@@ -404,51 +404,9 @@
  "ark-std",
  "derivative",
  "hashbrown 0.13.2",
-]
-
-[[package]]
-name = "ark-scale"
-version = "0.0.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49b08346a3e38e2be792ef53ee168623c9244d968ff00cd70fb9932f6fe36393"
-dependencies = [
- "ark-ec",
- "ark-ff",
- "ark-serialize",
- "ark-std",
- "parity-scale-codec",
 ]
 
 [[package]]
-name = "ark-scale"
-version = "0.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51bd73bb6ddb72630987d37fa963e99196896c0d0ea81b7c894567e74a2f83af"
-dependencies = [
- "ark-ec",
- "ark-ff",
- "ark-serialize",
- "ark-std",
- "parity-scale-codec",
- "scale-info",
-]
-
-[[package]]
-name = "ark-secret-scalar"
-version = "0.0.2"
-source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1"
-dependencies = [
- "ark-ec",
- "ark-ff",
- "ark-serialize",
- "ark-std",
- "ark-transcript",
- "digest 0.10.7",
- "rand_core 0.6.4",
- "zeroize",
-]
-
-[[package]]
 name = "ark-serialize"
 version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -482,23 +440,16 @@
 ]
 
 [[package]]
-name = "ark-transcript"
-version = "0.0.2"
-source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1"
-dependencies = [
- "ark-ff",
- "ark-serialize",
- "ark-std",
- "digest 0.10.7",
- "rand_core 0.6.4",
- "sha3 0.10.8",
-]
+name = "array-bytes"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6"
 
 [[package]]
 name = "array-bytes"
-version = "6.1.0"
+version = "6.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b1c5a481ec30a5abd8dfbd94ab5cf1bb4e9a66be7f1b3b322f2f1170c200fd"
+checksum = "de17a919934ad8c5cc99a1a74de4e2dab95d6121a8f27f94755ff525b630382c"
 
 [[package]]
 name = "arrayref"
@@ -607,21 +558,34 @@
 checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
 dependencies = [
  "concurrent-queue",
- "event-listener",
+ "event-listener 2.5.3",
  "futures-core",
 ]
 
 [[package]]
+name = "async-channel"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d37875bd9915b7d67c2f117ea2c30a0989874d0b2cb694fe25403c85763c0c9e"
+dependencies = [
+ "concurrent-queue",
+ "event-listener 3.1.0",
+ "event-listener-strategy",
+ "futures-core",
+ "pin-project-lite 0.2.13",
+]
+
+[[package]]
 name = "async-executor"
-version = "1.5.4"
+version = "1.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c1da3ae8dabd9c00f453a329dfe1fb28da3c0a72e2478cdcd93171740c20499"
+checksum = "fc5ea910c42e5ab19012bab31f53cb4d63d54c3a27730f9a833a88efcf4bb52d"
 dependencies = [
- "async-lock",
+ "async-lock 3.1.1",
  "async-task",
  "concurrent-queue",
  "fastrand 2.0.1",
- "futures-lite",
+ "futures-lite 2.0.1",
  "slab",
 ]
 
@@ -631,10 +595,10 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06"
 dependencies = [
- "async-lock",
+ "async-lock 2.8.0",
  "autocfg",
  "blocking",
- "futures-lite",
+ "futures-lite 1.13.0",
 ]
 
 [[package]]
@@ -643,84 +607,121 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
 dependencies = [
- "async-lock",
+ "async-lock 2.8.0",
  "autocfg",
  "cfg-if",
  "concurrent-queue",
- "futures-lite",
+ "futures-lite 1.13.0",
  "log",
  "parking",
- "polling",
- "rustix 0.37.24",
+ "polling 2.8.0",
+ "rustix 0.37.27",
  "slab",
- "socket2 0.4.9",
+ "socket2 0.4.10",
  "waker-fn",
 ]
 
 [[package]]
+name = "async-io"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41ed9d5715c2d329bf1b4da8d60455b99b187f27ba726df2883799af9af60997"
+dependencies = [
+ "async-lock 3.1.1",
+ "cfg-if",
+ "concurrent-queue",
+ "futures-io",
+ "futures-lite 2.0.1",
+ "parking",
+ "polling 3.3.0",
+ "rustix 0.38.25",
+ "slab",
+ "tracing",
+ "waker-fn",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
 name = "async-lock"
 version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
 dependencies = [
- "event-listener",
+ "event-listener 2.5.3",
 ]
 
 [[package]]
+name = "async-lock"
+version = "3.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "655b9c7fe787d3b25cc0f804a1a8401790f0c5bc395beb5a64dc77d8de079105"
+dependencies = [
+ "event-listener 3.1.0",
+ "event-listener-strategy",
+ "pin-project-lite 0.2.13",
+]
+
+[[package]]
 name = "async-net"
 version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f"
 dependencies = [
- "async-io",
+ "async-io 1.13.0",
  "blocking",
- "futures-lite",
+ "futures-lite 1.13.0",
 ]
 
 [[package]]
 name = "async-process"
-version = "1.7.0"
+version = "1.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9"
+checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88"
 dependencies = [
- "async-io",
- "async-lock",
- "autocfg",
+ "async-io 1.13.0",
+ "async-lock 2.8.0",
+ "async-signal",
  "blocking",
  "cfg-if",
- "event-listener",
- "futures-lite",
- "rustix 0.37.24",
- "signal-hook",
+ "event-listener 3.1.0",
+ "futures-lite 1.13.0",
+ "rustix 0.38.25",
  "windows-sys 0.48.0",
 ]
 
 [[package]]
-name = "async-recursion"
-version = "1.0.5"
+name = "async-signal"
+version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
+checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5"
 dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.37",
+ "async-io 2.2.0",
+ "async-lock 2.8.0",
+ "atomic-waker",
+ "cfg-if",
+ "futures-core",
+ "futures-io",
+ "rustix 0.38.25",
+ "signal-hook-registry",
+ "slab",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
 name = "async-task"
-version = "4.4.1"
+version = "4.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9441c6b2fe128a7c2bf680a44c34d0df31ce09e5b7e401fcca3faa483dbc921"
+checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1"
 
 [[package]]
 name = "async-trait"
-version = "0.1.73"
+version = "0.1.74"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
+checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -790,28 +791,6 @@
  "miniz_oxide",
  "object 0.32.1",
  "rustc-demangle",
-]
-
-[[package]]
-name = "bandersnatch_vrfs"
-version = "0.0.1"
-source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1"
-dependencies = [
- "ark-bls12-381",
- "ark-ec",
- "ark-ed-on-bls12-381-bandersnatch",
- "ark-ff",
- "ark-scale 0.0.11",
- "ark-serialize",
- "ark-std",
- "dleq_vrf",
- "fflonk",
- "merlin 3.0.0",
- "rand_chacha 0.3.1",
- "rand_core 0.6.4",
- "ring 0.1.0",
- "sha2 0.10.8",
- "zeroize",
 ]
 
 [[package]]
@@ -840,9 +819,9 @@
 
 [[package]]
 name = "base64"
-version = "0.21.4"
+version = "0.21.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
+checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
 
 [[package]]
 name = "base64ct"
@@ -861,8 +840,9 @@
 
 [[package]]
 name = "binary-merkle-tree"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a399848a68a5196a04c19db5bfc4dca3cd0989a3165150f06c1ad1bc8882aa34"
 dependencies = [
  "hash-db 0.16.0",
  "log",
@@ -895,7 +875,7 @@
  "regex",
  "rustc-hash",
  "shlex",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -921,9 +901,9 @@
 
 [[package]]
 name = "bitflags"
-version = "2.4.0"
+version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
+checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
 
 [[package]]
 name = "bitvec"
@@ -939,6 +919,18 @@
 
 [[package]]
 name = "blake2"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330"
+dependencies = [
+ "byte-tools",
+ "crypto-mac 0.7.0",
+ "digest 0.8.1",
+ "opaque-debug 0.2.3",
+]
+
+[[package]]
+name = "blake2"
 version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
@@ -1048,16 +1040,16 @@
 
 [[package]]
 name = "blocking"
-version = "1.4.0"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94c4ef1f913d78636d78d538eec1f18de81e481f44b1be0a81060090530846e1"
+checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118"
 dependencies = [
- "async-channel",
- "async-lock",
+ "async-channel 2.1.0",
+ "async-lock 3.1.1",
  "async-task",
  "fastrand 2.0.1",
  "futures-io",
- "futures-lite",
+ "futures-lite 2.0.1",
  "piper",
  "tracing",
 ]
@@ -1084,9 +1076,9 @@
 
 [[package]]
 name = "bounded-collections"
-version = "0.1.8"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb5b05133427c07c4776906f673ccf36c21b102c9829c641a5b56bd151d44fd6"
+checksum = "ca548b6163b872067dc5eb82fd130c56881435e30367d2073594a3d9744120dd"
 dependencies = [
  "log",
  "parity-scale-codec",
@@ -1104,6 +1096,18 @@
 ]
 
 [[package]]
+name = "bp-xcm-bridge-hub-router"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be3b4fafc31f17da1b4ea403c4118e4f4f1d9a5a696729b374551d582e48633b"
+dependencies = [
+ "parity-scale-codec",
+ "scale-info",
+ "sp-core",
+ "sp-runtime",
+]
+
+[[package]]
 name = "bs58"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1120,9 +1124,9 @@
 
 [[package]]
 name = "bstr"
-version = "1.6.2"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a"
+checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
 dependencies = [
  "memchr",
  "serde",
@@ -1163,9 +1167,9 @@
 
 [[package]]
 name = "byteorder"
-version = "1.4.3"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "bytes"
@@ -1185,6 +1189,16 @@
 ]
 
 [[package]]
+name = "c2-chacha"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d27dae93fe7b1e0424dc57179ac396908c26b035a87234809f5c4dfd1b47dc80"
+dependencies = [
+ "cipher 0.2.5",
+ "ppv-lite86",
+]
+
+[[package]]
 name = "camino"
 version = "1.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1195,9 +1209,9 @@
 
 [[package]]
 name = "cargo-platform"
-version = "0.1.3"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479"
+checksum = "e34637b3140142bdf929fb439e8aa4ebad7651ebf7b1080b3930aa16ac1459ff"
 dependencies = [
  "serde",
 ]
@@ -1210,7 +1224,7 @@
 dependencies = [
  "camino",
  "cargo-platform",
- "semver 1.0.19",
+ "semver 1.0.20",
  "serde",
  "serde_json",
  "thiserror",
@@ -1234,7 +1248,7 @@
 dependencies = [
  "aead 0.3.2",
  "cipher 0.2.5",
- "subtle",
+ "subtle 2.4.1",
 ]
 
 [[package]]
@@ -1268,15 +1282,13 @@
 checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
 
 [[package]]
-name = "chacha20"
-version = "0.8.2"
+name = "chacha"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6"
+checksum = "ddf3c081b5fba1e5615640aae998e0fbd10c24cbd897ee39ed754a77601a4862"
 dependencies = [
- "cfg-if",
- "cipher 0.3.0",
- "cpufeatures",
- "zeroize",
+ "byteorder",
+ "keystream",
 ]
 
 [[package]]
@@ -1292,14 +1304,14 @@
 
 [[package]]
 name = "chacha20poly1305"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5"
+checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
 dependencies = [
- "aead 0.4.3",
- "chacha20 0.8.2",
- "cipher 0.3.0",
- "poly1305 0.7.2",
+ "aead 0.5.2",
+ "chacha20",
+ "cipher 0.4.4",
+ "poly1305",
  "zeroize",
 ]
 
@@ -1356,6 +1368,7 @@
 dependencies = [
  "crypto-common",
  "inout",
+ "zeroize",
 ]
 
 [[package]]
@@ -1380,9 +1393,9 @@
 
 [[package]]
 name = "clap"
-version = "4.4.6"
+version = "4.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956"
+checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -1390,9 +1403,9 @@
 
 [[package]]
 name = "clap_builder"
-version = "4.4.6"
+version = "4.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45"
+checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc"
 dependencies = [
  "anstream",
  "anstyle",
@@ -1402,27 +1415,27 @@
 
 [[package]]
 name = "clap_derive"
-version = "4.4.2"
+version = "4.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
+checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
 dependencies = [
  "heck",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "clap_lex"
-version = "0.5.1"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
+checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
 
 [[package]]
 name = "coarsetime"
-version = "0.1.28"
+version = "0.1.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99280f81a35511dda7d44f7c943491b41d3ac6fd0b54aea92498bec8612a2423"
+checksum = "71367d3385c716342014ad17e3d19f7788ae514885a1f4c24f500260fb365e1a"
 dependencies = [
  "libc",
  "once_cell",
@@ -1448,27 +1461,13 @@
 
 [[package]]
 name = "comfy-table"
-version = "7.0.1"
+version = "7.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ab77dbd8adecaf3f0db40581631b995f312a8a5ae3aa9993188bb8f23d83a5b"
+checksum = "7c64043d6c7b7a4c58e39e7efccfdea7b93d885a795d0c054a69dbbf4dd52686"
 dependencies = [
- "strum",
- "strum_macros",
+ "strum 0.25.0",
+ "strum_macros 0.25.3",
  "unicode-width",
-]
-
-[[package]]
-name = "common"
-version = "0.1.0"
-source = "git+https://github.com/w3f/ring-proof?rev=0e948f3#0e948f3c28cbacecdd3020403c4841c0eb339213"
-dependencies = [
- "ark-ec",
- "ark-ff",
- "ark-poly",
- "ark-serialize",
- "ark-std",
- "fflonk",
- "merlin 3.0.0",
 ]
 
 [[package]]
@@ -1507,23 +1506,21 @@
 
 [[package]]
 name = "const-random"
-version = "0.1.15"
+version = "0.1.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e"
+checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a"
 dependencies = [
  "const-random-macro",
- "proc-macro-hack",
 ]
 
 [[package]]
 name = "const-random-macro"
-version = "0.1.15"
+version = "0.1.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb"
+checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
 dependencies = [
- "getrandom 0.2.10",
+ "getrandom 0.2.11",
  "once_cell",
- "proc-macro-hack",
  "tiny-keccak",
 ]
 
@@ -1540,6 +1537,12 @@
 checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
 
 [[package]]
+name = "constcat"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd7e35aee659887cbfb97aaf227ac12cad1a9d7c71e55ff3376839ed4e282d08"
+
+[[package]]
 name = "convert_case"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1591,9 +1594,9 @@
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.9"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
+checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
 dependencies = [
  "libc",
 ]
@@ -1707,9 +1710,9 @@
 
 [[package]]
 name = "crc-catalog"
-version = "2.2.0"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484"
+checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
 
 [[package]]
 name = "crc32fast"
@@ -1777,19 +1780,19 @@
 dependencies = [
  "generic-array 0.14.7",
  "rand_core 0.6.4",
- "subtle",
+ "subtle 2.4.1",
  "zeroize",
 ]
 
 [[package]]
 name = "crypto-bigint"
-version = "0.5.3"
+version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124"
+checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
 dependencies = [
  "generic-array 0.14.7",
  "rand_core 0.6.4",
- "subtle",
+ "subtle 2.4.1",
  "zeroize",
 ]
 
@@ -1806,12 +1809,22 @@
 
 [[package]]
 name = "crypto-mac"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
+dependencies = [
+ "generic-array 0.12.4",
+ "subtle 1.0.0",
+]
+
+[[package]]
+name = "crypto-mac"
 version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
 dependencies = [
  "generic-array 0.14.7",
- "subtle",
+ "subtle 2.4.1",
 ]
 
 [[package]]
@@ -1821,7 +1834,7 @@
 checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
 dependencies = [
  "generic-array 0.14.7",
- "subtle",
+ "subtle 2.4.1",
 ]
 
 [[package]]
@@ -1844,8 +1857,9 @@
 
 [[package]]
 name = "cumulus-client-cli"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "858e5a1c2d26c304d75cc7158ed2579f0ff90b68f2d07a2395d073249d485424"
 dependencies = [
  "clap",
  "parity-scale-codec",
@@ -1860,8 +1874,9 @@
 
 [[package]]
 name = "cumulus-client-collator"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be58c6ef9780a83267e0b9db50a01158d58ad37ba45ed8162a9ea1b2d61d119c"
 dependencies = [
  "cumulus-client-consensus-common",
  "cumulus-client-network",
@@ -1883,8 +1898,9 @@
 
 [[package]]
 name = "cumulus-client-consensus-aura"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b73f52d21017ff0f2dc6542f2873e1dc3e17561656d6af0810fb813fb553694"
 dependencies = [
  "async-trait",
  "cumulus-client-collator",
@@ -1925,8 +1941,9 @@
 
 [[package]]
 name = "cumulus-client-consensus-common"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ec580468eb700a2776cac54871704b3c3894bc0646c3b8375756bfffd24928f"
 dependencies = [
  "async-trait",
  "cumulus-client-pov-recovery",
@@ -1954,8 +1971,9 @@
 
 [[package]]
 name = "cumulus-client-consensus-proposer"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23a859c95a853e37c642b613be517d3d9c410a67204a5bd92eb35c5daaffa44d"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -1969,8 +1987,9 @@
 
 [[package]]
 name = "cumulus-client-network"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fac979caafb16a47493dfce7509decadad81f982c0110473ab69389af663678d"
 dependencies = [
  "async-trait",
  "cumulus-relay-chain-interface",
@@ -1992,8 +2011,9 @@
 
 [[package]]
 name = "cumulus-client-pov-recovery"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4031cda3e64955d57166068a27d544f46f4a9e4c14268a09d8b67eeac7fc51d"
 dependencies = [
  "async-trait",
  "cumulus-primitives-core",
@@ -2016,8 +2036,9 @@
 
 [[package]]
 name = "cumulus-client-service"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a72ee1a2276f11243b905676b60b77ca981c567cbed3795455b464502c3d4cb8"
 dependencies = [
  "cumulus-client-cli",
  "cumulus-client-collator",
@@ -2051,8 +2072,9 @@
 
 [[package]]
 name = "cumulus-pallet-aura-ext"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071cdddd31e2b0d47a74249675de828857f61eb5f6afa36cfcf63ea6ee2b60f2"
 dependencies = [
  "cumulus-pallet-parachain-system",
  "frame-support",
@@ -2069,8 +2091,9 @@
 
 [[package]]
 name = "cumulus-pallet-dmp-queue"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d1cb9d43cdfeedea19b4f6b8386e5b6264a97938b29f5c711a84e9dc7105ff7"
 dependencies = [
  "cumulus-primitives-core",
  "frame-support",
@@ -2086,8 +2109,9 @@
 
 [[package]]
 name = "cumulus-pallet-parachain-system"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d20d2280051998fcf113f04d25d4b39f27b449570b6350fdfb7e92541cb0aae7"
 dependencies = [
  "bytes",
  "cumulus-pallet-parachain-system-proc-macro",
@@ -2100,6 +2124,7 @@
  "log",
  "parity-scale-codec",
  "polkadot-parachain-primitives",
+ "polkadot-runtime-parachains",
  "scale-info",
  "sp-core",
  "sp-externalities",
@@ -2111,24 +2136,26 @@
  "sp-trie",
  "sp-version",
  "staging-xcm",
- "trie-db",
+ "trie-db 0.28.0",
 ]
 
 [[package]]
 name = "cumulus-pallet-parachain-system-proc-macro"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84baea20d10325b2501b6fa06d4a7902a43d6a6c62c71b5309e75c3ad8ae1441"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "cumulus-pallet-xcm"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ff03e14a0f5847bdee67a673ee945d3acd5c1d7238d46993208dcbfb774e27f"
 dependencies = [
  "cumulus-primitives-core",
  "frame-support",
@@ -2143,9 +2170,11 @@
 
 [[package]]
 name = "cumulus-pallet-xcmp-queue"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6af9816dd6564149729ba133c2c984c88fb15c4a2cb66f57be06b9147744e51"
 dependencies = [
+ "bp-xcm-bridge-hub-router",
  "cumulus-primitives-core",
  "frame-benchmarking",
  "frame-support",
@@ -2153,8 +2182,10 @@
  "log",
  "parity-scale-codec",
  "polkadot-runtime-common",
+ "polkadot-runtime-parachains",
  "rand_chacha 0.3.1",
  "scale-info",
+ "sp-core",
  "sp-io",
  "sp-runtime",
  "sp-std",
@@ -2164,8 +2195,9 @@
 
 [[package]]
 name = "cumulus-primitives-aura"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51c2ecd2393555e89245676fd49003fdc68dc7aa108f83f8c5ff5f8936ce5543"
 dependencies = [
  "parity-scale-codec",
  "polkadot-core-primitives",
@@ -2178,8 +2210,9 @@
 
 [[package]]
 name = "cumulus-primitives-core"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d40f62add2352287be4cb58b0017a91f61d953e2c6d2777c20d93185558196e1"
 dependencies = [
  "parity-scale-codec",
  "polkadot-core-primitives",
@@ -2195,8 +2228,9 @@
 
 [[package]]
 name = "cumulus-primitives-parachain-inherent"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d0b1e0e6dcf393dbf05b31122a8c4739acf407a96ec8fd707886f36ee95c355"
 dependencies = [
  "async-trait",
  "cumulus-primitives-core",
@@ -2218,8 +2252,9 @@
 
 [[package]]
 name = "cumulus-primitives-timestamp"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "771ef4a34f7bcd4e8782f73d8dbd0df031b1c1c82e54b06af69f88df2cddc316"
 dependencies = [
  "cumulus-primitives-core",
  "futures",
@@ -2231,14 +2266,17 @@
 
 [[package]]
 name = "cumulus-primitives-utility"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b4ef704f5a346711d0448f82e57dc5784b186f4bf5e3efbbca0df814b203539"
 dependencies = [
  "cumulus-primitives-core",
  "frame-support",
  "log",
+ "pallet-xcm-benchmarks",
  "parity-scale-codec",
  "polkadot-runtime-common",
+ "polkadot-runtime-parachains",
  "sp-io",
  "sp-runtime",
  "sp-std",
@@ -2249,8 +2287,9 @@
 
 [[package]]
 name = "cumulus-relay-chain-inprocess-interface"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9518b7440b3f887433058b000a564e06b6799fd6d2776f4d035b2802c67742eb"
 dependencies = [
  "async-trait",
  "cumulus-primitives-core",
@@ -2273,8 +2312,9 @@
 
 [[package]]
 name = "cumulus-relay-chain-interface"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af081ef8885042e7ae96e9d1cf32ec6f0616fe4cb78f0325ed7c5accded687fb"
 dependencies = [
  "async-trait",
  "cumulus-primitives-core",
@@ -2291,10 +2331,11 @@
 
 [[package]]
 name = "cumulus-relay-chain-minimal-node"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69a1635ecc0bc20e7907a559983c818e4130ecfd899635e831f3f9b93966082c"
 dependencies = [
- "array-bytes",
+ "array-bytes 6.2.0",
  "async-trait",
  "cumulus-primitives-core",
  "cumulus-relay-chain-interface",
@@ -2316,18 +2357,19 @@
  "sc-service",
  "sc-tracing",
  "sc-utils",
- "schnellru",
  "sp-api",
  "sp-consensus",
  "sp-consensus-babe",
  "sp-runtime",
+ "substrate-prometheus-endpoint",
  "tracing",
 ]
 
 [[package]]
 name = "cumulus-relay-chain-rpc-interface"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce507996b8e97e07e3687c1c55159b38f56b2550b476c727114ab2e7ad7b2bf1"
 dependencies = [
  "async-trait",
  "cumulus-primitives-core",
@@ -2364,8 +2406,9 @@
 
 [[package]]
 name = "cumulus-test-relay-sproof-builder"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59b921a9cb6758faa1c739f135fd87aa1e10a4e86a1c1db3119b396a62287cf2"
 dependencies = [
  "cumulus-primitives-core",
  "parity-scale-codec",
@@ -2385,7 +2428,7 @@
  "byteorder",
  "digest 0.8.1",
  "rand_core 0.5.1",
- "subtle",
+ "subtle 2.4.1",
  "zeroize",
 ]
 
@@ -2398,7 +2441,7 @@
  "byteorder",
  "digest 0.9.0",
  "rand_core 0.5.1",
- "subtle",
+ "subtle 2.4.1",
  "zeroize",
 ]
 
@@ -2415,19 +2458,19 @@
  "fiat-crypto",
  "platforms",
  "rustc_version",
- "subtle",
+ "subtle 2.4.1",
  "zeroize",
 ]
 
 [[package]]
 name = "curve25519-dalek-derive"
-version = "0.1.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b"
+checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -2445,9 +2488,9 @@
 
 [[package]]
 name = "cxx"
-version = "1.0.107"
+version = "1.0.110"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe98ba1789d56fb3db3bee5e032774d4f421b685de7ba703643584ba24effbe"
+checksum = "7129e341034ecb940c9072817cd9007974ea696844fc4dd582dc1653a7fbe2e8"
 dependencies = [
  "cc",
  "cxxbridge-flags",
@@ -2457,9 +2500,9 @@
 
 [[package]]
 name = "cxx-build"
-version = "1.0.107"
+version = "1.0.110"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4ce20f6b8433da4841b1dadfb9468709868022d829d5ca1f2ffbda928455ea3"
+checksum = "a2a24f3f5f8eed71936f21e570436f024f5c2e25628f7496aa7ccd03b90109d5"
 dependencies = [
  "cc",
  "codespan-reporting",
@@ -2467,24 +2510,24 @@
  "proc-macro2",
  "quote",
  "scratch",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "cxxbridge-flags"
-version = "1.0.107"
+version = "1.0.110"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20888d9e1d2298e2ff473cee30efe7d5036e437857ab68bbfea84c74dba91da2"
+checksum = "06fdd177fc61050d63f67f5bd6351fac6ab5526694ea8e359cd9cd3b75857f44"
 
 [[package]]
 name = "cxxbridge-macro"
-version = "1.0.107"
+version = "1.0.110"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fa16a70dd58129e4dfffdff535fb1bce66673f7bbeec4a5a1765a504e1ccd84"
+checksum = "587663dd5fb3d10932c8aecfe7c844db1bcf0aee93eeab08fac13dc1212c2e7f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -2599,9 +2642,12 @@
 
 [[package]]
 name = "deranged"
-version = "0.3.8"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
+checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3"
+dependencies = [
+ "powerfmt",
+]
 
 [[package]]
 name = "derivative"
@@ -2702,14 +2748,14 @@
  "block-buffer 0.10.4",
  "const-oid",
  "crypto-common",
- "subtle",
+ "subtle 2.4.1",
 ]
 
 [[package]]
 name = "directories"
-version = "4.0.1"
+version = "5.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210"
+checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
 dependencies = [
  "dirs-sys",
 ]
@@ -2726,13 +2772,14 @@
 
 [[package]]
 name = "dirs-sys"
-version = "0.3.7"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
+checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
 dependencies = [
  "libc",
+ "option-ext",
  "redox_users",
- "winapi",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -2754,40 +2801,23 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
-]
-
-[[package]]
-name = "dleq_vrf"
-version = "0.0.2"
-source = "git+https://github.com/w3f/ring-vrf?rev=3119f51#3119f51b54b69308abfb0671f6176cb125ae1bf1"
-dependencies = [
- "ark-ec",
- "ark-ff",
- "ark-scale 0.0.10",
- "ark-secret-scalar",
- "ark-serialize",
- "ark-std",
- "ark-transcript",
- "arrayvec 0.7.4",
- "rand_core 0.6.4",
- "zeroize",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "docify"
-version = "0.2.4"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76ee528c501ddd15d5181997e9518e59024844eac44fd1e40cb20ddb2a8562fa"
+checksum = "4235e9b248e2ba4b92007fe9c646f3adf0ffde16dc74713eacc92b8bc58d8d2f"
 dependencies = [
  "docify_macros",
 ]
 
 [[package]]
 name = "docify_macros"
-version = "0.2.4"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ca01728ab2679c464242eca99f94e2ce0514b52ac9ad950e2ed03fca991231c"
+checksum = "47020e12d7c7505670d1363dd53d6c23724f71a90a3ae32ff8eba40de8404626"
 dependencies = [
  "common-path",
  "derive-syn-parse",
@@ -2795,7 +2825,7 @@
  "proc-macro2",
  "quote",
  "regex",
- "syn 2.0.37",
+ "syn 2.0.39",
  "termcolor",
  "toml 0.7.8",
  "walkdir",
@@ -2842,9 +2872,9 @@
 
 [[package]]
 name = "dyn-clone"
-version = "1.0.14"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd"
+checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d"
 
 [[package]]
 name = "ecdsa"
@@ -2860,39 +2890,40 @@
 
 [[package]]
 name = "ecdsa"
-version = "0.16.8"
+version = "0.16.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4"
+checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
 dependencies = [
  "der 0.7.8",
  "digest 0.10.7",
- "elliptic-curve 0.13.5",
+ "elliptic-curve 0.13.8",
  "rfc6979 0.4.0",
- "signature 2.1.0",
+ "signature 2.2.0",
  "spki 0.7.2",
 ]
 
 [[package]]
 name = "ed25519"
-version = "2.2.2"
+version = "2.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d"
+checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
 dependencies = [
  "pkcs8 0.10.2",
- "signature 2.1.0",
+ "signature 2.2.0",
 ]
 
 [[package]]
 name = "ed25519-dalek"
-version = "2.0.0"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980"
+checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0"
 dependencies = [
  "curve25519-dalek 4.1.1",
  "ed25519",
  "rand_core 0.6.4",
  "serde",
  "sha2 0.10.8",
+ "subtle 2.4.1",
  "zeroize",
 ]
 
@@ -2918,7 +2949,7 @@
 dependencies = [
  "curve25519-dalek 4.1.1",
  "ed25519",
- "hashbrown 0.14.1",
+ "hashbrown 0.14.2",
  "hex",
  "rand_core 0.6.4",
  "sha2 0.10.8",
@@ -2949,18 +2980,18 @@
  "pkcs8 0.9.0",
  "rand_core 0.6.4",
  "sec1 0.3.0",
- "subtle",
+ "subtle 2.4.1",
  "zeroize",
 ]
 
 [[package]]
 name = "elliptic-curve"
-version = "0.13.5"
+version = "0.13.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b"
+checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
 dependencies = [
  "base16ct 0.2.0",
- "crypto-bigint 0.5.3",
+ "crypto-bigint 0.5.5",
  "digest 0.10.7",
  "ff 0.13.0",
  "generic-array 0.14.7",
@@ -2968,7 +2999,7 @@
  "pkcs8 0.10.2",
  "rand_core 0.6.4",
  "sec1 0.7.3",
- "subtle",
+ "subtle 2.4.1",
  "zeroize",
 ]
 
@@ -3007,7 +3038,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -3018,27 +3049,14 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
-]
-
-[[package]]
-name = "env_logger"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
-dependencies = [
- "atty",
- "humantime",
- "log",
- "regex",
- "termcolor",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "env_logger"
-version = "0.10.0"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
+checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
 dependencies = [
  "humantime",
  "is-terminal",
@@ -3061,23 +3079,12 @@
 
 [[package]]
 name = "errno"
-version = "0.3.4"
+version = "0.3.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480"
+checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8"
 dependencies = [
- "errno-dragonfly",
  "libc",
  "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
- "libc",
 ]
 
 [[package]]
@@ -3136,6 +3143,27 @@
 checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
 
 [[package]]
+name = "event-listener"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite 0.2.13",
+]
+
+[[package]]
+name = "event-listener-strategy"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160"
+dependencies = [
+ "event-listener 3.1.0",
+ "pin-project-lite 0.2.13",
+]
+
+[[package]]
 name = "evm"
 version = "0.39.1"
 source = "git+https://github.com/rust-blockchain/evm?rev=b7b82c7e1fc57b7449d6dfa6826600de37cc1e65#b7b82c7e1fc57b7449d6dfa6826600de37cc1e65"
@@ -3248,27 +3276,15 @@
 
 [[package]]
 name = "expander"
-version = "0.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3774182a5df13c3d1690311ad32fbe913feef26baba609fa2dd5f72042bd2ab6"
-dependencies = [
- "blake2",
- "fs-err",
- "proc-macro2",
- "quote",
-]
-
-[[package]]
-name = "expander"
 version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5f86a749cf851891866c10515ef6c299b5c69661465e9c3bbe7e07a2b77fb0f7"
 dependencies = [
- "blake2",
+ "blake2 0.10.6",
  "fs-err",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -3316,7 +3332,7 @@
 dependencies = [
  "expander 0.0.4",
  "indexmap 1.9.3",
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
@@ -3326,7 +3342,7 @@
 [[package]]
 name = "fc-api"
 version = "1.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "async-trait",
  "fp-storage",
@@ -3338,7 +3354,7 @@
 [[package]]
 name = "fc-consensus"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "async-trait",
  "fp-consensus",
@@ -3354,7 +3370,7 @@
 [[package]]
 name = "fc-db"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "async-trait",
  "fc-api",
@@ -3375,7 +3391,7 @@
 [[package]]
 name = "fc-mapping-sync"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "fc-db",
  "fc-storage",
@@ -3396,7 +3412,7 @@
 [[package]]
 name = "fc-rpc"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "ethereum",
  "ethereum-types",
@@ -3450,7 +3466,7 @@
 [[package]]
 name = "fc-rpc-core"
 version = "1.1.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "ethereum",
  "ethereum-types",
@@ -3463,7 +3479,7 @@
 [[package]]
 name = "fc-storage"
 version = "1.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "ethereum",
  "ethereum-types",
@@ -3494,7 +3510,7 @@
 checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
 dependencies = [
  "rand_core 0.6.4",
- "subtle",
+ "subtle 2.4.1",
 ]
 
 [[package]]
@@ -3504,27 +3520,14 @@
 checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
 dependencies = [
  "rand_core 0.6.4",
- "subtle",
-]
-
-[[package]]
-name = "fflonk"
-version = "0.1.0"
-source = "git+https://github.com/w3f/fflonk#26a5045b24e169cffc1f9328ca83d71061145c40"
-dependencies = [
- "ark-ec",
- "ark-ff",
- "ark-poly",
- "ark-serialize",
- "ark-std",
- "merlin 3.0.0",
+ "subtle 2.4.1",
 ]
 
 [[package]]
 name = "fiat-crypto"
-version = "0.2.1"
+version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d"
+checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7"
 
 [[package]]
 name = "file-per-thread-logger"
@@ -3532,7 +3535,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866"
 dependencies = [
- "env_logger 0.10.0",
+ "env_logger",
  "log",
 ]
 
@@ -3584,9 +3587,9 @@
 
 [[package]]
 name = "flate2"
-version = "1.0.27"
+version = "1.0.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010"
+checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
 dependencies = [
  "crc32fast",
  "libz-sys",
@@ -3610,8 +3613,9 @@
 
 [[package]]
 name = "fork-tree"
-version = "3.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "11.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c2d0a4310dcf0e5cce78e35e60dc2fda80ef61c8f8fc382e685dfc24fcf5db9"
 dependencies = [
  "parity-scale-codec",
 ]
@@ -3628,7 +3632,7 @@
 [[package]]
 name = "fp-account"
 version = "1.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "hex",
  "impl-serde",
@@ -3647,7 +3651,7 @@
 [[package]]
 name = "fp-consensus"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "ethereum",
  "parity-scale-codec",
@@ -3659,7 +3663,7 @@
 [[package]]
 name = "fp-ethereum"
 version = "1.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "ethereum",
  "ethereum-types",
@@ -3672,7 +3676,7 @@
 [[package]]
 name = "fp-evm"
 version = "3.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "evm",
  "frame-support",
@@ -3688,7 +3692,7 @@
 [[package]]
 name = "fp-rpc"
 version = "3.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "ethereum",
  "ethereum-types",
@@ -3705,7 +3709,7 @@
 [[package]]
 name = "fp-self-contained"
 version = "1.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "frame-support",
  "parity-scale-codec",
@@ -3717,7 +3721,7 @@
 [[package]]
 name = "fp-storage"
 version = "2.0.0"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "parity-scale-codec",
  "serde",
@@ -3731,8 +3735,9 @@
 
 [[package]]
 name = "frame-benchmarking"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3dd4946d63eab00d899f08a7e74e965cc6785c2298efaea6a2752905f4810407"
 dependencies = [
  "frame-support",
  "frame-support-procedural",
@@ -3756,11 +3761,12 @@
 
 [[package]]
 name = "frame-benchmarking-cli"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "29.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67e51c371bff90ba44767a79e72a036d7d648cee621cd2fe9f693e8c1d62941e"
 dependencies = [
  "Inflector",
- "array-bytes",
+ "array-bytes 6.2.0",
  "chrono",
  "clap",
  "comfy-table",
@@ -3804,19 +3810,21 @@
 
 [[package]]
 name = "frame-election-provider-solution-type"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "12.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03911cf3675af64252a6de7b4f383eafa80d5ea5830184e7a0739aeb0b95272d"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "frame-election-provider-support"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebad507fb038db2f7ce982d30bd9828a59785c9a4780348d59cd6cceaee80d1a"
 dependencies = [
  "frame-election-provider-solution-type",
  "frame-support",
@@ -3832,8 +3840,9 @@
 
 [[package]]
 name = "frame-executive"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dda2c20ea3267ee20c9a5482f320236510c4ade6aec1dd930cb57dc5651c64f"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -3862,10 +3871,10 @@
 
 [[package]]
 name = "frame-remote-externalities"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a30013df51f4d4e58472c4fecdbfeb141234ece5f6355e5b3a3e51d3f87d452d"
 dependencies = [
- "async-recursion",
  "futures",
  "indicatif",
  "jsonrpsee",
@@ -3884,8 +3893,9 @@
 
 [[package]]
 name = "frame-support"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "023504bbdd0e8d1ebe3d9d289b009337cdb9a24c5e74615ffd7b188aa1664c2d"
 dependencies = [
  "aquamarine",
  "bitflags 1.3.2",
@@ -3924,8 +3934,9 @@
 
 [[package]]
 name = "frame-support-procedural"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "20.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d6bc383298353ff2790ac1a301262c21ac196dbc26ef67a2213c46524a06dd1"
 dependencies = [
  "Inflector",
  "cfg-expr",
@@ -3937,35 +3948,39 @@
  "proc-macro-warning",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "sp-core-hashing",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "frame-support-procedural-tools"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "9.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3ac1266522a8c9a2d2d26d205ec3028b88582d5f3cd5cbc75d0ec8271d197b7"
 dependencies = [
  "frame-support-procedural-tools-derive",
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "frame-support-procedural-tools-derive"
-version = "3.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c078db2242ea7265faa486004e7fd8daaf1a577cfcac0070ce55d926922883"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "frame-system"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57e316407c45a5093c833966a906301aa0dcbd05048061cd9cde2548d017bfd9"
 dependencies = [
  "cfg-if",
  "frame-support",
@@ -3983,8 +3998,9 @@
 
 [[package]]
 name = "frame-system-benchmarking"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b1388055d29a7a1c4d41b1623d3fcbc9d7f31d17abe04500b270b26901d926"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -3998,8 +4014,9 @@
 
 [[package]]
 name = "frame-system-rpc-runtime-api"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17572a34fd866ad6cab6977a2c30b38645e0a499b3486de00ae9103f7002d6d3"
 dependencies = [
  "parity-scale-codec",
  "sp-api",
@@ -4007,8 +4024,9 @@
 
 [[package]]
 name = "frame-try-runtime"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f082e770275f9b46ddf46b09bc7a993f84db691c39d9e4d038ac07443cb17a18"
 dependencies = [
  "frame-support",
  "parity-scale-codec",
@@ -4019,9 +4037,12 @@
 
 [[package]]
 name = "fs-err"
-version = "2.9.0"
+version = "2.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541"
+checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"
+dependencies = [
+ "autocfg",
+]
 
 [[package]]
 name = "fs2"
@@ -4039,7 +4060,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47"
 dependencies = [
- "rustix 0.38.15",
+ "rustix 0.38.25",
  "windows-sys 0.48.0",
 ]
 
@@ -4051,9 +4072,9 @@
 
 [[package]]
 name = "futures"
-version = "0.3.28"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
+checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -4066,9 +4087,9 @@
 
 [[package]]
 name = "futures-channel"
-version = "0.3.28"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
+checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -4076,15 +4097,15 @@
 
 [[package]]
 name = "futures-core"
-version = "0.3.28"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
+checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.28"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
+checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -4094,9 +4115,9 @@
 
 [[package]]
 name = "futures-io"
-version = "0.3.28"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
+checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
 
 [[package]]
 name = "futures-lite"
@@ -4114,14 +4135,28 @@
 ]
 
 [[package]]
+name = "futures-lite"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb"
+dependencies = [
+ "fastrand 2.0.1",
+ "futures-core",
+ "futures-io",
+ "memchr",
+ "parking",
+ "pin-project-lite 0.2.13",
+]
+
+[[package]]
 name = "futures-macro"
-version = "0.3.28"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
+checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -4132,20 +4167,20 @@
 dependencies = [
  "futures-io",
  "rustls 0.20.9",
- "webpki 0.22.2",
+ "webpki 0.22.4",
 ]
 
 [[package]]
 name = "futures-sink"
-version = "0.3.28"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
+checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
 
 [[package]]
 name = "futures-task"
-version = "0.3.28"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
+checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
 
 [[package]]
 name = "futures-timer"
@@ -4155,9 +4190,9 @@
 
 [[package]]
 name = "futures-util"
-version = "0.3.28"
+version = "0.3.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
+checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -4223,9 +4258,9 @@
 
 [[package]]
 name = "getrandom"
-version = "0.2.10"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
 dependencies = [
  "cfg-if",
  "libc",
@@ -4296,7 +4331,7 @@
 dependencies = [
  "ff 0.12.1",
  "rand_core 0.6.4",
- "subtle",
+ "subtle 2.4.1",
 ]
 
 [[package]]
@@ -4307,14 +4342,14 @@
 dependencies = [
  "ff 0.13.0",
  "rand_core 0.6.4",
- "subtle",
+ "subtle 2.4.1",
 ]
 
 [[package]]
 name = "h2"
-version = "0.3.21"
+version = "0.3.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833"
+checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
 dependencies = [
  "bytes",
  "fnv",
@@ -4322,7 +4357,7 @@
  "futures-sink",
  "futures-util",
  "http",
- "indexmap 1.9.3",
+ "indexmap 2.1.0",
  "slab",
  "tokio",
  "tokio-util",
@@ -4331,9 +4366,9 @@
 
 [[package]]
 name = "handlebars"
-version = "4.4.0"
+version = "4.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c39b3bc2a8f715298032cf5087e58573809374b08160aa7d750582bdb82d2683"
+checksum = "faa67bab9ff362228eb3d00bd024a4965d8231bbb7921167f0cfa66c6626b225"
 dependencies = [
  "log",
  "pest",
@@ -4370,7 +4405,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 dependencies = [
- "ahash 0.7.6",
+ "ahash 0.7.7",
 ]
 
 [[package]]
@@ -4379,21 +4414,30 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
 dependencies = [
- "ahash 0.8.3",
+ "ahash 0.8.6",
 ]
 
 [[package]]
 name = "hashbrown"
-version = "0.14.1"
+version = "0.14.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12"
+checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
 dependencies = [
- "ahash 0.8.3",
+ "ahash 0.8.6",
  "allocator-api2",
  "serde",
 ]
 
 [[package]]
+name = "hashlink"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7"
+dependencies = [
+ "hashbrown 0.14.2",
+]
+
+[[package]]
 name = "heck"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4497,9 +4541,9 @@
 
 [[package]]
 name = "http"
-version = "0.2.9"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
+checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
 dependencies = [
  "bytes",
  "fnv",
@@ -4558,7 +4602,7 @@
  "httpdate",
  "itoa",
  "pin-project-lite 0.2.13",
- "socket2 0.4.9",
+ "socket2 0.4.10",
  "tokio",
  "tower-service",
  "tracing",
@@ -4567,33 +4611,33 @@
 
 [[package]]
 name = "hyper-rustls"
-version = "0.24.1"
+version = "0.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97"
+checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
 dependencies = [
  "futures-util",
  "http",
  "hyper",
  "log",
- "rustls 0.21.7",
+ "rustls 0.21.9",
  "rustls-native-certs",
  "tokio",
  "tokio-rustls",
- "webpki-roots 0.23.1",
+ "webpki-roots 0.25.2",
 ]
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.57"
+version = "0.1.58"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
+checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
  "iana-time-zone-haiku",
  "js-sys",
  "wasm-bindgen",
- "windows 0.48.0",
+ "windows-core",
 ]
 
 [[package]]
@@ -4644,11 +4688,11 @@
 
 [[package]]
 name = "if-watch"
-version = "3.0.1"
+version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9465340214b296cd17a0009acdb890d6160010b8adf8f78a00d0d7ab270f79f"
+checksum = "bbb892e5777fe09e16f3d44de7802f4daa7267ecbe8c466f19d94e25bb0c303e"
 dependencies = [
- "async-io",
+ "async-io 1.13.0",
  "core-foundation",
  "fnv",
  "futures",
@@ -4658,7 +4702,7 @@
  "rtnetlink",
  "system-configuration",
  "tokio",
- "windows 0.34.0",
+ "windows",
 ]
 
 [[package]]
@@ -4731,12 +4775,12 @@
 
 [[package]]
 name = "indexmap"
-version = "2.0.2"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
+checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
 dependencies = [
  "equivalent",
- "hashbrown 0.14.1",
+ "hashbrown 0.14.2",
 ]
 
 [[package]]
@@ -4833,7 +4877,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
 dependencies = [
- "socket2 0.5.4",
+ "socket2 0.5.5",
  "widestring",
  "windows-sys 0.48.0",
  "winreg",
@@ -4841,9 +4885,9 @@
 
 [[package]]
 name = "ipnet"
-version = "2.8.0"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
+checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
 
 [[package]]
 name = "is-terminal"
@@ -4852,7 +4896,7 @@
 checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
 dependencies = [
  "hermit-abi 0.3.3",
- "rustix 0.38.15",
+ "rustix 0.38.25",
  "windows-sys 0.48.0",
 ]
 
@@ -4891,18 +4935,18 @@
 
 [[package]]
 name = "jobserver"
-version = "0.1.26"
+version = "0.1.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
+checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "js-sys"
-version = "0.3.64"
+version = "0.3.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
+checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -4951,7 +4995,7 @@
 dependencies = [
  "anyhow",
  "arrayvec 0.7.4",
- "async-lock",
+ "async-lock 2.8.0",
  "async-trait",
  "beef",
  "futures-channel",
@@ -4997,7 +5041,7 @@
 checksum = "44e8ab85614a08792b9bff6c8feee23be78c98d0182d4c622c05256ab553892a"
 dependencies = [
  "heck",
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
@@ -5053,13 +5097,13 @@
 
 [[package]]
 name = "k256"
-version = "0.13.1"
+version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc"
+checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b"
 dependencies = [
  "cfg-if",
- "ecdsa 0.16.8",
- "elliptic-curve 0.13.5",
+ "ecdsa 0.16.9",
+ "elliptic-curve 0.13.8",
  "once_cell",
  "sha2 0.10.8",
 ]
@@ -5074,18 +5118,10 @@
 ]
 
 [[package]]
-name = "kusama-runtime-constants"
+name = "keystream"
 version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
-dependencies = [
- "frame-support",
- "polkadot-primitives",
- "polkadot-runtime-common",
- "smallvec",
- "sp-core",
- "sp-runtime",
- "sp-weights",
-]
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c33070833c9ee02266356de0c43f723152bd38bd96ddf52c82b3af10c9138b28"
 
 [[package]]
 name = "kvdb"
@@ -5122,9 +5158,9 @@
 
 [[package]]
 name = "landlock"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "520baa32708c4e957d2fc3a186bc5bd8d26637c33137f399ddfc202adb240068"
+checksum = "1530c5b973eeed4ac216af7e24baf5737645a6272e361f1fb95710678b67d9cc"
 dependencies = [
  "enumflags2",
  "libc",
@@ -5145,9 +5181,9 @@
 
 [[package]]
 name = "libc"
-version = "0.2.148"
+version = "0.2.150"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
+checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
 
 [[package]]
 name = "libloading"
@@ -5161,9 +5197,9 @@
 
 [[package]]
 name = "libm"
-version = "0.2.7"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
+checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
 
 [[package]]
 name = "libp2p"
@@ -5174,7 +5210,7 @@
  "bytes",
  "futures",
  "futures-timer",
- "getrandom 0.2.10",
+ "getrandom 0.2.11",
  "instant",
  "libp2p-allow-block-list",
  "libp2p-connection-limits",
@@ -5348,7 +5384,7 @@
  "log",
  "rand 0.8.5",
  "smallvec",
- "socket2 0.4.9",
+ "socket2 0.4.10",
  "tokio",
  "trust-dns-proto",
  "void",
@@ -5490,7 +5526,7 @@
  "libc",
  "libp2p-core",
  "log",
- "socket2 0.4.9",
+ "socket2 0.4.10",
  "tokio",
 ]
 
@@ -5508,7 +5544,7 @@
  "ring 0.16.20",
  "rustls 0.20.9",
  "thiserror",
- "webpki 0.22.2",
+ "webpki 0.22.4",
  "x509-parser 0.14.0",
  "yasna",
 ]
@@ -5591,6 +5627,17 @@
 ]
 
 [[package]]
+name = "libredox"
+version = "0.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
+dependencies = [
+ "bitflags 2.4.1",
+ "libc",
+ "redox_syscall 0.4.1",
+]
+
+[[package]]
 name = "librocksdb-sys"
 version = "0.11.0+8.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5632,7 +5679,7 @@
 dependencies = [
  "crunchy",
  "digest 0.9.0",
- "subtle",
+ "subtle 2.4.1",
 ]
 
 [[package]]
@@ -5711,15 +5758,27 @@
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.8"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
+
+[[package]]
+name = "lioness"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db"
+checksum = "4ae926706ba42c425c9457121178330d75e273df2e82e28b758faf3de3a9acb9"
+dependencies = [
+ "arrayref",
+ "blake2 0.8.1",
+ "chacha",
+ "keystream",
+]
 
 [[package]]
 name = "lock_api"
-version = "0.4.10"
+version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
+checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -5786,50 +5845,50 @@
 
 [[package]]
 name = "macro_magic"
-version = "0.4.2"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aee866bfee30d2d7e83835a4574aad5b45adba4cc807f2a3bbba974e5d4383c9"
+checksum = "e03844fc635e92f3a0067e25fa4bf3e3dbf3f2927bf3aa01bb7bc8f1c428949d"
 dependencies = [
  "macro_magic_core",
  "macro_magic_macros",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "macro_magic_core"
-version = "0.4.2"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e766a20fd9c72bab3e1e64ed63f36bd08410e75803813df210d1ce297d7ad00"
+checksum = "468155613a44cfd825f1fb0ffa532b018253920d404e6fca1e8d43155198a46d"
 dependencies = [
  "const-random",
  "derive-syn-parse",
  "macro_magic_core_macros",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "macro_magic_core_macros"
-version = "0.4.2"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c12469fc165526520dff2807c2975310ab47cf7190a45b99b49a7dc8befab17b"
+checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "macro_magic_macros"
-version = "0.4.2"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a"
+checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3"
 dependencies = [
  "macro_magic_core",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -5891,7 +5950,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64"
 dependencies = [
- "rustix 0.38.15",
+ "rustix 0.38.25",
 ]
 
 [[package]]
@@ -5991,9 +6050,9 @@
 
 [[package]]
 name = "mio"
-version = "0.8.8"
+version = "0.8.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
+checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
 dependencies = [
  "libc",
  "wasi 0.11.0+wasi-snapshot-preview1",
@@ -6001,9 +6060,35 @@
 ]
 
 [[package]]
+name = "mixnet"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daa3eb39495d8e2e2947a1d862852c90cc6a4a8845f8b41c8829cb9fcc047f4a"
+dependencies = [
+ "arrayref",
+ "arrayvec 0.7.4",
+ "bitflags 1.3.2",
+ "blake2 0.10.6",
+ "c2-chacha",
+ "curve25519-dalek 4.1.1",
+ "either",
+ "hashlink",
+ "lioness",
+ "log",
+ "parking_lot 0.12.1",
+ "rand 0.8.5",
+ "rand_chacha 0.3.1",
+ "rand_distr",
+ "subtle 2.4.1",
+ "thiserror",
+ "zeroize",
+]
+
+[[package]]
 name = "mmr-gadget"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "26.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62eff76fd1de7bad43b0e9e666970ae11ef8c24f49622585362c21ae5470986f"
 dependencies = [
  "futures",
  "log",
@@ -6021,8 +6106,9 @@
 
 [[package]]
 name = "mmr-rpc"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a387f061e68601d268aade23387eaaf6542e82b357ebc1f8d6a95a251b996d30"
 dependencies = [
  "anyhow",
  "jsonrpsee",
@@ -6115,7 +6201,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro-error",
  "proc-macro2",
  "quote",
@@ -6351,11 +6437,12 @@
 
 [[package]]
 name = "num-traits"
-version = "0.2.16"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
 dependencies = [
  "autocfg",
+ "libm",
 ]
 
 [[package]]
@@ -6370,23 +6457,23 @@
 
 [[package]]
 name = "num_enum"
-version = "0.7.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70bf6736f74634d299d00086f02986875b3c2d924781a6a2cb6c201e73da0ceb"
+checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0"
 dependencies = [
  "num_enum_derive",
 ]
 
 [[package]]
 name = "num_enum_derive"
-version = "0.7.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56ea360eafe1022f7cc56cd7b869ed57330fb2453d0c7831d99b74c65d2f5597"
+checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 2.0.0",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -6442,7 +6529,7 @@
 
 [[package]]
 name = "opal-runtime"
-version = "1.1.0"
+version = "1.2.0"
 dependencies = [
  "app-promotion-rpc",
  "cumulus-pallet-aura-ext",
@@ -6519,9 +6606,9 @@
  "pallet-unique",
  "pallet-utility",
  "pallet-xcm",
- "parachain-info",
  "parity-scale-codec",
  "polkadot-parachain-primitives",
+ "polkadot-runtime-common",
  "precompile-utils-macro",
  "scale-info",
  "serde",
@@ -6540,6 +6627,7 @@
  "sp-storage",
  "sp-transaction-pool",
  "sp-version",
+ "staging-parachain-info",
  "staging-xcm",
  "staging-xcm-builder",
  "staging-xcm-executor",
@@ -6570,10 +6658,16 @@
 checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 
 [[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
 name = "orchestra"
-version = "0.0.5"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "227585216d05ba65c7ab0a0450a3cf2cbd81a98862a54c4df8e14d5ac6adb015"
+checksum = "46d78e1deb2a8d54fc1f063a544130db4da31dfe4d5d3b493186424910222a76"
 dependencies = [
  "async-trait",
  "dyn-clonable",
@@ -6588,14 +6682,15 @@
 
 [[package]]
 name = "orchestra-proc-macro"
-version = "0.0.5"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2871aadd82a2c216ee68a69837a526dfe788ecbe74c4c5038a6acdbff6653066"
+checksum = "d035b1f968d91a826f2e34a9d6d02cb2af5aa7ca39ebd27922d850ab4b2dd2c6"
 dependencies = [
- "expander 0.0.6",
- "itertools 0.10.5",
+ "expander 2.0.0",
+ "indexmap 2.1.0",
+ "itertools 0.11.0",
  "petgraph",
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
@@ -6612,8 +6707,8 @@
 
 [[package]]
 name = "orml-tokens"
-version = "0.4.1-dev"
-source = "git+https://github.com/open-web3-stack/open-runtime-module-library?branch=polkadot-v1.1.0#b3694e631df7f1ca16b1973122937753fcdee9d4"
+version = "0.5.0-dev"
+source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=unique-polkadot-v1.3.0#6f36a9e79b75421ac56b259fd47d03db6c3e1603"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -6629,8 +6724,8 @@
 
 [[package]]
 name = "orml-traits"
-version = "0.4.1-dev"
-source = "git+https://github.com/open-web3-stack/open-runtime-module-library?branch=polkadot-v1.1.0#b3694e631df7f1ca16b1973122937753fcdee9d4"
+version = "0.5.0-dev"
+source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=unique-polkadot-v1.3.0#6f36a9e79b75421ac56b259fd47d03db6c3e1603"
 dependencies = [
  "frame-support",
  "impl-trait-for-tuples",
@@ -6649,8 +6744,8 @@
 
 [[package]]
 name = "orml-utilities"
-version = "0.4.1-dev"
-source = "git+https://github.com/open-web3-stack/open-runtime-module-library?branch=polkadot-v1.1.0#b3694e631df7f1ca16b1973122937753fcdee9d4"
+version = "0.5.0-dev"
+source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=unique-polkadot-v1.3.0#6f36a9e79b75421ac56b259fd47d03db6c3e1603"
 dependencies = [
  "frame-support",
  "parity-scale-codec",
@@ -6664,8 +6759,8 @@
 
 [[package]]
 name = "orml-vesting"
-version = "0.4.1-dev"
-source = "git+https://github.com/open-web3-stack/open-runtime-module-library?branch=polkadot-v1.1.0#b3694e631df7f1ca16b1973122937753fcdee9d4"
+version = "0.5.0-dev"
+source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=unique-polkadot-v1.3.0#6f36a9e79b75421ac56b259fd47d03db6c3e1603"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -6679,8 +6774,8 @@
 
 [[package]]
 name = "orml-xcm-support"
-version = "0.4.1-dev"
-source = "git+https://github.com/open-web3-stack/open-runtime-module-library?branch=polkadot-v1.1.0#b3694e631df7f1ca16b1973122937753fcdee9d4"
+version = "0.5.0-dev"
+source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=unique-polkadot-v1.3.0#6f36a9e79b75421ac56b259fd47d03db6c3e1603"
 dependencies = [
  "frame-support",
  "orml-traits",
@@ -6693,8 +6788,8 @@
 
 [[package]]
 name = "orml-xtokens"
-version = "0.4.1-dev"
-source = "git+https://github.com/open-web3-stack/open-runtime-module-library?branch=polkadot-v1.1.0#b3694e631df7f1ca16b1973122937753fcdee9d4"
+version = "0.5.0-dev"
+source = "git+https://github.com/uniquenetwork/open-runtime-module-library?branch=unique-polkadot-v1.3.0#6f36a9e79b75421ac56b259fd47d03db6c3e1603"
 dependencies = [
  "cumulus-primitives-core",
  "frame-support",
@@ -6758,9 +6853,26 @@
 ]
 
 [[package]]
+name = "pallet-asset-rate"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "740aebbcfefe8528f56ff8a339f810520a28df3ec159d016ef719aaa9f131af4"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-core",
+ "sp-runtime",
+ "sp-std",
+]
+
+[[package]]
 name = "pallet-aura"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04fbef67cf62445b7fd8e68241e6b71d9fb8c77abb3d52259eebf525a4cd5586"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -6776,8 +6888,9 @@
 
 [[package]]
 name = "pallet-authority-discovery"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fda272a66bbf1602579efcede67606ac43cda6d462ad551c527d8cadc871813d"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -6792,8 +6905,9 @@
 
 [[package]]
 name = "pallet-authorship"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d38eab59f7d15fe43c81fc3cd92f4c1f895ca6d0efb74fc2a6d6d7d3d34d413"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -6806,8 +6920,9 @@
 
 [[package]]
 name = "pallet-babe"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b12430ca4b79b27231acb1ff3f99d33d6503fbeba40bfc8380e42d59b6d52b0"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -6830,8 +6945,9 @@
 
 [[package]]
 name = "pallet-bags-list"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d49c4448e51a5c64d63a4263aebeb2dfb90dabb48746e178b337fb7f533d45f"
 dependencies = [
  "aquamarine",
  "docify",
@@ -6852,8 +6968,9 @@
 
 [[package]]
 name = "pallet-balances"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9de2915b425ae77d63ba25c194780599b7be25307454a138cfb316c16d001e68"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -6889,7 +7006,7 @@
 [[package]]
 name = "pallet-base-fee"
 version = "1.0.0"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "fp-evm",
  "frame-support",
@@ -6902,8 +7019,9 @@
 
 [[package]]
 name = "pallet-beefy"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8563fce9fdb0e557015c0b58ed7ea7d5c1a4a1ddb1d27bf56e040d6bbf5c79e9"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -6922,10 +7040,11 @@
 
 [[package]]
 name = "pallet-beefy-mmr"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee3ed75c348ba23064cea40dab623719ef348bfe67ea39f195f82e2e7a7d0115"
 dependencies = [
- "array-bytes",
+ "array-bytes 6.2.0",
  "binary-merkle-tree",
  "frame-support",
  "frame-system",
@@ -6947,8 +7066,9 @@
 
 [[package]]
 name = "pallet-bounties"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74c0fb83c88f217e5bfe07a69a6d8a6c32d01241159ab81705ba5d4c3e24aaab"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -6965,8 +7085,9 @@
 
 [[package]]
 name = "pallet-child-bounties"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2246ce705aee37f9b6ad818e3646910d31ef4191e1c234bff054a710ef8d8a38"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7010,8 +7131,9 @@
 
 [[package]]
 name = "pallet-collective"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dddb120b5ee520146617a8c49b4d4c980ba9188918d43085539bf78815e7ec1d"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7071,8 +7193,9 @@
 
 [[package]]
 name = "pallet-conviction-voting"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c8ff7512a377b708f71772e5169550cebc8f74bc8c26553015698eaa0975356"
 dependencies = [
  "assert_matches",
  "frame-benchmarking",
@@ -7088,8 +7211,9 @@
 
 [[package]]
 name = "pallet-democracy"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed9f24ad18db2eeae0f03ba1743a82aaf300e0bbd6cdcb1119b0da93eef3d77f"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7106,8 +7230,9 @@
 
 [[package]]
 name = "pallet-election-provider-multi-phase"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "481178ef558a9409d9c12fc01279b517e3a0a7797664e89761447dba3a182ce6"
 dependencies = [
  "frame-benchmarking",
  "frame-election-provider-support",
@@ -7124,13 +7249,14 @@
  "sp-npos-elections",
  "sp-runtime",
  "sp-std",
- "strum",
+ "strum 0.24.1",
 ]
 
 [[package]]
 name = "pallet-election-provider-support-benchmarking"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5ab6413ec88b64acf849a202795c67940dc3bcc846ce03bd0893b90e2119ecf"
 dependencies = [
  "frame-benchmarking",
  "frame-election-provider-support",
@@ -7143,8 +7269,9 @@
 
 [[package]]
 name = "pallet-elections-phragmen"
-version = "5.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "26.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "021da1d28b604b3654f895987dcb1ccb47d73102b31bc84c8f784bed261f01d8"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7163,7 +7290,7 @@
 [[package]]
 name = "pallet-ethereum"
 version = "4.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "ethereum",
  "ethereum-types",
@@ -7186,7 +7313,7 @@
 [[package]]
 name = "pallet-evm"
 version = "6.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "environmental",
  "evm",
@@ -7268,7 +7395,7 @@
 [[package]]
 name = "pallet-evm-precompile-simple"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.1.0#e99be6383ce0b0bc33768e479505cf4302dc0f8a"
+source = "git+https://github.com/uniquenetwork/unique-frontier?branch=unique-polkadot-v1.3.0#2b684850edc955bcd3c3943216e451364ff0afa3"
 dependencies = [
  "fp-evm",
  "ripemd",
@@ -7293,8 +7420,9 @@
 
 [[package]]
 name = "pallet-fast-unstake"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05634a197738c999a3032393916182fedccce13cb063fc330ee9bf810cd53b49"
 dependencies = [
  "docify",
  "frame-benchmarking",
@@ -7364,8 +7492,9 @@
 
 [[package]]
 name = "pallet-grandpa"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b87c7f4cd94a526054dfebf7a84fbcaf6385033defa246ad83e321e71f8c5a92"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7404,8 +7533,9 @@
 
 [[package]]
 name = "pallet-identity"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "735bf6c19d30299e2d448797170a67d41c6a8ba593fb3a71ce4e11d3b85c60e9"
 dependencies = [
  "enumflags2",
  "frame-benchmarking",
@@ -7420,8 +7550,9 @@
 
 [[package]]
 name = "pallet-im-online"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59eb1c68cc6b4700ad1d2a81ba847ff7b37406aa0326b7716825155d3f985762"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7440,8 +7571,9 @@
 
 [[package]]
 name = "pallet-indices"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0893ae7f2211010e92bf57fe31f18e2223a2f97f6d6393aa7192e283ec520beb"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7487,8 +7619,9 @@
 
 [[package]]
 name = "pallet-membership"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e1504034588eb733f8ce98b77757e9a7390662313aa133ef1e3b9fbb94359c7"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7504,8 +7637,9 @@
 
 [[package]]
 name = "pallet-message-queue"
-version = "7.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "28.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0776bf51d03bd746159063fa1357234feb85114273d40ef3aa3efba65d091eb4"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7523,8 +7657,9 @@
 
 [[package]]
 name = "pallet-mmr"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2b9789cac80b48e9427724d0b400f984fb844fc711fc2dd2d0cdccdedda7169"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7541,8 +7676,9 @@
 
 [[package]]
 name = "pallet-multisig"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea2785a0bfb1884a8283bf65010bb7189c8fce958ced9947a8c71c148ef199f"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7557,8 +7693,9 @@
 
 [[package]]
 name = "pallet-nis"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7aa7ec891b7f1801a405095a2ad2c70eef94d2abe86792eee54794de23cbd035"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7573,8 +7710,9 @@
 
 [[package]]
 name = "pallet-nomination-pools"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "22.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1896f33fff0c41934532fb492078d78b784f301ddd81e5041dd8e8279e652c49"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -7592,8 +7730,9 @@
 
 [[package]]
 name = "pallet-nomination-pools-benchmarking"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b27cbf4a47cc79862d254f16b38c68fd2dda087ce58e7c0021859d89718e865a"
 dependencies = [
  "frame-benchmarking",
  "frame-election-provider-support",
@@ -7612,8 +7751,9 @@
 
 [[package]]
 name = "pallet-nomination-pools-runtime-api"
-version = "1.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "20.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65c256cc530a19ff614f2af9b5c95ae9aa777a2bf1542aa455ae65e842f8c924"
 dependencies = [
  "pallet-nomination-pools",
  "parity-scale-codec",
@@ -7644,8 +7784,9 @@
 
 [[package]]
 name = "pallet-offences"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3fd14c02ed4b689652826aa93284aada5a2cf859df3cc34ad88b2fd410a8c50"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -7661,8 +7802,9 @@
 
 [[package]]
 name = "pallet-offences-benchmarking"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1b3ae77cfb16f0495372853d42a44e34ab7b183bd8996a8cee91715f783ff49"
 dependencies = [
  "frame-benchmarking",
  "frame-election-provider-support",
@@ -7685,8 +7827,9 @@
 
 [[package]]
 name = "pallet-preimage"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1ed40405c758b52375cfc75aac74f10ff9bb9480569e5cfca42682e2db6c387"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7702,8 +7845,9 @@
 
 [[package]]
 name = "pallet-proxy"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fbc0b550f5cbbad51f9daf795cc7046d40bbff256dae8d6072fd710ab40fd3a"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7717,8 +7861,9 @@
 
 [[package]]
 name = "pallet-ranked-collective"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8181da7fd6b9adf4f8641c5bcb156cd209e3226eea87ee9f9b1ac41f8e37c714"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7735,8 +7880,9 @@
 
 [[package]]
 name = "pallet-recovery"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "889fddd16cfdea09c2ae4dc8e9f67a1ec4b8ac680412cffb772fa572489ec687"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7750,8 +7896,9 @@
 
 [[package]]
 name = "pallet-referenda"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "592ff9873af379bf55e835072afd787cd6435204213ac484e86345b026f4ae4e"
 dependencies = [
  "assert_matches",
  "frame-benchmarking",
@@ -7789,8 +7936,9 @@
 
 [[package]]
 name = "pallet-scheduler"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "26.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3508a51d359c6640577feead9dc00667f38cec385baad77b636c61ff746ffe24"
 dependencies = [
  "docify",
  "frame-benchmarking",
@@ -7807,8 +7955,9 @@
 
 [[package]]
 name = "pallet-session"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "768a6fb5333efc2bd2a3538c1d6ffa4178398660d4e3be89f2eb82d4e9088ae6"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -7829,8 +7978,9 @@
 
 [[package]]
 name = "pallet-session-benchmarking"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5401cee669394e86a15851ace4ad60ef1b4d656f11ff22c83d8004051279ea59"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7846,8 +7996,9 @@
 
 [[package]]
 name = "pallet-society"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36959be2c7f810ba6b8ece8cfe2ee515774c1c776f1ed0bebf3b9e8068f6a435"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7864,8 +8015,9 @@
 
 [[package]]
 name = "pallet-staking"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bed335abd32d357dd9750dae7fb87b01dfd8fe69faadcb94a6e0e0a43057d923"
 dependencies = [
  "frame-benchmarking",
  "frame-election-provider-support",
@@ -7887,19 +8039,21 @@
 
 [[package]]
 name = "pallet-staking-reward-curve"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df8878e29f3d001ac1b1b714621f462e41a9d1fa8f385657f955e8a1ec0684d7"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "pallet-staking-reward-fn"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "16.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45b6f832653badb5f70bdfecc1ded64b02b8159b27f18515af03f8b80f1b023b"
 dependencies = [
  "log",
  "sp-arithmetic",
@@ -7907,8 +8061,9 @@
 
 [[package]]
 name = "pallet-staking-runtime-api"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "11.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773c0d24ad4da4b505e47b43e91c8c0af4e835f16104bc770732a4796c174748"
 dependencies = [
  "parity-scale-codec",
  "sp-api",
@@ -7916,8 +8071,9 @@
 
 [[package]]
 name = "pallet-state-trie-migration"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "26.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "550292d79f281fd1bfbbf2643f10cef3d67068075d46374295f2efe7f7113da0"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7950,9 +8106,11 @@
 
 [[package]]
 name = "pallet-sudo"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcec9f73ecb8d0439a13043a253a9fd90aa6bf5aece6470194bbfc7f79256d88"
 dependencies = [
+ "docify",
  "frame-benchmarking",
  "frame-support",
  "frame-system",
@@ -7966,7 +8124,7 @@
 [[package]]
 name = "pallet-template-transaction-payment"
 version = "3.0.0"
-source = "git+https://github.com/uniquenetwork/pallet-sponsoring?branch=polkadot-v1.1.0#2fbec92640f517e4812be7ed61ef7691af6e0bba"
+source = "git+https://github.com/uniquenetwork/pallet-sponsoring?branch=polkadot-v1.3.0#6071a67116a08ef81083337360de376b63c0ea1c"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -7997,9 +8155,11 @@
 
 [[package]]
 name = "pallet-timestamp"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b25ec8749cf3f481b5e5199be701bac0dea835851b83fc7c455192762711858d"
 dependencies = [
+ "docify",
  "frame-benchmarking",
  "frame-support",
  "frame-system",
@@ -8016,8 +8176,9 @@
 
 [[package]]
 name = "pallet-tips"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81b17cf8b964e5533f1f5ac1f087f3f69adfead754cb5dd25abe395ec1e7abc9"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -8035,8 +8196,9 @@
 
 [[package]]
 name = "pallet-transaction-payment"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87ef7ceaac786e41613731e3bc48284f1aa3ec260934abda2daed949de6e5ada"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -8051,8 +8213,9 @@
 
 [[package]]
 name = "pallet-transaction-payment-rpc"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "27.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99adb3915b29d04362648a4be9114de3bfe37c431f214b1ef96b71f358950d9d"
 dependencies = [
  "jsonrpsee",
  "pallet-transaction-payment-rpc-runtime-api",
@@ -8067,8 +8230,9 @@
 
 [[package]]
 name = "pallet-transaction-payment-rpc-runtime-api"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07d87fdc4028155367c6ea98143054a6c00b38bfd77ec08681e289e429e35505"
 dependencies = [
  "pallet-transaction-payment",
  "parity-scale-codec",
@@ -8079,9 +8243,11 @@
 
 [[package]]
 name = "pallet-treasury"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8dd462af11574485864023849e0622916b611dbc88111192fb39b1e6d7e666ba"
 dependencies = [
+ "docify",
  "frame-benchmarking",
  "frame-support",
  "frame-system",
@@ -8090,6 +8256,7 @@
  "parity-scale-codec",
  "scale-info",
  "serde",
+ "sp-core",
  "sp-runtime",
  "sp-std",
 ]
@@ -8123,8 +8290,9 @@
 
 [[package]]
 name = "pallet-utility"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85a8a6941da32837e4297e0d8abe0a5c94f348a119cccbf27b0f99ee01246c0e"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -8139,8 +8307,9 @@
 
 [[package]]
 name = "pallet-vesting"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd29411ef24eb6a856adf1bc33b37ead4835a25dafb1c4c8c95b13fa5247748f"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -8154,8 +8323,9 @@
 
 [[package]]
 name = "pallet-whitelist"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d37304829099cfec7d17df70cfe11ccf6cb7bd624eab80e8e79e895859454540"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -8169,8 +8339,9 @@
 
 [[package]]
 name = "pallet-xcm"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04d5e5404d9dadb39390949aadc2c641c16ce4cb0f47ed7a7ff584ab914c2984"
 dependencies = [
  "bounded-collections",
  "frame-benchmarking",
@@ -8190,8 +8361,9 @@
 
 [[package]]
 name = "pallet-xcm-benchmarks"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6bfdc94e39541b111db7d2c2a95a18a3c3bb42dd37c20b8705727e617ce00c9"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
@@ -8208,26 +8380,12 @@
 ]
 
 [[package]]
-name = "parachain-info"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
-dependencies = [
- "cumulus-primitives-core",
- "frame-support",
- "frame-system",
- "parity-scale-codec",
- "scale-info",
- "sp-runtime",
- "sp-std",
-]
-
-[[package]]
 name = "parity-db"
-version = "0.4.11"
+version = "0.4.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab512a34b3c2c5e465731cc7668edf79208bbe520be03484eeb05e63ed221735"
+checksum = "59e9ab494af9e6e813c72170f0d3c1de1500990d62c97cc05cc7576f91aa402f"
 dependencies = [
- "blake2",
+ "blake2 0.10.6",
  "crc32fast",
  "fs2",
  "hex",
@@ -8262,7 +8420,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
@@ -8282,9 +8440,9 @@
 
 [[package]]
 name = "parking"
-version = "2.1.1"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e52c774a4c39359c1d1c52e43f73dd91a75a614652c825408eec30c95a9b2067"
+checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
 
 [[package]]
 name = "parking_lot"
@@ -8304,7 +8462,7 @@
 checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
 dependencies = [
  "lock_api",
- "parking_lot_core 0.9.8",
+ "parking_lot_core 0.9.9",
 ]
 
 [[package]]
@@ -8323,13 +8481,13 @@
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.8"
+version = "0.9.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
+checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall 0.3.5",
+ "redox_syscall 0.4.1",
  "smallvec",
  "windows-targets 0.48.5",
 ]
@@ -8405,9 +8563,9 @@
 
 [[package]]
 name = "pest"
-version = "2.7.4"
+version = "2.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4"
+checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5"
 dependencies = [
  "memchr",
  "thiserror",
@@ -8416,9 +8574,9 @@
 
 [[package]]
 name = "pest_derive"
-version = "2.7.4"
+version = "2.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8"
+checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2"
 dependencies = [
  "pest",
  "pest_generator",
@@ -8426,22 +8584,22 @@
 
 [[package]]
 name = "pest_generator"
-version = "2.7.4"
+version = "2.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a"
+checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227"
 dependencies = [
  "pest",
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "pest_meta"
-version = "2.7.4"
+version = "2.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d"
+checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6"
 dependencies = [
  "once_cell",
  "pest",
@@ -8455,7 +8613,7 @@
 checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
 dependencies = [
  "fixedbitset",
- "indexmap 2.0.2",
+ "indexmap 2.1.0",
 ]
 
 [[package]]
@@ -8475,7 +8633,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -8535,14 +8693,15 @@
 
 [[package]]
 name = "platforms"
-version = "3.1.2"
+version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8"
+checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0"
 
 [[package]]
 name = "polkadot-approval-distribution"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aafcdaca311b3f8ea463548cc2f62289a2689d3198ea8cba2d100fab378fff3c"
 dependencies = [
  "futures",
  "futures-timer",
@@ -8559,8 +8718,9 @@
 
 [[package]]
 name = "polkadot-availability-bitfield-distribution"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "316fa25f773ac3f470578d2dc2ff73cefc2a01c9ea0a9a00767529184701792c"
 dependencies = [
  "always-assert",
  "futures",
@@ -8575,8 +8735,9 @@
 
 [[package]]
 name = "polkadot-availability-distribution"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "118ed63ece1ec1ccf240ab44d932a932ae778ece57a6fba34953b7c0b436f6b1"
 dependencies = [
  "derive_more",
  "fatality",
@@ -8598,9 +8759,11 @@
 
 [[package]]
 name = "polkadot-availability-recovery"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13245b9f37a4d409c47cf46f74d2601df82f1bf12678b1a792ad1aa5effebd13"
 dependencies = [
+ "async-trait",
  "fatality",
  "futures",
  "parity-scale-codec",
@@ -8619,15 +8782,16 @@
 
 [[package]]
 name = "polkadot-cli"
-version = "1.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd0d87ec2b375e4f353d9fc22fa8d405578e44f1f12a7ff74936a3997f69d62f"
 dependencies = [
  "clap",
  "frame-benchmarking-cli",
  "futures",
  "log",
  "polkadot-node-metrics",
- "polkadot-performance-test",
+ "polkadot-node-primitives",
  "polkadot-service",
  "sc-cli",
  "sc-executor",
@@ -8646,8 +8810,9 @@
 
 [[package]]
 name = "polkadot-collator-protocol"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f5ed0e739de576e41203ba99b9da1347998174a84fb5ea825f1a8e30e1dff88"
 dependencies = [
  "bitvec",
  "fatality",
@@ -8668,8 +8833,9 @@
 
 [[package]]
 name = "polkadot-core-primitives"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b08d1d6ca24e1b13f8069e015cfab794344212dd7436aadd61de8086a82664ef"
 dependencies = [
  "parity-scale-codec",
  "scale-info",
@@ -8680,8 +8846,9 @@
 
 [[package]]
 name = "polkadot-dispute-distribution"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffa05fec2897e38a2ec42df5f84110fbb170dbe549d5d1e454f635b141cb2aca"
 dependencies = [
  "derive_more",
  "fatality",
@@ -8705,8 +8872,9 @@
 
 [[package]]
 name = "polkadot-erasure-coding"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9714c537368095f1bc2e70c45fb8ae3347c19b344f8d5b4722cc781690a74924"
 dependencies = [
  "parity-scale-codec",
  "polkadot-node-primitives",
@@ -8719,8 +8887,9 @@
 
 [[package]]
 name = "polkadot-gossip-support"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9acc782f4c0efb0809cc325a49b50c498255a973dfc665e940043af20936d525"
 dependencies = [
  "futures",
  "futures-timer",
@@ -8740,8 +8909,9 @@
 
 [[package]]
 name = "polkadot-network-bridge"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7355e7f9cac8e5fe4899796e92aea2ea94678854dc44e21890a33d4c6c6ec3"
 dependencies = [
  "always-assert",
  "async-trait",
@@ -8763,8 +8933,9 @@
 
 [[package]]
 name = "polkadot-node-collation-generation"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bed91a561c9edfc5bd1d8e432cec8cecde63aaf12131cc19881d67e39be0fce"
 dependencies = [
  "futures",
  "parity-scale-codec",
@@ -8781,8 +8952,9 @@
 
 [[package]]
 name = "polkadot-node-core-approval-voting"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "976e5fcd0c10fbe37d120a9e4702324585e529498c56d03fd7b529f17644fe34"
 dependencies = [
  "bitvec",
  "derive_more",
@@ -8810,8 +8982,9 @@
 
 [[package]]
 name = "polkadot-node-core-av-store"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9d1018400db515cec0748e4c83d6010601d1784350dfd465386a7ee47699cd3"
 dependencies = [
  "bitvec",
  "futures",
@@ -8832,8 +9005,9 @@
 
 [[package]]
 name = "polkadot-node-core-backing"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "051940f4f7214dcc370077ead642052cda2c7316641ea9ff1f05624be2a272d2"
 dependencies = [
  "bitvec",
  "fatality",
@@ -8851,8 +9025,9 @@
 
 [[package]]
 name = "polkadot-node-core-bitfield-signing"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77cea47f010914b5e52f2f1eb96c058cb117045c5864c733236e7b24ea103d22"
 dependencies = [
  "futures",
  "polkadot-node-subsystem",
@@ -8866,8 +9041,9 @@
 
 [[package]]
 name = "polkadot-node-core-candidate-validation"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbb2306632d1ee08cc2f4d5945b4ec795fd79ce801ae03e79961c18877220ed2"
 dependencies = [
  "async-trait",
  "futures",
@@ -8887,8 +9063,9 @@
 
 [[package]]
 name = "polkadot-node-core-chain-api"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e8787fcec6e036d21421adf3db0295c142a878c482e0aba2e5aefcf050f10"
 dependencies = [
  "futures",
  "polkadot-node-metrics",
@@ -8902,8 +9079,9 @@
 
 [[package]]
 name = "polkadot-node-core-chain-selection"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8028469b10f5f1fa10ea9b08cb09bb53bcb55a25298e4154928d3aaf7d5d066a"
 dependencies = [
  "futures",
  "futures-timer",
@@ -8919,8 +9097,9 @@
 
 [[package]]
 name = "polkadot-node-core-dispute-coordinator"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "662387f0e7b23596326754796fbb6f52e32c3deb0c11f9ff341e23a0a7139608"
 dependencies = [
  "fatality",
  "futures",
@@ -8938,8 +9117,9 @@
 
 [[package]]
 name = "polkadot-node-core-parachains-inherent"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0f57ce13de845fe1441fa3ab3405dcb142d3dc0ea985c4e28efa35b97d07d0"
 dependencies = [
  "async-trait",
  "futures",
@@ -8955,8 +9135,9 @@
 
 [[package]]
 name = "polkadot-node-core-prospective-parachains"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a010a14312c5c5eec800397cc60cce10131d4a29cedf563ee639fc7b9b27ba1"
 dependencies = [
  "bitvec",
  "fatality",
@@ -8972,8 +9153,9 @@
 
 [[package]]
 name = "polkadot-node-core-provisioner"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8a67ac3aa0a0e89ff20d5eb761fca78c124848a2627e35343e824d78cc9fe91"
 dependencies = [
  "bitvec",
  "fatality",
@@ -8989,12 +9171,15 @@
 
 [[package]]
 name = "polkadot-node-core-pvf"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f58224dbfbd773947ff3fccc3318bda11909e8a0f7c36f7f1234c0c1f25a62a"
 dependencies = [
  "always-assert",
+ "cfg-if",
  "futures",
  "futures-timer",
+ "is_executable",
  "libc",
  "parity-scale-codec",
  "pin-project",
@@ -9009,7 +9194,6 @@
  "sp-core",
  "sp-maybe-compressed-blob",
  "sp-wasm-interface",
- "substrate-build-script-utils",
  "tempfile",
  "tokio",
  "tracing-gum",
@@ -9017,8 +9201,9 @@
 
 [[package]]
 name = "polkadot-node-core-pvf-checker"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7abe14484e66b365748bd4b2988cc2c68e03146bc399bdf8139f9eb5cf6c6cf0"
 dependencies = [
  "futures",
  "polkadot-node-primitives",
@@ -9033,9 +9218,11 @@
 
 [[package]]
 name = "polkadot-node-core-pvf-common"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94004d011a260b8efdf6ddf80ac815ba6ede84bb46e32d588161c1d860c5a65d"
 dependencies = [
+ "cfg-if",
  "cpu-time",
  "futures",
  "landlock",
@@ -9055,32 +9242,10 @@
 ]
 
 [[package]]
-name = "polkadot-node-core-pvf-prepare-worker"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
-dependencies = [
- "futures",
- "libc",
- "parity-scale-codec",
- "polkadot-node-core-pvf-common",
- "polkadot-parachain-primitives",
- "polkadot-primitives",
- "rayon",
- "sc-executor",
- "sc-executor-common",
- "sc-executor-wasmtime",
- "sp-io",
- "sp-maybe-compressed-blob",
- "sp-tracing",
- "tikv-jemalloc-ctl",
- "tokio",
- "tracing-gum",
-]
-
-[[package]]
 name = "polkadot-node-core-runtime-api"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dccc7a95fea3562bd3a47f22c0e4ddcb755114dc0477f3173db8d5ebf0d84f50"
 dependencies = [
  "futures",
  "polkadot-node-metrics",
@@ -9094,8 +9259,9 @@
 
 [[package]]
 name = "polkadot-node-jaeger"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2cfe6d4769181dce55b1b8fc53f0bd85bb4aa20473702fbce95a94abafa19379"
 dependencies = [
  "lazy_static",
  "log",
@@ -9112,8 +9278,9 @@
 
 [[package]]
 name = "polkadot-node-metrics"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c51a586fc3ef87c685588a650c18882b4cf069d8adc0d7d9bd2670749cb4e82b"
 dependencies = [
  "bs58 0.5.0",
  "futures",
@@ -9131,10 +9298,11 @@
 
 [[package]]
 name = "polkadot-node-network-protocol"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6de513655bf71400299cda1ccaebfa612fd3965e7ce5a9120b4ff37bfc80931"
 dependencies = [
- "async-channel",
+ "async-channel 1.9.0",
  "async-trait",
  "bitvec",
  "derive_more",
@@ -9148,15 +9316,16 @@
  "rand 0.8.5",
  "sc-authority-discovery",
  "sc-network",
- "strum",
+ "strum 0.24.1",
  "thiserror",
  "tracing-gum",
 ]
 
 [[package]]
 name = "polkadot-node-primitives"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e82ee5edac871310bd1ce16a035ad2fc901d6ddd69ea0bbabc7f0a70a02770a"
 dependencies = [
  "bounded-vec",
  "futures",
@@ -9177,8 +9346,9 @@
 
 [[package]]
 name = "polkadot-node-subsystem"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e89d3f964ebd57275c2fff4d3cc755d210698fedeac1a0a238c0eb31534c96d"
 dependencies = [
  "polkadot-node-jaeger",
  "polkadot-node-subsystem-types",
@@ -9187,8 +9357,9 @@
 
 [[package]]
 name = "polkadot-node-subsystem-types"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e1013b3bac6e9b76bbd71433c3eba36b5c0fa9306bfc473ec02e3a104e156d2"
 dependencies = [
  "async-trait",
  "derive_more",
@@ -9199,6 +9370,7 @@
  "polkadot-node-primitives",
  "polkadot-primitives",
  "polkadot-statement-table",
+ "sc-client-api",
  "sc-network",
  "sc-transaction-pool-api",
  "smallvec",
@@ -9211,8 +9383,9 @@
 
 [[package]]
 name = "polkadot-node-subsystem-util"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8134075bfee921305ff229412e9282a3351215bf049c6a403197cc795f919941"
 dependencies = [
  "async-trait",
  "derive_more",
@@ -9230,10 +9403,12 @@
  "polkadot-node-network-protocol",
  "polkadot-node-primitives",
  "polkadot-node-subsystem",
+ "polkadot-node-subsystem-types",
  "polkadot-overseer",
  "polkadot-primitives",
  "prioritized-metered-channel",
  "rand 0.8.5",
+ "sc-client-api",
  "schnellru",
  "sp-application-crypto",
  "sp-core",
@@ -9244,8 +9419,9 @@
 
 [[package]]
 name = "polkadot-overseer"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2f547e981cbd72357ba30952193844d30de5063e9d304c117c9b941f12b5f84"
 dependencies = [
  "async-trait",
  "futures",
@@ -9258,7 +9434,6 @@
  "polkadot-node-subsystem-types",
  "polkadot-primitives",
  "sc-client-api",
- "schnellru",
  "sp-api",
  "sp-core",
  "tikv-jemalloc-ctl",
@@ -9267,8 +9442,9 @@
 
 [[package]]
 name = "polkadot-parachain-primitives"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42265630c0c48e25d7ee5a9f4bdcafd003be65c0a44deeb6541620ca169fa519"
 dependencies = [
  "bounded-collections",
  "derive_more",
@@ -9283,27 +9459,10 @@
 ]
 
 [[package]]
-name = "polkadot-performance-test"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
-dependencies = [
- "env_logger 0.9.3",
- "log",
- "polkadot-erasure-coding",
- "polkadot-node-core-pvf-prepare-worker",
- "polkadot-node-primitives",
- "polkadot-primitives",
- "quote",
- "sc-executor-common",
- "sp-maybe-compressed-blob",
- "staging-kusama-runtime",
- "thiserror",
-]
-
-[[package]]
 name = "polkadot-primitives"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee4508ff6b035edc08c54bb61238500179963f6f1eb8266dce6a5625509124bc"
 dependencies = [
  "bitvec",
  "hex-literal",
@@ -9328,8 +9487,9 @@
 
 [[package]]
 name = "polkadot-rpc"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce0432643ea2e4923db1f0ba6c82305c53725e18c857e911c4d979e4f7aafae5"
 dependencies = [
  "jsonrpsee",
  "mmr-rpc",
@@ -9359,106 +9519,10 @@
 ]
 
 [[package]]
-name = "polkadot-runtime"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
-dependencies = [
- "bitvec",
- "frame-benchmarking",
- "frame-election-provider-support",
- "frame-executive",
- "frame-support",
- "frame-system",
- "frame-system-benchmarking",
- "frame-system-rpc-runtime-api",
- "frame-try-runtime",
- "hex-literal",
- "log",
- "pallet-authority-discovery",
- "pallet-authorship",
- "pallet-babe",
- "pallet-bags-list",
- "pallet-balances",
- "pallet-bounties",
- "pallet-child-bounties",
- "pallet-collective",
- "pallet-conviction-voting",
- "pallet-democracy",
- "pallet-election-provider-multi-phase",
- "pallet-election-provider-support-benchmarking",
- "pallet-elections-phragmen",
- "pallet-fast-unstake",
- "pallet-grandpa",
- "pallet-identity 4.0.0-dev (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0)",
- "pallet-im-online",
- "pallet-indices",
- "pallet-membership",
- "pallet-message-queue",
- "pallet-multisig",
- "pallet-nomination-pools",
- "pallet-nomination-pools-benchmarking",
- "pallet-nomination-pools-runtime-api",
- "pallet-offences",
- "pallet-offences-benchmarking",
- "pallet-preimage",
- "pallet-proxy",
- "pallet-referenda",
- "pallet-scheduler",
- "pallet-session",
- "pallet-session-benchmarking",
- "pallet-staking",
- "pallet-staking-reward-curve",
- "pallet-staking-runtime-api",
- "pallet-timestamp",
- "pallet-tips",
- "pallet-transaction-payment",
- "pallet-transaction-payment-rpc-runtime-api",
- "pallet-treasury",
- "pallet-utility",
- "pallet-vesting",
- "pallet-whitelist",
- "pallet-xcm",
- "pallet-xcm-benchmarks",
- "parity-scale-codec",
- "polkadot-primitives",
- "polkadot-runtime-common",
- "polkadot-runtime-constants",
- "polkadot-runtime-parachains",
- "rustc-hex",
- "scale-info",
- "serde",
- "serde_derive",
- "smallvec",
- "sp-api",
- "sp-arithmetic",
- "sp-authority-discovery",
- "sp-block-builder",
- "sp-consensus-babe",
- "sp-consensus-beefy",
- "sp-core",
- "sp-inherents",
- "sp-io",
- "sp-mmr-primitives",
- "sp-npos-elections",
- "sp-offchain",
- "sp-runtime",
- "sp-session",
- "sp-staking",
- "sp-std",
- "sp-storage",
- "sp-transaction-pool",
- "sp-version",
- "staging-xcm",
- "staging-xcm-builder",
- "staging-xcm-executor",
- "static_assertions",
- "substrate-wasm-builder",
-]
-
-[[package]]
 name = "polkadot-runtime-common"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a788f8ed8b33262c33f72d78e3416c5991e40d333178ae43000a92181ee44bca"
 dependencies = [
  "bitvec",
  "frame-benchmarking",
@@ -9468,6 +9532,7 @@
  "impl-trait-for-tuples",
  "libsecp256k1",
  "log",
+ "pallet-asset-rate",
  "pallet-authorship",
  "pallet-babe",
  "pallet-balances",
@@ -9480,6 +9545,7 @@
  "pallet-transaction-payment",
  "pallet-treasury",
  "pallet-vesting",
+ "pallet-xcm-benchmarks",
  "parity-scale-codec",
  "polkadot-primitives",
  "polkadot-runtime-parachains",
@@ -9498,27 +9564,16 @@
  "sp-staking",
  "sp-std",
  "staging-xcm",
+ "staging-xcm-builder",
+ "staging-xcm-executor",
  "static_assertions",
-]
-
-[[package]]
-name = "polkadot-runtime-constants"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
-dependencies = [
- "frame-support",
- "polkadot-primitives",
- "polkadot-runtime-common",
- "smallvec",
- "sp-core",
- "sp-runtime",
- "sp-weights",
 ]
 
 [[package]]
 name = "polkadot-runtime-metrics"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfe45b01d9d621174c9c0eef0871aeead5986393838206fe58df3ae414bcb8d2"
 dependencies = [
  "bs58 0.5.0",
  "frame-benchmarking",
@@ -9530,8 +9585,9 @@
 
 [[package]]
 name = "polkadot-runtime-parachains"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "936dbae8a7a88dba07da726d779126716e05364d8475ced1c313f32755050a02"
 dependencies = [
  "bitflags 1.3.2",
  "bitvec",
@@ -9551,6 +9607,7 @@
  "pallet-timestamp",
  "pallet-vesting",
  "parity-scale-codec",
+ "polkadot-core-primitives",
  "polkadot-parachain-primitives",
  "polkadot-primitives",
  "polkadot-runtime-metrics",
@@ -9576,8 +9633,9 @@
 
 [[package]]
 name = "polkadot-service"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afc65d44c4dd6a8be74194dcac66552dd4e79ee0bcc287349721925e8238177a"
 dependencies = [
  "async-trait",
  "frame-benchmarking",
@@ -9632,8 +9690,6 @@
  "polkadot-parachain-primitives",
  "polkadot-primitives",
  "polkadot-rpc",
- "polkadot-runtime",
- "polkadot-runtime-common",
  "polkadot-runtime-parachains",
  "polkadot-statement-distribution",
  "rococo-runtime",
@@ -9686,7 +9742,6 @@
  "sp-transaction-pool",
  "sp-version",
  "sp-weights",
- "staging-kusama-runtime",
  "substrate-prometheus-endpoint",
  "thiserror",
  "tracing-gum",
@@ -9695,8 +9750,9 @@
 
 [[package]]
 name = "polkadot-statement-distribution"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6992cb6e2ba744752f9f403cb5e0f70ac5431f39f9ea859a3978f22c79799cb"
 dependencies = [
  "arrayvec 0.7.4",
  "bitvec",
@@ -9719,8 +9775,9 @@
 
 [[package]]
 name = "polkadot-statement-table"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22b2a11cb8871f7e30a8f5e455c92d19a186065644ee00f9acda550ff89dacce"
 dependencies = [
  "parity-scale-codec",
  "polkadot-primitives",
@@ -9744,14 +9801,17 @@
 ]
 
 [[package]]
-name = "poly1305"
-version = "0.7.2"
+name = "polling"
+version = "3.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede"
+checksum = "e53b6af1f60f36f8c2ac2aad5459d75a5a9b4be1e8cdd40264f315d78193e531"
 dependencies = [
- "cpufeatures",
- "opaque-debug 0.3.0",
- "universal-hash 0.4.1",
+ "cfg-if",
+ "concurrent-queue",
+ "pin-project-lite 0.2.13",
+ "rustix 0.38.25",
+ "tracing",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -9791,9 +9851,15 @@
 
 [[package]]
 name = "portable-atomic"
-version = "1.4.3"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b"
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
 
 [[package]]
 name = "ppv-lite86"
@@ -9859,14 +9925,14 @@
 checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d"
 dependencies = [
  "proc-macro2",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "primitive-types"
-version = "0.12.1"
+version = "0.12.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66"
+checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2"
 dependencies = [
  "fixed-hash",
  "impl-codec",
@@ -9878,9 +9944,9 @@
 
 [[package]]
 name = "prioritized-metered-channel"
-version = "0.2.0"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "382698e48a268c832d0b181ed438374a6bb708a82a8ca273bb0f61c74cf209c4"
+checksum = "e99f0c89bd88f393aab44a4ab949351f7bc7e7e1179d11ecbfe50cbe4c47e342"
 dependencies = [
  "coarsetime",
  "crossbeam-queue",
@@ -9899,7 +9965,16 @@
 checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
 dependencies = [
  "once_cell",
- "toml_edit",
+ "toml_edit 0.19.15",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8"
+dependencies = [
+ "toml_edit 0.20.7",
 ]
 
 [[package]]
@@ -9927,27 +10002,21 @@
 ]
 
 [[package]]
-name = "proc-macro-hack"
-version = "0.5.20+deprecated"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
-
-[[package]]
 name = "proc-macro-warning"
-version = "0.4.2"
+version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e"
+checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.67"
+version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
+checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
 dependencies = [
  "unicode-ident",
 ]
@@ -9986,7 +10055,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -10054,7 +10123,7 @@
 
 [[package]]
 name = "quartz-runtime"
-version = "1.1.0"
+version = "1.2.0"
 dependencies = [
  "app-promotion-rpc",
  "cumulus-pallet-aura-ext",
@@ -10130,9 +10199,9 @@
  "pallet-unique",
  "pallet-utility",
  "pallet-xcm",
- "parachain-info",
  "parity-scale-codec",
  "polkadot-parachain-primitives",
+ "polkadot-runtime-common",
  "precompile-utils-macro",
  "scale-info",
  "serde",
@@ -10151,6 +10220,7 @@
  "sp-storage",
  "sp-transaction-pool",
  "sp-version",
+ "staging-parachain-info",
  "staging-xcm",
  "staging-xcm-builder",
  "staging-xcm-executor",
@@ -10203,9 +10273,9 @@
 
 [[package]]
 name = "quinn-proto"
-version = "0.9.5"
+version = "0.9.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c956be1b23f4261676aed05a0046e204e8a6836e50203902683a718af0797989"
+checksum = "94b0b33c13a79f669c85defaf4c275dc86a0c0372807d0ca3d78e0bb87274863"
 dependencies = [
  "bytes",
  "rand 0.8.5",
@@ -10216,7 +10286,7 @@
  "thiserror",
  "tinyvec",
  "tracing",
- "webpki 0.22.2",
+ "webpki 0.22.4",
 ]
 
 [[package]]
@@ -10293,7 +10363,17 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 dependencies = [
- "getrandom 0.2.10",
+ "getrandom 0.2.11",
+]
+
+[[package]]
+name = "rand_distr"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
+dependencies = [
+ "num-traits",
+ "rand 0.8.5",
 ]
 
 [[package]]
@@ -10384,13 +10464,22 @@
 ]
 
 [[package]]
+name = "redox_syscall"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
 name = "redox_users"
-version = "0.4.3"
+version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
+checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
 dependencies = [
- "getrandom 0.2.10",
- "redox_syscall 0.2.16",
+ "getrandom 0.2.11",
+ "libredox",
  "thiserror",
 ]
 
@@ -10424,7 +10513,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -10441,14 +10530,14 @@
 
 [[package]]
 name = "regex"
-version = "1.9.6"
+version = "1.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff"
+checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-automata 0.3.9",
- "regex-syntax 0.7.5",
+ "regex-automata 0.4.3",
+ "regex-syntax 0.8.2",
 ]
 
 [[package]]
@@ -10462,13 +10551,13 @@
 
 [[package]]
 name = "regex-automata"
-version = "0.3.9"
+version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9"
+checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-syntax 0.7.5",
+ "regex-syntax 0.8.2",
 ]
 
 [[package]]
@@ -10479,9 +10568,9 @@
 
 [[package]]
 name = "regex-syntax"
-version = "0.7.5"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
+checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
 
 [[package]]
 name = "resolv-conf"
@@ -10511,22 +10600,7 @@
 checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
 dependencies = [
  "hmac 0.12.1",
- "subtle",
-]
-
-[[package]]
-name = "ring"
-version = "0.1.0"
-source = "git+https://github.com/w3f/ring-proof?rev=0e948f3#0e948f3c28cbacecdd3020403c4841c0eb339213"
-dependencies = [
- "ark-ec",
- "ark-ff",
- "ark-poly",
- "ark-serialize",
- "ark-std",
- "common",
- "fflonk",
- "merlin 3.0.0",
+ "subtle 2.4.1",
 ]
 
 [[package]]
@@ -10539,12 +10613,26 @@
  "libc",
  "once_cell",
  "spin 0.5.2",
- "untrusted",
+ "untrusted 0.7.1",
  "web-sys",
  "winapi",
 ]
 
 [[package]]
+name = "ring"
+version = "0.17.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b"
+dependencies = [
+ "cc",
+ "getrandom 0.2.11",
+ "libc",
+ "spin 0.9.8",
+ "untrusted 0.9.0",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
 name = "ripemd"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -10587,8 +10675,9 @@
 
 [[package]]
 name = "rococo-runtime"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4198843a4ec01f56b58ee26e15df123593da562a07b838c66c4e519dbfc1922d"
 dependencies = [
  "binary-merkle-tree",
  "frame-benchmarking",
@@ -10600,6 +10689,7 @@
  "frame-try-runtime",
  "hex-literal",
  "log",
+ "pallet-asset-rate",
  "pallet-authority-discovery",
  "pallet-authorship",
  "pallet-babe",
@@ -10609,10 +10699,11 @@
  "pallet-bounties",
  "pallet-child-bounties",
  "pallet-collective",
+ "pallet-conviction-voting",
  "pallet-democracy",
  "pallet-elections-phragmen",
  "pallet-grandpa",
- "pallet-identity 4.0.0-dev (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0)",
+ "pallet-identity 25.0.0",
  "pallet-im-online",
  "pallet-indices",
  "pallet-membership",
@@ -10623,7 +10714,9 @@
  "pallet-offences",
  "pallet-preimage",
  "pallet-proxy",
+ "pallet-ranked-collective",
  "pallet-recovery",
+ "pallet-referenda",
  "pallet-scheduler",
  "pallet-session",
  "pallet-society",
@@ -10637,6 +10730,7 @@
  "pallet-treasury",
  "pallet-utility",
  "pallet-vesting",
+ "pallet-whitelist",
  "pallet-xcm",
  "pallet-xcm-benchmarks",
  "parity-scale-codec",
@@ -10650,11 +10744,13 @@
  "serde_derive",
  "smallvec",
  "sp-api",
+ "sp-arithmetic",
  "sp-authority-discovery",
  "sp-block-builder",
  "sp-consensus-babe",
  "sp-consensus-beefy",
  "sp-core",
+ "sp-genesis-builder",
  "sp-inherents",
  "sp-io",
  "sp-mmr-primitives",
@@ -10675,8 +10771,9 @@
 
 [[package]]
 name = "rococo-runtime-constants"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "272eaa4f1b4b5357d89d1f8f504cb5ee81a105bf7e5c295f053c6e521f2a199b"
 dependencies = [
  "frame-support",
  "polkadot-primitives",
@@ -10685,17 +10782,18 @@
  "sp-core",
  "sp-runtime",
  "sp-weights",
+ "staging-xcm",
 ]
 
 [[package]]
 name = "rpassword"
-version = "7.2.0"
+version = "7.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322"
+checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f"
 dependencies = [
  "libc",
  "rtoolbox",
- "winapi",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -10726,12 +10824,12 @@
 
 [[package]]
 name = "rtoolbox"
-version = "0.0.1"
+version = "0.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a"
+checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e"
 dependencies = [
  "libc",
- "winapi",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -10772,7 +10870,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
 dependencies = [
- "semver 1.0.19",
+ "semver 1.0.20",
 ]
 
 [[package]]
@@ -10786,9 +10884,9 @@
 
 [[package]]
 name = "rustix"
-version = "0.36.15"
+version = "0.36.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c37f1bd5ef1b5422177b7646cba67430579cfe2ace80f284fee876bca52ad941"
+checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed"
 dependencies = [
  "bitflags 1.3.2",
  "errno",
@@ -10800,9 +10898,9 @@
 
 [[package]]
 name = "rustix"
-version = "0.37.24"
+version = "0.37.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4279d76516df406a8bd37e7dff53fd37d1a093f997a3c34a5c21658c126db06d"
+checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2"
 dependencies = [
  "bitflags 1.3.2",
  "errno",
@@ -10814,14 +10912,14 @@
 
 [[package]]
 name = "rustix"
-version = "0.38.15"
+version = "0.38.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2f9da0cbd88f9f09e7814e388301c8414c51c62aa6ce1e4b5c551d49d96e531"
+checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
 dependencies = [
- "bitflags 2.4.0",
+ "bitflags 2.4.1",
  "errno",
  "libc",
- "linux-raw-sys 0.4.8",
+ "linux-raw-sys 0.4.11",
  "windows-sys 0.48.0",
 ]
 
@@ -10846,20 +10944,20 @@
 dependencies = [
  "log",
  "ring 0.16.20",
- "sct 0.7.0",
- "webpki 0.22.2",
+ "sct 0.7.1",
+ "webpki 0.22.4",
 ]
 
 [[package]]
 name = "rustls"
-version = "0.21.7"
+version = "0.21.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8"
+checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9"
 dependencies = [
  "log",
- "ring 0.16.20",
- "rustls-webpki 0.101.6",
- "sct 0.7.0",
+ "ring 0.17.5",
+ "rustls-webpki",
+ "sct 0.7.1",
 ]
 
 [[package]]
@@ -10876,31 +10974,21 @@
 
 [[package]]
 name = "rustls-pemfile"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
-dependencies = [
- "base64 0.21.4",
-]
-
-[[package]]
-name = "rustls-webpki"
-version = "0.100.3"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f6a5fc258f1c1276dfe3016516945546e2d5383911efc0fc4f1cdc5df3a4ae3"
+checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
 dependencies = [
- "ring 0.16.20",
- "untrusted",
+ "base64 0.21.5",
 ]
 
 [[package]]
 name = "rustls-webpki"
-version = "0.101.6"
+version = "0.101.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe"
+checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
 dependencies = [
- "ring 0.16.20",
- "untrusted",
+ "ring 0.17.5",
+ "untrusted 0.9.0",
 ]
 
 [[package]]
@@ -10957,8 +11045,9 @@
 
 [[package]]
 name = "sc-allocator"
-version = "4.1.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "20.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66b4c5976a9cff7fcf24c946276a62ea7837862b6f3bf9f8011f08faf4f08474"
 dependencies = [
  "log",
  "sp-core",
@@ -10968,8 +11057,9 @@
 
 [[package]]
 name = "sc-authority-discovery"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb7e0e8a4ea5304b65d49c0085a458ed2e43394f95457689875d3e0c6e118dee"
 dependencies = [
  "async-trait",
  "futures",
@@ -10996,8 +11086,9 @@
 
 [[package]]
 name = "sc-basic-authorship"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0aa6c85e3e0b5af9cab7078166d8c4575b7b9edac0ade6be1aadee828420104"
 dependencies = [
  "futures",
  "futures-timer",
@@ -11019,8 +11110,9 @@
 
 [[package]]
 name = "sc-block-builder"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d3999b9b758c09a6c1155e481b683ee87712f071cc5a0679f9ee4906a14a404"
 dependencies = [
  "parity-scale-codec",
  "sc-client-api",
@@ -11034,8 +11126,9 @@
 
 [[package]]
 name = "sc-chain-spec"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7e711ea9870d3fb8e2a3ea5b601a9e20c63d0d2f457f40146407721e246a77"
 dependencies = [
  "memmap2",
  "sc-chain-spec-derive",
@@ -11053,21 +11146,23 @@
 
 [[package]]
 name = "sc-chain-spec-derive"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f25158f791eb48715da9322375598b541cadd1f193674e8a4d77c79ffa3d95d"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "sc-cli"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22c61058223f80c1f961b03f7737529609a3283eef91129e971a1966101c18ea"
 dependencies = [
- "array-bytes",
+ "array-bytes 6.2.0",
  "chrono",
  "clap",
  "fdlimit",
@@ -11082,6 +11177,7 @@
  "sc-client-api",
  "sc-client-db",
  "sc-keystore",
+ "sc-mixnet",
  "sc-network",
  "sc-service",
  "sc-telemetry",
@@ -11103,8 +11199,9 @@
 
 [[package]]
 name = "sc-client-api"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7d32101f415f4d7ddbe8b5de1c1387a78d6dce070e26407ec605fe9f3fc9e23"
 dependencies = [
  "fnv",
  "futures",
@@ -11124,13 +11221,15 @@
  "sp-state-machine",
  "sp-statement-store",
  "sp-storage",
+ "sp-trie",
  "substrate-prometheus-endpoint",
 ]
 
 [[package]]
 name = "sc-client-db"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4ced79f609a44782874d856cf39d256838957195ef34f4fb8ced90bf4b725d0"
 dependencies = [
  "hash-db 0.16.0",
  "kvdb",
@@ -11155,8 +11254,9 @@
 
 [[package]]
 name = "sc-consensus"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86e4100cc8fb3876708e1ec5a7c63af3baa75febd5051beb9ddd1e4835fdfc27"
 dependencies = [
  "async-trait",
  "futures",
@@ -11180,8 +11280,9 @@
 
 [[package]]
 name = "sc-consensus-aura"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e3e282836a7deeeb71d965a0942828f81ae2b03fd67515b733d5f33dd5da855"
 dependencies = [
  "async-trait",
  "futures",
@@ -11209,8 +11310,9 @@
 
 [[package]]
 name = "sc-consensus-babe"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a48ef5eaf7bffc647dfdfd42c7c02a929d89410b065beeb80753fd94f5fe70d"
 dependencies = [
  "async-trait",
  "fork-tree",
@@ -11227,7 +11329,6 @@
  "sc-consensus-slots",
  "sc-telemetry",
  "sc-transaction-pool-api",
- "scale-info",
  "sp-api",
  "sp-application-crypto",
  "sp-block-builder",
@@ -11245,8 +11346,9 @@
 
 [[package]]
 name = "sc-consensus-babe-rpc"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a78a543d8d2e8d9a6a8b60f16ac12e6fbeffbc2322ef8fa139f733ce53ccaa8"
 dependencies = [
  "futures",
  "jsonrpsee",
@@ -11267,11 +11369,12 @@
 
 [[package]]
 name = "sc-consensus-beefy"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3709a96723feaeb7a7ca0d3f7995d084029f8effeeb09d45975a8aa3ba1a63b"
 dependencies = [
- "array-bytes",
- "async-channel",
+ "array-bytes 6.2.0",
+ "async-channel 1.9.0",
  "async-trait",
  "fnv",
  "futures",
@@ -11301,8 +11404,9 @@
 
 [[package]]
 name = "sc-consensus-beefy-rpc"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1699fe1791dd985a5dd6075c84136027eb3e2ccff46d3e5273fdbd5b246f763"
 dependencies = [
  "futures",
  "jsonrpsee",
@@ -11320,8 +11424,9 @@
 
 [[package]]
 name = "sc-consensus-epochs"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5eafc0534bb118f614fc50fe066e423dbecfedf816cd9c43e0b492e30c1782c8"
 dependencies = [
  "fork-tree",
  "parity-scale-codec",
@@ -11333,11 +11438,12 @@
 
 [[package]]
 name = "sc-consensus-grandpa"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30cbc5db21ea2c4ba65b23315e73e69e8155630fb47c84b93d40b0e759c9d86d"
 dependencies = [
- "ahash 0.8.3",
- "array-bytes",
+ "ahash 0.8.6",
+ "array-bytes 6.2.0",
  "async-trait",
  "dyn-clone",
  "finality-grandpa",
@@ -11374,8 +11480,9 @@
 
 [[package]]
 name = "sc-consensus-grandpa-rpc"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3c545dac29d5dd002170e063ca0725be95ef653be135d251f91dbe053f63173"
 dependencies = [
  "finality-grandpa",
  "futures",
@@ -11394,8 +11501,9 @@
 
 [[package]]
 name = "sc-consensus-manual-seal"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc7577e49019ece17432c51ddbd4f6b02829b1f784a72b7064855ad70dc08b3f"
 dependencies = [
  "assert_matches",
  "async-trait",
@@ -11429,8 +11537,9 @@
 
 [[package]]
 name = "sc-consensus-slots"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2059681962e33394682627e7bd7245b5094236594f5c97c4c96988d901bda534"
 dependencies = [
  "async-trait",
  "futures",
@@ -11452,8 +11561,9 @@
 
 [[package]]
 name = "sc-executor"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225f2ad733bc7234a6638d5203624194824b2f78ab631bc911223f536a66b9c8"
 dependencies = [
  "parity-scale-codec",
  "parking_lot 0.12.1",
@@ -11474,8 +11584,9 @@
 
 [[package]]
 name = "sc-executor-common"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "169c1cfe81ba0e0d44ab4ada1600e30b6a9de588c792db73e32a854a6e3e1a87"
 dependencies = [
  "sc-allocator",
  "sp-maybe-compressed-blob",
@@ -11486,14 +11597,16 @@
 
 [[package]]
 name = "sc-executor-wasmtime"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9167d733e928c528273be63b905ec750cfda85d740453071463da69f7d633bc"
 dependencies = [
  "anyhow",
  "cfg-if",
  "libc",
  "log",
- "rustix 0.36.15",
+ "parking_lot 0.12.1",
+ "rustix 0.36.17",
  "sc-allocator",
  "sc-executor-common",
  "sp-runtime-interface",
@@ -11503,8 +11616,9 @@
 
 [[package]]
 name = "sc-informant"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7189a0b95fe5d79895a107c6c057bc9351cd9c867552200815199cde25bcdb9d"
 dependencies = [
  "ansi_term",
  "futures",
@@ -11519,10 +11633,11 @@
 
 [[package]]
 name = "sc-keystore"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "22.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abecdf9778fccc254c0b5e227ea8b90fd59247044a30ad293a068b180427d244"
 dependencies = [
- "array-bytes",
+ "array-bytes 6.2.0",
  "parking_lot 0.12.1",
  "serde_json",
  "sp-application-crypto",
@@ -11532,12 +11647,42 @@
 ]
 
 [[package]]
+name = "sc-mixnet"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d53ea71ec60601c18d6adcaf7a62698fc2e886c16dc8fdf8d61b3b76244dea38"
+dependencies = [
+ "array-bytes 4.2.0",
+ "arrayvec 0.7.4",
+ "blake2 0.10.6",
+ "futures",
+ "futures-timer",
+ "libp2p-identity",
+ "log",
+ "mixnet",
+ "multiaddr",
+ "parity-scale-codec",
+ "parking_lot 0.12.1",
+ "sc-client-api",
+ "sc-network",
+ "sc-transaction-pool-api",
+ "sp-api",
+ "sp-consensus",
+ "sp-core",
+ "sp-keystore",
+ "sp-mixnet",
+ "sp-runtime",
+ "thiserror",
+]
+
+[[package]]
 name = "sc-network"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01f519592a971199c486d412dbf38ba54096857080bf4b9d29c9ffabcfee3745"
 dependencies = [
- "array-bytes",
- "async-channel",
+ "array-bytes 6.2.0",
+ "async-channel 1.9.0",
  "async-trait",
  "asynchronous-codec",
  "bytes",
@@ -11574,10 +11719,11 @@
 
 [[package]]
 name = "sc-network-bitswap"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fe63a55e03d8bc796ff1e94e7fb62a62acfd7a80a47865a97b55c13371c3e05"
 dependencies = [
- "async-channel",
+ "async-channel 1.9.0",
  "cid",
  "futures",
  "libp2p-identity",
@@ -11594,8 +11740,9 @@
 
 [[package]]
 name = "sc-network-common"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d236686d15275e4aa49ca929a06fb6fac28aa70e35ee185b981036c149f9e9d"
 dependencies = [
  "async-trait",
  "bitflags 1.3.2",
@@ -11611,10 +11758,11 @@
 
 [[package]]
 name = "sc-network-gossip"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b884a9f7cd348c4c1899c0bbf95237e39dffba4baec48d4b98c1046f6bb04fa5"
 dependencies = [
- "ahash 0.8.3",
+ "ahash 0.8.6",
  "futures",
  "futures-timer",
  "libp2p",
@@ -11629,11 +11777,12 @@
 
 [[package]]
 name = "sc-network-light"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aac888fd720ef8bb2ff7d2b7f7b2e54d17bb85a417cf1e1b6f0f64f7e644936d"
 dependencies = [
- "array-bytes",
- "async-channel",
+ "array-bytes 6.2.0",
+ "async-channel 1.9.0",
  "futures",
  "libp2p-identity",
  "log",
@@ -11650,11 +11799,12 @@
 
 [[package]]
 name = "sc-network-sync"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10c697aa8f52cf194b9f00113a7d0d3ce5d1456bedd6169a9caae10737f02907"
 dependencies = [
- "array-bytes",
- "async-channel",
+ "array-bytes 6.2.0",
+ "async-channel 1.9.0",
  "async-trait",
  "fork-tree",
  "futures",
@@ -11680,14 +11830,16 @@
  "sp-runtime",
  "substrate-prometheus-endpoint",
  "thiserror",
+ "tokio-stream",
 ]
 
 [[package]]
 name = "sc-network-transactions"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb7c9bfc7b58ce229d1512158b8f13dc849ec24857d1c29a41a867fb8afb5c09"
 dependencies = [
- "array-bytes",
+ "array-bytes 6.2.0",
  "futures",
  "libp2p",
  "log",
@@ -11702,10 +11854,11 @@
 
 [[package]]
 name = "sc-offchain"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "26.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47950facab8dedf71c39667ccce8834252944e8f091f3a3bcdfc0b4503573da4"
 dependencies = [
- "array-bytes",
+ "array-bytes 6.2.0",
  "bytes",
  "fnv",
  "futures",
@@ -11736,8 +11889,9 @@
 
 [[package]]
 name = "sc-proposer-metrics"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "221845dce4e7adb57eca5f73318699b377cff29aef92a586e71aa5cef62f879b"
 dependencies = [
  "log",
  "substrate-prometheus-endpoint",
@@ -11745,8 +11899,9 @@
 
 [[package]]
 name = "sc-rpc"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "26.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb277280b6b3519e4a2e693b75d4ca516ebb4a928162e6a1791b217b2be60c9f"
 dependencies = [
  "futures",
  "jsonrpsee",
@@ -11756,6 +11911,7 @@
  "sc-block-builder",
  "sc-chain-spec",
  "sc-client-api",
+ "sc-mixnet",
  "sc-rpc-api",
  "sc-tracing",
  "sc-transaction-pool-api",
@@ -11776,12 +11932,14 @@
 
 [[package]]
 name = "sc-rpc-api"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "def499ac717db8442fe18543e52330d5f105027b666df73c0b38e81e9105078b"
 dependencies = [
  "jsonrpsee",
  "parity-scale-codec",
  "sc-chain-spec",
+ "sc-mixnet",
  "sc-transaction-pool-api",
  "scale-info",
  "serde",
@@ -11795,8 +11953,9 @@
 
 [[package]]
 name = "sc-rpc-server"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e8083e1b026dcf397f8c1122b3fba6cc744c6962996df6a30e0fb75223f7637"
 dependencies = [
  "http",
  "jsonrpsee",
@@ -11810,10 +11969,11 @@
 
 [[package]]
 name = "sc-rpc-spec-v2"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "198ea9287111b4060ce1d70dce99804b99d1a92b5fb23a79d94bf0cb460ca3ce"
 dependencies = [
- "array-bytes",
+ "array-bytes 6.2.0",
  "futures",
  "futures-util",
  "hex",
@@ -11838,8 +11998,9 @@
 
 [[package]]
 name = "sc-service"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3623ae5bd7b089da9796a3f1edd974c94f34dd4b4b527146662ef409ae9cd38c"
 dependencies = [
  "async-trait",
  "directories",
@@ -11902,8 +12063,9 @@
 
 [[package]]
 name = "sc-state-db"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3635fe572adfe796886e18910c8b94f7ce67f9ae3e2c161176e122ddf0baa7e4"
 dependencies = [
  "log",
  "parity-scale-codec",
@@ -11913,8 +12075,9 @@
 
 [[package]]
 name = "sc-storage-monitor"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f9acfc934aa5b0185e861ce81245685086c7231fcb2b582da4afc4d0bd62a98"
 dependencies = [
  "clap",
  "fs4",
@@ -11927,8 +12090,9 @@
 
 [[package]]
 name = "sc-sync-state-rpc"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe1efc0811813b73b9bb6eccc630ccd43d13b4306255a41ef55b9304d32e64c2"
 dependencies = [
  "jsonrpsee",
  "parity-scale-codec",
@@ -11946,8 +12110,9 @@
 
 [[package]]
 name = "sc-sysinfo"
-version = "6.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60967710b85e650652832df73915b64c315f7b437e53c4635bd26106d6d05c21"
 dependencies = [
  "futures",
  "libc",
@@ -11965,8 +12130,9 @@
 
 [[package]]
 name = "sc-telemetry"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "12.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28e214e4d46cac02321bc3dc6fd72f019ac10819d1ac8f24f6935a4ae74ef273"
 dependencies = [
  "chrono",
  "futures",
@@ -11984,8 +12150,9 @@
 
 [[package]]
 name = "sc-tracing"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83bcd745ea216ba0c0a344cff2c41b12e27846d5fca4b28f56ff77e1d3ff3634"
 dependencies = [
  "ansi_term",
  "atty",
@@ -12013,19 +12180,21 @@
 
 [[package]]
 name = "sc-tracing-proc-macro"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c4ae9e4f957d7274ac6b59d667b66262caf6482dbb1b63f1c370528626b1272"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "sc-transaction-pool"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f6db45a057a619670e07deefb4e69aab83386f076363db424907da2b2e82590"
 dependencies = [
  "async-trait",
  "futures",
@@ -12050,8 +12219,9 @@
 
 [[package]]
 name = "sc-transaction-pool-api"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1491607f296bb8cce09a5eb3a03320c60ad52bb8120127b26f69c32bcaccd8f2"
 dependencies = [
  "async-trait",
  "futures",
@@ -12066,10 +12236,11 @@
 
 [[package]]
 name = "sc-utils"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "11.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81a4769c82dde62b9243dcc166be52e0c5d2d61cf2599923271118d9c8b997b1"
 dependencies = [
- "async-channel",
+ "async-channel 1.9.0",
  "futures",
  "futures-timer",
  "lazy_static",
@@ -12081,9 +12252,9 @@
 
 [[package]]
 name = "scale-info"
-version = "2.9.0"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782"
+checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60"
 dependencies = [
  "bitvec",
  "cfg-if",
@@ -12095,11 +12266,11 @@
 
 [[package]]
 name = "scale-info-derive"
-version = "2.9.0"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "912e55f6d20e0e80d63733872b40e1227c0bce1e1ab81ba67d696339bfd7fd29"
+checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
@@ -12120,7 +12291,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d"
 dependencies = [
- "ahash 0.8.3",
+ "ahash 0.8.6",
  "cfg-if",
  "hashbrown 0.13.2",
 ]
@@ -12139,7 +12310,7 @@
  "rand 0.7.3",
  "rand_core 0.5.1",
  "sha2 0.8.2",
- "subtle",
+ "subtle 2.4.1",
  "zeroize",
 ]
 
@@ -12178,17 +12349,17 @@
 checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce"
 dependencies = [
  "ring 0.16.20",
- "untrusted",
+ "untrusted 0.7.1",
 ]
 
 [[package]]
 name = "sct"
-version = "0.7.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
+checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
 dependencies = [
- "ring 0.16.20",
- "untrusted",
+ "ring 0.17.5",
+ "untrusted 0.9.0",
 ]
 
 [[package]]
@@ -12213,7 +12384,7 @@
  "der 0.6.1",
  "generic-array 0.14.7",
  "pkcs8 0.9.0",
- "subtle",
+ "subtle 2.4.1",
  "zeroize",
 ]
 
@@ -12227,7 +12398,7 @@
  "der 0.7.8",
  "generic-array 0.14.7",
  "pkcs8 0.10.2",
- "subtle",
+ "subtle 2.4.1",
  "zeroize",
 ]
 
@@ -12292,9 +12463,9 @@
 
 [[package]]
 name = "semver"
-version = "1.0.19"
+version = "1.0.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0"
+checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
 dependencies = [
  "serde",
 ]
@@ -12307,29 +12478,29 @@
 
 [[package]]
 name = "serde"
-version = "1.0.188"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
+checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.188"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
+checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.107"
+version = "1.0.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
+checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
 dependencies = [
  "itoa",
  "ryu",
@@ -12338,9 +12509,9 @@
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.3"
+version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
+checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80"
 dependencies = [
  "serde",
 ]
@@ -12436,9 +12607,9 @@
 
 [[package]]
 name = "sharded-slab"
-version = "0.1.6"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1b21f559e07218024e7e9f90f96f601825397de0e25420135f7f952453fed0b"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
 dependencies = [
  "lazy_static",
 ]
@@ -12448,16 +12619,6 @@
 version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380"
-
-[[package]]
-name = "signal-hook"
-version = "0.3.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
-dependencies = [
- "libc",
- "signal-hook-registry",
-]
 
 [[package]]
 name = "signal-hook-registry"
@@ -12480,9 +12641,9 @@
 
 [[package]]
 name = "signature"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
 dependencies = [
  "digest 0.10.7",
  "rand_core 0.6.4",
@@ -12524,8 +12685,9 @@
 
 [[package]]
 name = "slot-range-helper"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e902c6b7e8f86718aee7989d6c8ea851d9772cb54a3389f2d729d8df41167ec"
 dependencies = [
  "enumn",
  "parity-scale-codec",
@@ -12545,9 +12707,9 @@
 
 [[package]]
 name = "smallvec"
-version = "1.11.1"
+version = "1.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
+checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
 
 [[package]]
 name = "smol"
@@ -12555,15 +12717,15 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1"
 dependencies = [
- "async-channel",
+ "async-channel 1.9.0",
  "async-executor",
  "async-fs",
- "async-io",
- "async-lock",
+ "async-io 1.13.0",
+ "async-lock 2.8.0",
  "async-net",
  "async-process",
  "blocking",
- "futures-lite",
+ "futures-lite 1.13.0",
 ]
 
 [[package]]
@@ -12573,22 +12735,22 @@
 checksum = "c0bb30cf57b7b5f6109ce17c3164445e2d6f270af2cb48f6e4d31c2967c9a9f5"
 dependencies = [
  "arrayvec 0.7.4",
- "async-lock",
+ "async-lock 2.8.0",
  "atomic-take",
- "base64 0.21.4",
+ "base64 0.21.5",
  "bip39",
  "blake2-rfc",
  "bs58 0.5.0",
- "chacha20 0.9.1",
+ "chacha20",
  "crossbeam-queue",
  "derive_more",
  "ed25519-zebra 4.0.3",
  "either",
- "event-listener",
+ "event-listener 2.5.3",
  "fnv",
- "futures-lite",
+ "futures-lite 1.13.0",
  "futures-util",
- "hashbrown 0.14.1",
+ "hashbrown 0.14.2",
  "hex",
  "hmac 0.12.1",
  "itertools 0.11.0",
@@ -12601,7 +12763,7 @@
  "num-traits",
  "pbkdf2 0.12.2",
  "pin-project",
- "poly1305 0.8.0",
+ "poly1305",
  "rand 0.8.5",
  "rand_chacha 0.3.1",
  "ruzstd",
@@ -12626,18 +12788,18 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "256b5bad1d6b49045e95fe87492ce73d5af81545d8b4d8318a872d2007024c33"
 dependencies = [
- "async-channel",
- "async-lock",
- "base64 0.21.4",
+ "async-channel 1.9.0",
+ "async-lock 2.8.0",
+ "base64 0.21.5",
  "blake2-rfc",
  "derive_more",
  "either",
- "event-listener",
+ "event-listener 2.5.3",
  "fnv",
  "futures-channel",
- "futures-lite",
+ "futures-lite 1.13.0",
  "futures-util",
- "hashbrown 0.14.1",
+ "hashbrown 0.14.2",
  "hex",
  "itertools 0.11.0",
  "log",
@@ -12664,26 +12826,26 @@
 
 [[package]]
 name = "snow"
-version = "0.9.3"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c9d1425eb528a21de2755c75af4c9b5d57f50a0d4c3b7f1828a4cd03f8ba155"
+checksum = "58021967fd0a5eeeb23b08df6cc244a4d4a5b4aec1d27c9e02fad1a58b4cd74e"
 dependencies = [
- "aes-gcm 0.9.4",
- "blake2",
+ "aes-gcm 0.10.3",
+ "blake2 0.10.6",
  "chacha20poly1305",
  "curve25519-dalek 4.1.1",
  "rand_core 0.6.4",
- "ring 0.16.20",
+ "ring 0.17.5",
  "rustc_version",
  "sha2 0.10.8",
- "subtle",
+ "subtle 2.4.1",
 ]
 
 [[package]]
 name = "socket2"
-version = "0.4.9"
+version = "0.4.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
+checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
 dependencies = [
  "libc",
  "winapi",
@@ -12691,9 +12853,9 @@
 
 [[package]]
 name = "socket2"
-version = "0.5.4"
+version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
 dependencies = [
  "libc",
  "windows-sys 0.48.0",
@@ -12718,8 +12880,9 @@
 
 [[package]]
 name = "sp-api"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f582f92ce47c86e4ffffe81fdd5120fea7c850dc0800653a7fa203bcc1532335"
 dependencies = [
  "hash-db 0.16.0",
  "log",
@@ -12739,22 +12902,24 @@
 
 [[package]]
 name = "sp-api-proc-macro"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "12.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a896941b2d27365a6f937ebce11e36d55132dc32104f6a48b4cd765b55efd252"
 dependencies = [
  "Inflector",
- "blake2",
+ "blake2 0.10.6",
  "expander 2.0.0",
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "sp-application-crypto"
-version = "23.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "27.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a93da025616ab59639f8e378df579c5aaa2c8b9999f328a0239156a57c991b53"
 dependencies = [
  "parity-scale-codec",
  "scale-info",
@@ -12766,8 +12931,9 @@
 
 [[package]]
 name = "sp-arithmetic"
-version = "16.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "20.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f80b5c16afb61dde1037a469d570adcc686440036429e50abe2301ba9d61aad5"
 dependencies = [
  "integer-sqrt",
  "num-traits",
@@ -12780,8 +12946,9 @@
 
 [[package]]
 name = "sp-authority-discovery"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e204d85bad6f02a5ae8fbba83c365e20459e979fd69db5575ba4b3ea1025ab3c"
 dependencies = [
  "parity-scale-codec",
  "scale-info",
@@ -12793,8 +12960,9 @@
 
 [[package]]
 name = "sp-block-builder"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6cd16df3d1cdad862d3e764f10f7675876b011e032907423fdfa377ae2ec8575"
 dependencies = [
  "sp-api",
  "sp-inherents",
@@ -12804,8 +12972,9 @@
 
 [[package]]
 name = "sp-blockchain"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4932b97cde61874f395bab9b02443e3bd2046943abb280b63f83da9d0b623ea7"
 dependencies = [
  "futures",
  "log",
@@ -12822,8 +12991,9 @@
 
 [[package]]
 name = "sp-consensus"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c5d7170fb7cfb18024ef7eeb40d272d22b9c3587d85cde2d091e8463b397f06"
 dependencies = [
  "async-trait",
  "futures",
@@ -12837,8 +13007,9 @@
 
 [[package]]
 name = "sp-consensus-aura"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "643a7c486a645f398d219d1fbcc8a416cad5018164a212fefde5c2ef00a182e4"
 dependencies = [
  "async-trait",
  "parity-scale-codec",
@@ -12854,8 +13025,9 @@
 
 [[package]]
 name = "sp-consensus-babe"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "268f9b2e36d4e136c09ad87876cdcfd7ff734cb5917f333fefebff248f95a24f"
 dependencies = [
  "async-trait",
  "parity-scale-codec",
@@ -12873,8 +13045,9 @@
 
 [[package]]
 name = "sp-consensus-beefy"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90e18fe984ea745727e645c43d6a955bc471b3bcd36aa8d260c3bd0deeada0c5"
 dependencies = [
  "lazy_static",
  "parity-scale-codec",
@@ -12887,13 +13060,14 @@
  "sp-mmr-primitives",
  "sp-runtime",
  "sp-std",
- "strum",
+ "strum 0.24.1",
 ]
 
 [[package]]
 name = "sp-consensus-grandpa"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28bbee685900110419913f281ce0f29457fbc17418f00d15f0212c8043aba167"
 dependencies = [
  "finality-grandpa",
  "log",
@@ -12910,8 +13084,9 @@
 
 [[package]]
 name = "sp-consensus-slots"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "895b0c176d4eead833ddee5251d3cccbaeb0191ca3f33f84b11d347bebc6e21f"
 dependencies = [
  "parity-scale-codec",
  "scale-info",
@@ -12922,14 +13097,13 @@
 
 [[package]]
 name = "sp-core"
-version = "21.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9ebb090ead698a6df04347c86a31ba91a387edb8a58534ec70c4f977d1e1e87"
 dependencies = [
- "array-bytes",
- "arrayvec 0.7.4",
- "bandersnatch_vrfs",
+ "array-bytes 6.2.0",
  "bitflags 1.3.2",
- "blake2",
+ "blake2 0.10.6",
  "bounded-collections",
  "bs58 0.5.0",
  "dyn-clonable",
@@ -12964,13 +13138,15 @@
  "thiserror",
  "tiny-bip39",
  "tracing",
+ "w3f-bls",
  "zeroize",
 ]
 
 [[package]]
 name = "sp-core-hashing"
-version = "9.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "13.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb8524f01591ee58b46cd83c9dbc0fcffd2fd730dabec4f59326cd58a00f17e2"
 dependencies = [
  "blake2b_simd",
  "byteorder",
@@ -12982,18 +13158,20 @@
 
 [[package]]
 name = "sp-core-hashing-proc-macro"
-version = "9.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "13.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ce3e6931303769197da81facefa86159fa1085dcd96ecb7e7407b5b93582a0"
 dependencies = [
  "quote",
  "sp-core-hashing",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "sp-database"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "9.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c6e8c710d6a71512af6f42d9dba9c3d1f6ad793846480babf459bbde3d60a94"
 dependencies = [
  "kvdb",
  "parking_lot 0.12.1",
@@ -13001,18 +13179,20 @@
 
 [[package]]
 name = "sp-debug-derive"
-version = "8.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "12.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50535e1a5708d3ba5c1195b59ebefac61cc8679c2c24716b87a86e8b7ed2e4a1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "sp-externalities"
-version = "0.19.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "884d05160bc89d0943d1c9fb8006c3d44b80f37f8af607aeff8d4d9cc82e279a"
 dependencies = [
  "environmental",
  "parity-scale-codec",
@@ -13022,8 +13202,9 @@
 
 [[package]]
 name = "sp-genesis-builder"
-version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0cb71d40ad47e40bdcce5ae5531c7d7ba579cd495a0e0413642fb063fa66f84"
 dependencies = [
  "serde_json",
  "sp-api",
@@ -13033,8 +13214,9 @@
 
 [[package]]
 name = "sp-inherents"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "604229aa145be0cff853b47ffed8bc2c62eb08ec6974d6307b9a559c378e6dc5"
 dependencies = [
  "async-trait",
  "impl-trait-for-tuples",
@@ -13047,8 +13229,9 @@
 
 [[package]]
 name = "sp-io"
-version = "23.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "27.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ced350da15e8ba3a106206840acc42a6d3eb0d7e8bf7aa43ab00eac0bdf956f"
 dependencies = [
  "bytes",
  "ed25519-dalek",
@@ -13071,19 +13254,21 @@
 
 [[package]]
 name = "sp-keyring"
-version = "24.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "28.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "655ec0b35cb9cb9029fb323aa676b07d58deb872cecc7566e50278409a00ee95"
 dependencies = [
  "lazy_static",
  "sp-core",
  "sp-runtime",
- "strum",
+ "strum 0.24.1",
 ]
 
 [[package]]
 name = "sp-keystore"
-version = "0.27.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b8ec5ebbba70bee83d79c3fe5e49f12df0a4bb6029858ddf9a15eea7539a592"
 dependencies = [
  "parity-scale-codec",
  "parking_lot 0.12.1",
@@ -13094,8 +13279,9 @@
 
 [[package]]
 name = "sp-maybe-compressed-blob"
-version = "4.1.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "9.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8846768f036429227e49f6ab523fbee4bc6edfee278a361bf27999590fe020d4"
 dependencies = [
  "thiserror",
  "zstd 0.12.4",
@@ -13103,19 +13289,34 @@
 
 [[package]]
 name = "sp-metadata-ir"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ca9ff0e522a74725ac92f009d38deeb12e880f5296afbd78a6c6b970b773278"
+dependencies = [
+ "frame-metadata",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-mixnet"
 version = "0.1.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdf61f28ca97aab6c21a3c6e0ed496e60d505e5de1f43fd4ba748c9afaa4fc85"
 dependencies = [
- "frame-metadata",
  "parity-scale-codec",
  "scale-info",
+ "sp-api",
+ "sp-application-crypto",
  "sp-std",
 ]
 
 [[package]]
 name = "sp-mmr-primitives"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c3b33c20a4b1dd5a0069ced6997078a2af5d625f2c53d1b69bef9e131f42d77"
 dependencies = [
  "ckb-merkle-mountain-range",
  "log",
@@ -13132,8 +13333,9 @@
 
 [[package]]
 name = "sp-npos-elections"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ee3536d7fd990c30864ca545d7bdbee02dc66a92ac2a7a66ab4e21521992a7b"
 dependencies = [
  "parity-scale-codec",
  "scale-info",
@@ -13146,8 +13348,9 @@
 
 [[package]]
 name = "sp-offchain"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9310227f043ed99877b0449a683025a7461431a00995dcd6ef423a273d0fd85d"
 dependencies = [
  "sp-api",
  "sp-core",
@@ -13156,8 +13359,9 @@
 
 [[package]]
 name = "sp-panic-handler"
-version = "8.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "12.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b00e40857ed3e0187f145b037c733545c5633859f1bd1d1b09deb52805fa696a"
 dependencies = [
  "backtrace",
  "lazy_static",
@@ -13166,8 +13370,9 @@
 
 [[package]]
 name = "sp-rpc"
-version = "6.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51867fea921f54bbaa2bf505f373559b5f3b80e8d7f38ecb9677f0d3795a3e6a"
 dependencies = [
  "rustc-hash",
  "serde",
@@ -13176,8 +13381,9 @@
 
 [[package]]
 name = "sp-runtime"
-version = "24.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "28.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d9c40ff7303e62219b55635e5245d963358cb77d6916250991ebcb82c0be2c6"
 dependencies = [
  "either",
  "hash256-std-hasher",
@@ -13198,8 +13404,9 @@
 
 [[package]]
 name = "sp-runtime-interface"
-version = "17.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "21.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f365332922a8cfa98ab00c6d08b1b0f24e159e730dd554e720d950ff3371b1f"
 dependencies = [
  "bytes",
  "impl-trait-for-tuples",
@@ -13216,20 +13423,22 @@
 
 [[package]]
 name = "sp-runtime-interface-proc-macro"
-version = "11.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "15.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b2afcbd1bd18d323371111b66b7ac2870bdc1c86c3d7b0dae67b112ca52b4d8"
 dependencies = [
  "Inflector",
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "sp-session"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "248dd8f49aa96b56bf0a7d513691ddb4194f9359fdb93e94397eabdef1036085"
 dependencies = [
  "parity-scale-codec",
  "scale-info",
@@ -13243,8 +13452,9 @@
 
 [[package]]
 name = "sp-staking"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee0feed0137234598bd1f76d0b468c585ea16619ea9ed1acbba82dd24ac79788"
 dependencies = [
  "impl-trait-for-tuples",
  "parity-scale-codec",
@@ -13257,8 +13467,9 @@
 
 [[package]]
 name = "sp-state-machine"
-version = "0.28.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96e087fa4430befd2047b61d912c9d6fa4eaed408c4b58b46c6e9acd7965f2d3"
 dependencies = [
  "hash-db 0.16.0",
  "log",
@@ -13273,13 +13484,14 @@
  "sp-trie",
  "thiserror",
  "tracing",
- "trie-db",
+ "trie-db 0.28.0",
 ]
 
 [[package]]
 name = "sp-statement-store"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "7.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b8654bcd37602b1811414050d34d14f543873bd4e64e50d210a0116b660c600"
 dependencies = [
  "aes-gcm 0.10.3",
  "curve25519-dalek 4.1.1",
@@ -13302,13 +13514,15 @@
 
 [[package]]
 name = "sp-std"
-version = "8.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "12.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54c78c5a66682568cc7b153603c5d01a2cc8f5c221c7b1e921517a0eef18ae05"
 
 [[package]]
 name = "sp-storage"
-version = "13.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "016f20812cc51bd479cc88d048c35d44cd3adde4accdb159d49d6050f2953595"
 dependencies = [
  "impl-serde",
  "parity-scale-codec",
@@ -13320,8 +13534,9 @@
 
 [[package]]
 name = "sp-timestamp"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "004a7f453240db80b2967c0e1c6411836efc7daa7afae98fd16202caa51460e0"
 dependencies = [
  "async-trait",
  "parity-scale-codec",
@@ -13333,8 +13548,9 @@
 
 [[package]]
 name = "sp-tracing"
-version = "10.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "14.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d727cb5265641ffbb7d4e42c18b63e29f6cfdbd240aae3bcf093c3d6eb29a19"
 dependencies = [
  "parity-scale-codec",
  "sp-std",
@@ -13345,8 +13561,9 @@
 
 [[package]]
 name = "sp-transaction-pool"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7cd2afe89c474339d15d06e73639171ebe4d280be6904d9349072103da21427"
 dependencies = [
  "sp-api",
  "sp-runtime",
@@ -13354,8 +13571,9 @@
 
 [[package]]
 name = "sp-transaction-storage-proof"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39ae7c4954431b8479f7b2b6b82f0551cc360a1ee59b6a5276eef86a1099eaed"
 dependencies = [
  "async-trait",
  "parity-scale-codec",
@@ -13369,10 +13587,11 @@
 
 [[package]]
 name = "sp-trie"
-version = "22.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "26.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e359b358263cc322c3f678c272a3a519621d9853dcfa1374dfcbdb5f54c6f85"
 dependencies = [
- "ahash 0.8.3",
+ "ahash 0.8.6",
  "hash-db 0.16.0",
  "hashbrown 0.13.2",
  "lazy_static",
@@ -13380,20 +13599,22 @@
  "nohash-hasher",
  "parity-scale-codec",
  "parking_lot 0.12.1",
+ "rand 0.8.5",
  "scale-info",
  "schnellru",
  "sp-core",
  "sp-std",
  "thiserror",
  "tracing",
- "trie-db",
+ "trie-db 0.28.0",
  "trie-root",
 ]
 
 [[package]]
 name = "sp-version"
-version = "22.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "26.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e93da332eba3cb59a65f128da5edd5c70e1475692b45470104e7465b1278471"
 dependencies = [
  "impl-serde",
  "parity-scale-codec",
@@ -13409,19 +13630,21 @@
 
 [[package]]
 name = "sp-version-proc-macro"
-version = "8.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "12.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49535d8c7184dab46d15639c68374a30cbb1534e392fa09a1ebb059a993ad436"
 dependencies = [
  "parity-scale-codec",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "sp-wasm-interface"
-version = "14.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "18.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5d85813d46a22484cdf5e5afddbbe85442dd1b4d84d67a8c7792f92f9f93607"
 dependencies = [
  "anyhow",
  "impl-trait-for-tuples",
@@ -13433,8 +13656,9 @@
 
 [[package]]
 name = "sp-weights"
-version = "20.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "751676c1263e7f3600af16bad26a7978a816bc532676fe05eafa23b862c05b9e"
 dependencies = [
  "parity-scale-codec",
  "scale-info",
@@ -13454,7 +13678,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -13477,7 +13701,7 @@
 dependencies = [
  "lazy_static",
  "maplit",
- "strum",
+ "strum 0.24.1",
 ]
 
 [[package]]
@@ -13502,9 +13726,9 @@
 
 [[package]]
 name = "ss58-registry"
-version = "1.43.0"
+version = "1.44.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e6915280e2d0db8911e5032a5c275571af6bdded2916abd691a659be25d3439"
+checksum = "35935738370302d5e33963665b77541e4b990a3e919ec904c837a56cfc891de1"
 dependencies = [
  "Inflector",
  "num-format",
@@ -13522,115 +13746,25 @@
 checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
 
 [[package]]
-name = "staging-kusama-runtime"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+name = "staging-parachain-info"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a1bcf863664ca5708d92894fc30d2c6606c7dbb7d7cfcf43b9ae69d5b83f4fb"
 dependencies = [
- "binary-merkle-tree",
- "bitvec",
- "frame-benchmarking",
- "frame-election-provider-support",
- "frame-executive",
+ "cumulus-primitives-core",
  "frame-support",
  "frame-system",
- "frame-system-benchmarking",
- "frame-system-rpc-runtime-api",
- "frame-try-runtime",
- "hex-literal",
- "kusama-runtime-constants",
- "log",
- "pallet-authority-discovery",
- "pallet-authorship",
- "pallet-babe",
- "pallet-bags-list",
- "pallet-balances",
- "pallet-beefy",
- "pallet-beefy-mmr",
- "pallet-bounties",
- "pallet-child-bounties",
- "pallet-collective",
- "pallet-conviction-voting",
- "pallet-democracy",
- "pallet-election-provider-multi-phase",
- "pallet-election-provider-support-benchmarking",
- "pallet-elections-phragmen",
- "pallet-fast-unstake",
- "pallet-grandpa",
- "pallet-identity 4.0.0-dev (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0)",
- "pallet-im-online",
- "pallet-indices",
- "pallet-membership",
- "pallet-message-queue",
- "pallet-mmr",
- "pallet-multisig",
- "pallet-nis",
- "pallet-nomination-pools",
- "pallet-nomination-pools-benchmarking",
- "pallet-nomination-pools-runtime-api",
- "pallet-offences",
- "pallet-offences-benchmarking",
- "pallet-preimage",
- "pallet-proxy",
- "pallet-ranked-collective",
- "pallet-recovery",
- "pallet-referenda",
- "pallet-scheduler",
- "pallet-session",
- "pallet-session-benchmarking",
- "pallet-society",
- "pallet-staking",
- "pallet-staking-runtime-api",
- "pallet-state-trie-migration",
- "pallet-timestamp",
- "pallet-tips",
- "pallet-transaction-payment",
- "pallet-transaction-payment-rpc-runtime-api",
- "pallet-treasury",
- "pallet-utility",
- "pallet-vesting",
- "pallet-whitelist",
- "pallet-xcm",
- "pallet-xcm-benchmarks",
  "parity-scale-codec",
- "polkadot-primitives",
- "polkadot-runtime-common",
- "polkadot-runtime-parachains",
- "rustc-hex",
  "scale-info",
- "serde",
- "serde_derive",
- "smallvec",
- "sp-api",
- "sp-application-crypto",
- "sp-arithmetic",
- "sp-authority-discovery",
- "sp-block-builder",
- "sp-consensus-babe",
- "sp-consensus-beefy",
- "sp-core",
- "sp-inherents",
- "sp-io",
- "sp-mmr-primitives",
- "sp-npos-elections",
- "sp-offchain",
  "sp-runtime",
- "sp-session",
- "sp-staking",
  "sp-std",
- "sp-storage",
- "sp-transaction-pool",
- "sp-version",
- "staging-xcm",
- "staging-xcm-builder",
- "staging-xcm-executor",
- "static_assertions",
- "substrate-wasm-builder",
 ]
 
 [[package]]
 name = "staging-xcm"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7abd0c2e401a1e264379131c27676bc65c9631aaa508044bc04d8ce60a7d8524"
 dependencies = [
  "bounded-collections",
  "derivative",
@@ -13646,8 +13780,9 @@
 
 [[package]]
 name = "staging-xcm-builder"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa3b14246daaf0301dd35d698bac570d82ba0c6c6c1d3e149b93bcf377b2fc6b"
 dependencies = [
  "frame-support",
  "frame-system",
@@ -13668,8 +13803,9 @@
 
 [[package]]
 name = "staging-xcm-executor"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a85a421053f810f3ed988ba3cc39d926c95f70f1ae73282aa8cd5c50072173b"
 dependencies = [
  "environmental",
  "frame-benchmarking",
@@ -13740,10 +13876,16 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
 dependencies = [
- "strum_macros",
+ "strum_macros 0.24.3",
 ]
 
 [[package]]
+name = "strum"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
+
+[[package]]
 name = "strum_macros"
 version = "0.24.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -13757,6 +13899,19 @@
 ]
 
 [[package]]
+name = "strum_macros"
+version = "0.25.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn 2.0.39",
+]
+
+[[package]]
 name = "stun"
 version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -13768,7 +13923,7 @@
  "md-5",
  "rand 0.8.5",
  "ring 0.16.20",
- "subtle",
+ "subtle 2.4.1",
  "thiserror",
  "tokio",
  "url",
@@ -13777,9 +13932,9 @@
 
 [[package]]
 name = "substrate-bip39"
-version = "0.4.4"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49eee6965196b32f882dd2ee85a92b1dbead41b04e53907f269de3b0dc04733c"
+checksum = "e620c7098893ba667438b47169c00aacdd9e7c10e042250ce2b60b087ec97328"
 dependencies = [
  "hmac 0.11.0",
  "pbkdf2 0.8.0",
@@ -13790,13 +13945,15 @@
 
 [[package]]
 name = "substrate-build-script-utils"
-version = "3.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "9.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a3b7556a62d77b7b8abc34e425817f6f563c2f2aa7142f1c4e93e6422156cc1"
 
 [[package]]
 name = "substrate-frame-rpc-system"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "25.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c241af714c378075b1185e574202cbb9105e849b8c9ea44ef87880bdb3e9a75"
 dependencies = [
  "frame-system-rpc-runtime-api",
  "futures",
@@ -13814,8 +13971,9 @@
 
 [[package]]
 name = "substrate-prometheus-endpoint"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ededbe617291db8a47d6e5155486ff1e5425f0bbf5dcb7f752730466a62bd293"
 dependencies = [
  "hyper",
  "log",
@@ -13826,8 +13984,9 @@
 
 [[package]]
 name = "substrate-rpc-client"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5575c2bef89385e5406565b8fe5620856d414e3846c60927a78f0788cb288c8c"
 dependencies = [
  "async-trait",
  "jsonrpsee",
@@ -13839,8 +13998,9 @@
 
 [[package]]
 name = "substrate-state-trie-migration-rpc"
-version = "4.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d57888ccce554552c535346893a497d2cfd232f15b6b676d130cdd5bf3f2ccea"
 dependencies = [
  "jsonrpsee",
  "parity-scale-codec",
@@ -13851,13 +14011,14 @@
  "sp-runtime",
  "sp-state-machine",
  "sp-trie",
- "trie-db",
+ "trie-db 0.28.0",
 ]
 
 [[package]]
 name = "substrate-wasm-builder"
-version = "5.0.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "14.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12ab1707dbbd129622b771a9b80b25f0ebf1c04854b907bc44b51ec96fb4005b"
 dependencies = [
  "ansi_term",
  "build-helper",
@@ -13865,7 +14026,7 @@
  "filetime",
  "parity-wasm",
  "sp-maybe-compressed-blob",
- "strum",
+ "strum 0.24.1",
  "tempfile",
  "toml 0.7.8",
  "walkdir",
@@ -13883,6 +14044,12 @@
 
 [[package]]
 name = "subtle"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
+
+[[package]]
+name = "subtle"
 version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
@@ -13906,9 +14073,9 @@
 
 [[package]]
 name = "syn"
-version = "2.0.37"
+version = "2.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
+checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -13956,28 +14123,28 @@
 
 [[package]]
 name = "target-lexicon"
-version = "0.12.11"
+version = "0.12.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a"
+checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a"
 
 [[package]]
 name = "tempfile"
-version = "3.8.0"
+version = "3.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
+checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
 dependencies = [
  "cfg-if",
  "fastrand 2.0.1",
- "redox_syscall 0.3.5",
- "rustix 0.38.15",
+ "redox_syscall 0.4.1",
+ "rustix 0.38.25",
  "windows-sys 0.48.0",
 ]
 
 [[package]]
 name = "termcolor"
-version = "1.3.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
+checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
 dependencies = [
  "winapi-util",
 ]
@@ -14022,42 +14189,42 @@
 
 [[package]]
 name = "thiserror"
-version = "1.0.49"
+version = "1.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
+checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-core"
-version = "1.0.38"
+version = "1.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497"
+checksum = "c001ee18b7e5e3f62cbf58c7fe220119e68d902bb7443179c0c8aef30090e999"
 dependencies = [
  "thiserror-core-impl",
 ]
 
 [[package]]
 name = "thiserror-core-impl"
-version = "1.0.38"
+version = "1.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac"
+checksum = "e4c60d69f36615a077cc7663b9cb8e42275722d23e58a7fa3d2c7f2915d09d04"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.49"
+version = "1.0.50"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
+checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -14121,12 +14288,13 @@
 
 [[package]]
 name = "time"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe"
+checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
 dependencies = [
  "deranged",
  "itoa",
+ "powerfmt",
  "serde",
  "time-core",
  "time-macros",
@@ -14202,9 +14370,9 @@
 
 [[package]]
 name = "tokio"
-version = "1.32.0"
+version = "1.34.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
+checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9"
 dependencies = [
  "backtrace",
  "bytes",
@@ -14214,20 +14382,20 @@
  "parking_lot 0.12.1",
  "pin-project-lite 0.2.13",
  "signal-hook-registry",
- "socket2 0.5.4",
+ "socket2 0.5.5",
  "tokio-macros",
  "windows-sys 0.48.0",
 ]
 
 [[package]]
 name = "tokio-macros"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
+checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -14247,7 +14415,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
 dependencies = [
- "rustls 0.21.7",
+ "rustls 0.21.9",
  "tokio",
 ]
 
@@ -14265,9 +14433,9 @@
 
 [[package]]
 name = "tokio-util"
-version = "0.7.9"
+version = "0.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d"
+checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
 dependencies = [
  "bytes",
  "futures-core",
@@ -14296,14 +14464,14 @@
  "serde",
  "serde_spanned",
  "toml_datetime",
- "toml_edit",
+ "toml_edit 0.19.15",
 ]
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.3"
+version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
+checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
 dependencies = [
  "serde",
 ]
@@ -14314,7 +14482,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
 dependencies = [
- "indexmap 2.0.2",
+ "indexmap 2.1.0",
  "serde",
  "serde_spanned",
  "toml_datetime",
@@ -14322,6 +14490,17 @@
 ]
 
 [[package]]
+name = "toml_edit"
+version = "0.20.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
+dependencies = [
+ "indexmap 2.1.0",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
 name = "tower"
 version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -14338,7 +14517,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
 dependencies = [
- "bitflags 2.4.0",
+ "bitflags 2.4.1",
  "bytes",
  "futures-core",
  "futures-util",
@@ -14364,11 +14543,10 @@
 
 [[package]]
 name = "tracing"
-version = "0.1.37"
+version = "0.1.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
+checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
 dependencies = [
- "cfg-if",
  "log",
  "pin-project-lite 0.2.13",
  "tracing-attributes",
@@ -14377,20 +14555,20 @@
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.26"
+version = "0.1.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
+checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "tracing-core"
-version = "0.1.31"
+version = "0.1.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
 dependencies = [
  "once_cell",
  "valuable",
@@ -14408,8 +14586,9 @@
 
 [[package]]
 name = "tracing-gum"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32c0555bd635d9adbf8dec0bf45f7c2aef7541121d648ba37f5f792a211077b6"
 dependencies = [
  "coarsetime",
  "polkadot-node-jaeger",
@@ -14420,24 +14599,25 @@
 
 [[package]]
 name = "tracing-gum-proc-macro"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35756d8c1a227ec525853a1080bf890d03d939deb2bc50d4d43c96516c795d0d"
 dependencies = [
  "expander 2.0.0",
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
 name = "tracing-log"
-version = "0.1.3"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
+checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2"
 dependencies = [
- "lazy_static",
  "log",
+ "once_cell",
  "tracing-core",
 ]
 
@@ -14483,6 +14663,18 @@
  "hash-db 0.16.0",
  "hashbrown 0.13.2",
  "log",
+ "smallvec",
+]
+
+[[package]]
+name = "trie-db"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff28e0f815c2fea41ebddf148e008b077d2faddb026c9555b29696114d602642"
+dependencies = [
+ "hash-db 0.16.0",
+ "hashbrown 0.13.2",
+ "log",
  "rustc-hex",
  "smallvec",
 ]
@@ -14524,7 +14716,7 @@
  "lazy_static",
  "rand 0.8.5",
  "smallvec",
- "socket2 0.4.9",
+ "socket2 0.4.10",
  "thiserror",
  "tinyvec",
  "tokio",
@@ -14560,8 +14752,9 @@
 
 [[package]]
 name = "try-runtime-cli"
-version = "0.10.0-dev"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "0.35.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "845090aa8572116b06813914fc1d09448fe895d82982b63d58de4f91b4eb79b6"
 dependencies = [
  "async-trait",
  "clap",
@@ -14662,7 +14855,7 @@
  "sp-runtime",
  "sp-state-machine",
  "sp-trie",
- "trie-db",
+ "trie-db 0.27.1",
  "unique-runtime",
  "up-common",
  "up-data-structs",
@@ -14724,7 +14917,7 @@
 
 [[package]]
 name = "unique-node"
-version = "1.1.0"
+version = "1.2.0"
 dependencies = [
  "app-promotion-rpc",
  "clap",
@@ -14808,7 +15001,7 @@
 
 [[package]]
 name = "unique-runtime"
-version = "1.1.0"
+version = "1.2.0"
 dependencies = [
  "app-promotion-rpc",
  "cumulus-pallet-aura-ext",
@@ -14884,9 +15077,9 @@
  "pallet-unique",
  "pallet-utility",
  "pallet-xcm",
- "parachain-info",
  "parity-scale-codec",
  "polkadot-parachain-primitives",
+ "polkadot-runtime-common",
  "precompile-utils-macro",
  "scale-info",
  "serde",
@@ -14905,6 +15098,7 @@
  "sp-storage",
  "sp-transaction-pool",
  "sp-version",
+ "staging-parachain-info",
  "staging-xcm",
  "staging-xcm-builder",
  "staging-xcm-executor",
@@ -14923,7 +15117,7 @@
 checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05"
 dependencies = [
  "generic-array 0.14.7",
- "subtle",
+ "subtle 2.4.1",
 ]
 
 [[package]]
@@ -14933,7 +15127,7 @@
 checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
 dependencies = [
  "crypto-common",
- "subtle",
+ "subtle 2.4.1",
 ]
 
 [[package]]
@@ -14955,8 +15149,14 @@
 checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
 
 [[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
 name = "up-common"
-version = "1.1.0"
+version = "1.2.0"
 dependencies = [
  "cumulus-primitives-core",
  "fp-rpc",
@@ -15017,7 +15217,7 @@
 [[package]]
 name = "up-sponsorship"
 version = "0.1.0"
-source = "git+https://github.com/uniquenetwork/pallet-sponsoring?branch=polkadot-v1.1.0#2fbec92640f517e4812be7ed61ef7691af6e0bba"
+source = "git+https://github.com/uniquenetwork/pallet-sponsoring?branch=polkadot-v1.3.0#6071a67116a08ef81083337360de376b63c0ea1c"
 dependencies = [
  "impl-trait-for-tuples",
 ]
@@ -15041,11 +15241,11 @@
 
 [[package]]
 name = "uuid"
-version = "1.4.1"
+version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
+checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560"
 dependencies = [
- "getrandom 0.2.10",
+ "getrandom 0.2.11",
 ]
 
 [[package]]
@@ -15073,6 +15273,30 @@
 checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
 
 [[package]]
+name = "w3f-bls"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7335e4c132c28cc43caef6adb339789e599e39adbe78da0c4d547fad48cbc331"
+dependencies = [
+ "ark-bls12-377",
+ "ark-bls12-381",
+ "ark-ec",
+ "ark-ff",
+ "ark-serialize",
+ "ark-serialize-derive",
+ "arrayref",
+ "constcat",
+ "digest 0.10.7",
+ "rand 0.8.5",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.4",
+ "sha2 0.10.8",
+ "sha3 0.10.8",
+ "thiserror",
+ "zeroize",
+]
+
+[[package]]
 name = "waitgroup"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -15120,9 +15344,9 @@
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.87"
+version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
+checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -15130,24 +15354,24 @@
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.87"
+version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
+checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
 dependencies = [
  "bumpalo",
  "log",
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.37"
+version = "0.4.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
+checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02"
 dependencies = [
  "cfg-if",
  "js-sys",
@@ -15157,9 +15381,9 @@
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.87"
+version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
+checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -15167,22 +15391,22 @@
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.87"
+version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
+checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.87"
+version = "0.2.88"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
+checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
 
 [[package]]
 name = "wasm-instrument"
@@ -15195,14 +15419,14 @@
 
 [[package]]
 name = "wasm-opt"
-version = "0.114.1"
+version = "0.116.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d005a95f934878a1fb446a816d51c3601a0120ff929005ba3bab3c749cfd1c7"
+checksum = "fc942673e7684671f0c5708fc18993569d184265fd5223bb51fc8e5b9b6cfd52"
 dependencies = [
  "anyhow",
  "libc",
- "strum",
- "strum_macros",
+ "strum 0.24.1",
+ "strum_macros 0.24.3",
  "tempfile",
  "thiserror",
  "wasm-opt-cxx-sys",
@@ -15211,9 +15435,9 @@
 
 [[package]]
 name = "wasm-opt-cxx-sys"
-version = "0.114.1"
+version = "0.116.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d04e240598162810fad3b2e96fa0dec6dba1eb65a03f3bd99a9248ab8b56caa"
+checksum = "8c57b28207aa724318fcec6575fe74803c23f6f266fce10cbc9f3f116762f12e"
 dependencies = [
  "anyhow",
  "cxx",
@@ -15223,9 +15447,9 @@
 
 [[package]]
 name = "wasm-opt-sys"
-version = "0.114.1"
+version = "0.116.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2efd2aaca519d64098c4faefc8b7433a97ed511caf4c9e516384eb6aef1ff4f9"
+checksum = "8a1cce564dc768dacbdb718fc29df2dba80bd21cb47d8f77ae7e3d95ceb98cbe"
 dependencies = [
  "anyhow",
  "cc",
@@ -15342,12 +15566,12 @@
 checksum = "c86437fa68626fe896e5afc69234bb2b5894949083586535f200385adfd71213"
 dependencies = [
  "anyhow",
- "base64 0.21.4",
+ "base64 0.21.5",
  "bincode",
  "directories-next",
  "file-per-thread-logger",
  "log",
- "rustix 0.36.15",
+ "rustix 0.36.17",
  "serde",
  "sha2 0.10.8",
  "toml 0.5.11",
@@ -15443,7 +15667,7 @@
 dependencies = [
  "object 0.30.4",
  "once_cell",
- "rustix 0.36.15",
+ "rustix 0.36.17",
 ]
 
 [[package]]
@@ -15474,7 +15698,7 @@
  "memoffset 0.8.0",
  "paste",
  "rand 0.8.5",
- "rustix 0.36.15",
+ "rustix 0.36.17",
  "wasmtime-asm-macros",
  "wasmtime-environ",
  "wasmtime-jit-debug",
@@ -15495,9 +15719,9 @@
 
 [[package]]
 name = "web-sys"
-version = "0.3.64"
+version = "0.3.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
+checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -15510,17 +15734,17 @@
 checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea"
 dependencies = [
  "ring 0.16.20",
- "untrusted",
+ "untrusted 0.7.1",
 ]
 
 [[package]]
 name = "webpki"
-version = "0.22.2"
+version = "0.22.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07ecc0cd7cac091bf682ec5efa18b1cff79d617b84181f38b3951dbe135f607f"
+checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53"
 dependencies = [
- "ring 0.16.20",
- "untrusted",
+ "ring 0.17.5",
+ "untrusted 0.9.0",
 ]
 
 [[package]]
@@ -15529,16 +15753,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
 dependencies = [
- "webpki 0.22.2",
-]
-
-[[package]]
-name = "webpki-roots"
-version = "0.23.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338"
-dependencies = [
- "rustls-webpki 0.100.3",
+ "webpki 0.22.4",
 ]
 
 [[package]]
@@ -15634,7 +15849,7 @@
  "sha1",
  "sha2 0.10.8",
  "signature 1.6.4",
- "subtle",
+ "subtle 2.4.1",
  "thiserror",
  "tokio",
  "webpki 0.21.4",
@@ -15674,7 +15889,7 @@
 checksum = "f08dfd7a6e3987e255c4dbe710dde5d94d0f0574f8a21afa95d171376c143106"
 dependencies = [
  "log",
- "socket2 0.4.9",
+ "socket2 0.4.10",
  "thiserror",
  "tokio",
  "webrtc-util",
@@ -15728,7 +15943,7 @@
  "rtcp",
  "rtp",
  "sha-1",
- "subtle",
+ "subtle 2.4.1",
  "thiserror",
  "tokio",
  "webrtc-util",
@@ -15757,8 +15972,9 @@
 
 [[package]]
 name = "westend-runtime"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e833bb935995cb8da9848b974f37801c66163502929ecf22ca15878b8e8edbb7"
 dependencies = [
  "binary-merkle-tree",
  "bitvec",
@@ -15772,6 +15988,7 @@
  "frame-try-runtime",
  "hex-literal",
  "log",
+ "pallet-asset-rate",
  "pallet-authority-discovery",
  "pallet-authorship",
  "pallet-babe",
@@ -15780,13 +15997,14 @@
  "pallet-beefy",
  "pallet-beefy-mmr",
  "pallet-collective",
+ "pallet-conviction-voting",
  "pallet-democracy",
  "pallet-election-provider-multi-phase",
  "pallet-election-provider-support-benchmarking",
  "pallet-elections-phragmen",
  "pallet-fast-unstake",
  "pallet-grandpa",
- "pallet-identity 4.0.0-dev (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0)",
+ "pallet-identity 25.0.0",
  "pallet-im-online",
  "pallet-indices",
  "pallet-membership",
@@ -15801,6 +16019,7 @@
  "pallet-preimage",
  "pallet-proxy",
  "pallet-recovery",
+ "pallet-referenda",
  "pallet-scheduler",
  "pallet-session",
  "pallet-session-benchmarking",
@@ -15816,6 +16035,7 @@
  "pallet-treasury",
  "pallet-utility",
  "pallet-vesting",
+ "pallet-whitelist",
  "pallet-xcm",
  "pallet-xcm-benchmarks",
  "parity-scale-codec",
@@ -15830,11 +16050,13 @@
  "smallvec",
  "sp-api",
  "sp-application-crypto",
+ "sp-arithmetic",
  "sp-authority-discovery",
  "sp-block-builder",
  "sp-consensus-babe",
  "sp-consensus-beefy",
  "sp-core",
+ "sp-genesis-builder",
  "sp-inherents",
  "sp-io",
  "sp-mmr-primitives",
@@ -15856,8 +16078,9 @@
 
 [[package]]
 name = "westend-runtime-constants"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "682c32c5f5e6d51c431bf66c33fc502c66e7b25488c0bd92f5ee020c329f2beb"
 dependencies = [
  "frame-support",
  "polkadot-primitives",
@@ -15866,6 +16089,7 @@
  "sp-core",
  "sp-runtime",
  "sp-weights",
+ "staging-xcm",
 ]
 
 [[package]]
@@ -15877,14 +16101,14 @@
  "either",
  "home",
  "once_cell",
- "rustix 0.38.15",
+ "rustix 0.38.25",
 ]
 
 [[package]]
 name = "wide"
-version = "0.7.12"
+version = "0.7.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebecebefc38ff1860b4bc47550bbfa63af5746061cf0d29fcd7fa63171602598"
+checksum = "c68938b57b33da363195412cfc5fc37c9ed49aa9cfe2156fde64b8d2c9498242"
 dependencies = [
  "bytemuck",
  "safe_arch",
@@ -15929,22 +16153,19 @@
 
 [[package]]
 name = "windows"
-version = "0.34.0"
+version = "0.51.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f"
+checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9"
 dependencies = [
- "windows_aarch64_msvc 0.34.0",
- "windows_i686_gnu 0.34.0",
- "windows_i686_msvc 0.34.0",
- "windows_x86_64_gnu 0.34.0",
- "windows_x86_64_msvc 0.34.0",
+ "windows-core",
+ "windows-targets 0.48.5",
 ]
 
 [[package]]
-name = "windows"
-version = "0.48.0"
+name = "windows-core"
+version = "0.51.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
 dependencies = [
  "windows-targets 0.48.5",
 ]
@@ -16008,12 +16229,6 @@
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.34.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -16026,12 +16241,6 @@
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.34.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -16047,12 +16256,6 @@
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.34.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956"
-
-[[package]]
-name = "windows_i686_msvc"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
@@ -16062,12 +16265,6 @@
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.34.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -16092,12 +16289,6 @@
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.34.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -16113,9 +16304,9 @@
 
 [[package]]
 name = "winnow"
-version = "0.5.15"
+version = "0.5.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc"
+checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b"
 dependencies = [
  "memchr",
 ]
@@ -16201,13 +16392,14 @@
 
 [[package]]
 name = "xcm-procedural"
-version = "1.0.0"
-source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "401e2b62628da9246dececb06fe58118196557dd8deb9ce12d95cc4aaf56003f"
 dependencies = [
  "Inflector",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -16234,10 +16426,30 @@
 ]
 
 [[package]]
+name = "zerocopy"
+version = "0.7.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.39",
+]
+
+[[package]]
 name = "zeroize"
-version = "1.6.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
+checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
 dependencies = [
  "zeroize_derive",
 ]
@@ -16250,7 +16462,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn 2.0.39",
 ]
 
 [[package]]
@@ -16293,11 +16505,10 @@
 
 [[package]]
 name = "zstd-sys"
-version = "2.0.8+zstd.1.5.5"
+version = "2.0.9+zstd.1.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c"
+checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656"
 dependencies = [
  "cc",
- "libc",
  "pkg-config",
 ]
modifiedCargo.tomldiffbeforeafterboth
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,7 +11,7 @@
 	'runtime/tests',
 	'runtime/unique',
 ]
-package.version = "1.1.0"
+package.version = "1.2.0"
 resolver = "2"
 
 [profile.release]
@@ -34,7 +34,7 @@
 evm-coder = { version = "0.4.2", default-features = false, features = ['bondrewd'] }
 pallet-app-promotion = { path = "pallets/app-promotion", default-features = false }
 pallet-balances-adapter = { default-features = false, path = "pallets/balances-adapter" }
-pallet-charge-transaction = { package = "pallet-template-transaction-payment", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v1.1.0" }
+pallet-charge-transaction = { package = "pallet-template-transaction-payment", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v1.3.0" }
 pallet-collator-selection = { default-features = false, path = "pallets/collator-selection" }
 pallet-common = { default-features = false, path = "pallets/common" }
 pallet-configuration = { default-features = false, path = "pallets/configuration" }
@@ -61,7 +61,7 @@
 up-data-structs = { path = "primitives/data-structs", default-features = false }
 up-pov-estimate-rpc = { path = "primitives/pov-estimate-rpc", default-features = false }
 up-rpc = { path = "primitives/rpc", default-features = false }
-up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v1.1.0" }
+up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v1.3.0" }
 
 # Unique: Runtimes
 opal-runtime = { path = "runtime/opal" }
@@ -69,140 +69,141 @@
 unique-runtime = { path = "runtime/unique" }
 
 # Frontier (Unique patches over the Parity version)
-fc-api = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
-fc-consensus = { git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
-fc-db = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
-fc-mapping-sync = { git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
-fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
-fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
-fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
-fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
+fc-api = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
+fc-consensus = { git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
+fc-db = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
+fc-mapping-sync = { git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
+fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
+fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
+fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
+fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
 fp-self-contained = { default-features = false, features = [
 	"serde",
-], git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
-fp-storage = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
-pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
-pallet-evm-precompile-simple = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.1.0" }
+], git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
+fp-storage = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
+pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
+pallet-evm-precompile-simple = { default-features = false, git = "https://github.com/uniquenetwork/unique-frontier", branch = "unique-polkadot-v1.3.0" }
 
 # Parity
 codec = { default-features = false, features = ['derive'], package = 'parity-scale-codec', version = "3.6.5" }
-cumulus-client-cli = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-client-collator = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-client-consensus-aura = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-client-consensus-common = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-client-consensus-proposer = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-client-network = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-client-service = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-pallet-aura-ext = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-pallet-dmp-queue = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-pallet-parachain-system = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-pallet-xcm = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-pallet-xcmp-queue = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-primitives-aura = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-primitives-core = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-primitives-parachain-inherent = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-primitives-timestamp = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-primitives-utility = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-relay-chain-inprocess-interface = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-relay-chain-interface = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-cumulus-relay-chain-minimal-node = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-frame-executive = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-frame-support = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-frame-system = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-frame-system-rpc-runtime-api = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-aura = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-authorship = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-balances = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-collective = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-democracy = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-membership = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-preimage = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-ranked-collective = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-referenda = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-scheduler = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-session = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-state-trie-migration = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-sudo = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-timestamp = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-transaction-payment = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-transaction-payment-rpc-runtime-api = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-treasury = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-utility = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0", default-features = false }
-parachain-info = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
+cumulus-client-cli = "0.4.0"
+cumulus-client-collator = "0.4.0"
+cumulus-client-consensus-aura = "0.4.0"
+cumulus-client-consensus-common = "0.4.0"
+cumulus-client-consensus-proposer = "0.4.0"
+cumulus-client-network = "0.4.0"
+cumulus-client-service = "0.4.0"
+cumulus-pallet-aura-ext = { default-features = false, version = "0.4.0" }
+cumulus-pallet-dmp-queue = { default-features = false, version = "0.4.0" }
+cumulus-pallet-parachain-system = { default-features = false, version = "0.4.0" }
+cumulus-pallet-xcm = { default-features = false, version = "0.4.0" }
+cumulus-pallet-xcmp-queue = { default-features = false, version = "0.4.0" }
+cumulus-primitives-aura = { default-features = false, version = "0.4.0" }
+cumulus-primitives-core = { default-features = false, version = "0.4.0" }
+cumulus-primitives-parachain-inherent = { default-features = false, version = "0.4.0" }
+cumulus-primitives-timestamp = { default-features = false, version = "0.4.0" }
+cumulus-primitives-utility = { default-features = false, version = "0.4.0" }
+cumulus-relay-chain-inprocess-interface = "0.4.0"
+cumulus-relay-chain-interface = "0.4.0"
+cumulus-relay-chain-minimal-node = "0.4.0"
+frame-executive = { default-features = false, version = "25.0.0" }
+frame-support = { default-features = false, version = "25.0.0" }
+frame-system = { default-features = false, version = "25.0.0" }
+frame-system-rpc-runtime-api = { default-features = false, version = "23.0.0" }
+pallet-aura = { default-features = false, version = "24.0.0" }
+pallet-authorship = { default-features = false, version = "25.0.0" }
+pallet-balances = { default-features = false, version = "25.0.0" }
+pallet-collective = { default-features = false, version = "25.0.0" }
+pallet-democracy = { default-features = false, version = "25.0.0" }
+pallet-membership = { default-features = false, version = "25.0.0" }
+pallet-preimage = { default-features = false, version = "25.0.0" }
+pallet-ranked-collective = { default-features = false, version = "25.0.0" }
+pallet-referenda = { default-features = false, version = "25.0.0" }
+pallet-scheduler = { default-features = false, version = "26.0.0" }
+pallet-session = { default-features = false, version = "25.0.0" }
+pallet-state-trie-migration = { default-features = false, version = "26.0.0" }
+pallet-sudo = { default-features = false, version = "25.0.0" }
+pallet-timestamp = { default-features = false, version = "24.0.0" }
+pallet-transaction-payment = { default-features = false, version = "25.0.0" }
+pallet-transaction-payment-rpc = "27.0.0"
+pallet-transaction-payment-rpc-runtime-api = { default-features = false, version = "25.0.0" }
+pallet-treasury = { default-features = false, version = "24.0.0" }
+pallet-utility = { default-features = false, version = "25.0.0" }
+pallet-xcm = { default-features = false, version = "4.0.0" }
 parity-scale-codec = { version = "3.6.5", features = ["derive"], default-features = false }
-polkadot-cli = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-polkadot-parachain-primitives = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0", default-features = false }
-polkadot-primitives = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-polkadot-service = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-basic-authorship = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-chain-spec = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-cli = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-client-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-consensus = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-consensus-manual-seal = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-executor = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-network = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-network-sync = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-rpc = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-rpc-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-service = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-sysinfo = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-telemetry = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-tracing = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sc-transaction-pool = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
+polkadot-cli = "4.0.0"
+polkadot-parachain-primitives = { default-features = false, version = "3.0.0" }
+polkadot-primitives = "4.0.0"
+polkadot-runtime-common = { default-features = false, version = "4.0.0" }
+polkadot-service = "4.0.0"
+sc-basic-authorship = "0.31.0"
+sc-chain-spec = "24.0.0"
+sc-cli = "0.33.0"
+sc-client-api = "25.0.0"
+sc-consensus = "0.30.0"
+sc-consensus-manual-seal = "0.32.0"
+sc-executor = "0.29.0"
+sc-network = "0.31.0"
+sc-network-sync = "0.30.0"
+sc-rpc = "26.0.0"
+sc-rpc-api = "0.30.0"
+sc-service = "0.32.0"
+sc-sysinfo = "24.0.0"
+sc-telemetry = "12.0.0"
+sc-tracing = "25.0.0"
+sc-transaction-pool = "25.0.0"
 scale-info = { version = "2.9.0", default-features = false, features = ["derive"] }
-sp-api = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-arithmetic = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-block-builder = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-blockchain = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-consensus-aura = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-core = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-externalities = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-inherents = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-io = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-keystore = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-offchain = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-runtime = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-session = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-staking = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-state-machine = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-std = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-storage = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-timestamp = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-tracing = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-transaction-pool = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-trie = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-version = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-sp-weights = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-staging-xcm = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0", default-features = false }
-staging-xcm-builder = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0", default-features = false }
-staging-xcm-executor = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0", default-features = false }
-substrate-frame-rpc-system = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-substrate-prometheus-endpoint = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
+sp-api = { default-features = false, version = "23.0.0" }
+sp-arithmetic = { default-features = false, version = "20.0.0" }
+sp-block-builder = { default-features = false, version = "23.0.0" }
+sp-blockchain = "25.0.0"
+sp-consensus-aura = { default-features = false, version = "0.29.0" }
+sp-core = { default-features = false, version = "25.0.0" }
+sp-externalities = "0.23.0"
+sp-inherents = { default-features = false, version = "23.0.0" }
+sp-io = { default-features = false, version = "27.0.0" }
+sp-keystore = "0.31.0"
+sp-offchain = { default-features = false, version = "23.0.0" }
+sp-runtime = { default-features = false, version = "28.0.0" }
+sp-session = { default-features = false, version = "24.0.0" }
+sp-staking = { default-features = false, version = "23.0.0" }
+sp-state-machine = "0.32.0"
+sp-std = { default-features = false, version = "12.0.0" }
+sp-storage = { default-features = false, version = "17.0.0" }
+sp-timestamp = "23.0.0"
+sp-tracing = "14.0.0"
+sp-transaction-pool = { default-features = false, version = "23.0.0" }
+sp-trie = { default-features = false, version = "26.0.0" }
+sp-version = { default-features = false, version = "26.0.0" }
+sp-weights = { default-features = false, version = "24.0.0" }
+staging-parachain-info = { default-features = false, version = "0.4.0" }
+staging-xcm = { default-features = false, version = "4.0.0" }
+staging-xcm-builder = { default-features = false, version = "4.0.0" }
+staging-xcm-executor = { default-features = false, version = "4.0.0" }
+substrate-frame-rpc-system = "25.0.0"
+substrate-prometheus-endpoint = "0.16.0"
 
 # Parity: Build utils
-substrate-build-script-utils = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-substrate-wasm-builder = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
+substrate-build-script-utils = "9.0.0"
+substrate-wasm-builder = "14.0.0"
 
 # Parity: Benchmarking
-frame-benchmarking = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-frame-benchmarking-cli = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-frame-system-benchmarking = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
+frame-benchmarking = { default-features = false, version = "25.0.0" }
+frame-benchmarking-cli = "29.0.0"
+frame-system-benchmarking = { default-features = false, version = "25.0.0" }
 
 # Parity: Try Runtime
-frame-try-runtime = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
-try-runtime-cli = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" }
+frame-try-runtime = { default-features = false, version = "0.31.0" }
+try-runtime-cli = "0.35.0"
 
 # ORML
-orml-tokens = { default-features = false, git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v1.1.0" }
-orml-traits = { default-features = false, git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v1.1.0" }
-orml-vesting = { default-features = false, git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v1.1.0" }
-orml-xcm-support = { default-features = false, git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v1.1.0" }
-orml-xtokens = { default-features = false, git = "https://github.com/open-web3-stack/open-runtime-module-library", branch = "polkadot-v1.1.0" }
+orml-tokens = { default-features = false, git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "unique-polkadot-v1.3.0" }
+orml-traits = { default-features = false, git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "unique-polkadot-v1.3.0" }
+orml-vesting = { default-features = false, git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "unique-polkadot-v1.3.0" }
+orml-xcm-support = { default-features = false, git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "unique-polkadot-v1.3.0" }
+orml-xtokens = { default-features = false, git = "https://github.com/uniquenetwork/open-runtime-module-library", branch = "unique-polkadot-v1.3.0" }
 
 # Other
 derivative = { version = "2.2.0", features = ["use_core"] }
modifiedjs-packages/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/js-packages/playgrounds/unique.dev.ts
+++ b/js-packages/playgrounds/unique.dev.ts
@@ -696,7 +696,7 @@
       const recipient = this.helper.util.fromSeed(mnemonicGenerate(), ss58Format);
       accounts.push(recipient);
       if(balance !== 0n) {
-        const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recipient.address}, balance * tokenNominal]);
+        const tx = this.helper.constructApiCall('api.tx.balances.transferKeepAlive', [{Id: recipient.address}, balance * tokenNominal]);
         transactions.push(this.helper.signTransaction(donor, tx, {nonce}, 'account generation'));
         nonce++;
       }
@@ -749,7 +749,7 @@
         const recipient = this.helper.util.fromSeed(mnemonicGenerate(), ss58Format);
         accounts.push(recipient);
         if(withBalance !== 0n) {
-          const tx = this.helper.constructApiCall('api.tx.balances.transfer', [{Id: recipient.address}, withBalance * tokenNominal]);
+          const tx = this.helper.constructApiCall('api.tx.balances.transferKeepAlive', [{Id: recipient.address}, withBalance * tokenNominal]);
           transactions.push(this.helper.signTransaction(donor, tx, {nonce}, 'account generation'));
           nonce++;
         }
modifiedjs-packages/playgrounds/unique.tsdiffbeforeafterboth
before · js-packages/playgrounds/unique.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034/* eslint-disable @typescript-eslint/no-var-requires */5/* eslint-disable function-call-argument-newline */6/* eslint-disable no-prototype-builtins */78import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';9import type {SignerOptions} from '@polkadot/api/types';10import type {AugmentedSubmittables} from '@polkadot/api-base/types/submittable';11import type {ApiInterfaceEvents} from '@polkadot/api/types';12import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto';13import type {IKeyringPair} from '@polkadot/types/types';14import {hexToU8a} from '@polkadot/util/hex';15import {u8aConcat} from '@polkadot/util/u8a';16import type {17  IApiListeners,18  IBlock,19  IEvent,20  IChainProperties,21  ICollectionCreationOptions,22  ICollectionLimits,23  ICollectionPermissions,24  ICrossAccountId,25  ICrossAccountIdLower,26  ILogger,27  INestingPermissions,28  IProperty,29  IStakingInfo,30  ISubstrateBalance,31  IToken,32  ITokenPropertyPermission,33  ITransactionResult,34  IUniqueHelperLog,35  TApiAllowedListeners,36  TEthereumAccount,37  TSigner,38  TSubstrateAccount,39  TNetworks,40  IEthCrossAccountId,41} from './types.js';42import type {RuntimeDispatchInfo} from '@polkadot/types/interfaces';4344export class CrossAccountId {45  account: ICrossAccountId;4647  constructor(account: ICrossAccountId) {48    this.account = account;49  }5051  static fromKeyring(account: IKeyringPair, domain: 'Substrate' | 'Ethereum' = 'Substrate') {52    switch (domain) {53      case 'Substrate': return new CrossAccountId({Substrate: account.address});54      case 'Ethereum': return new CrossAccountId({Substrate: account.address}).toEthereum();55    }56  }5758  static fromLowerCaseKeys(address: ICrossAccountIdLower): CrossAccountId {59    if('substrate' in address) return new CrossAccountId({Substrate: address.substrate});60    else return new CrossAccountId({Ethereum: address.ethereum});61  }6263  static normalizeSubstrateAddress(address: {Substrate: TSubstrateAccount}, ss58Format = 42): TSubstrateAccount {64    return encodeAddress(decodeAddress(address.Substrate), ss58Format);65  }6667  static withNormalizedSubstrate(address: ICrossAccountId, ss58Format = 42): ICrossAccountId {68    if('Substrate' in address) return {Substrate: CrossAccountId.normalizeSubstrateAddress(address, ss58Format)};69    return address;70  }7172  withNormalizedSubstrate(ss58Format = 42): CrossAccountId {73    if('Substrate' in this.account) this.account = CrossAccountId.withNormalizedSubstrate(this.account, ss58Format);74    return this;75  }7677  static translateSubToEth(address: TSubstrateAccount): TEthereumAccount {78    return nesting.toChecksumAddress('0x' + Array.from(addressToEvm(address), i => i.toString(16).padStart(2, '0')).join(''));79  }8081  toEthereum(): CrossAccountId {82    this.account = CrossAccountId.toEthereum(this.account);83    return this;84  }8586  static toEthereum(account: ICrossAccountId): ICrossAccountId {87    if('Substrate' in account) return {Ethereum: CrossAccountId.translateSubToEth(account.Substrate)};88    return account;89  }9091  static translateEthToSub(address: TEthereumAccount, ss58Format?: number): TSubstrateAccount {92    return evmToAddress(address, ss58Format);93  }9495  toSubstrate(ss58Format?: number): CrossAccountId {96    this.account = CrossAccountId.toSubstrate(this.account, ss58Format);97    return this;98  }99100  static toSubstrate(account: ICrossAccountId, ss58Format?: number): ICrossAccountId {101    if('Ethereum' in account) return {Substrate: CrossAccountId.translateEthToSub(account.Ethereum, ss58Format)};102    return account;103  }104105  toLowerCase(): CrossAccountId {106    this.account = CrossAccountId.toLowerCase(this.account);107    return this;108  }109110  static toLowerCase(account: ICrossAccountId) {111    if('Substrate' in account) return {Substrate: account.Substrate.toLowerCase()};112    if('Ethereum' in account) return {Ethereum: account.Ethereum.toLowerCase()};113    return account;114  }115116  toICrossAccountId(): ICrossAccountId {117    return this.account;118  }119}120121const nesting = {122  toChecksumAddress(address: string): string {123    if(typeof address === 'undefined') return '';124125    if(!/^(0x)?[0-9a-f]{40}$/i.test(address)) throw new Error(`Given address "${address}" is not a valid Ethereum address.`);126127    address = address.toLowerCase().replace(/^0x/i, '');128    const addressHash = keccakAsHex(address).replace(/^0x/i, '');129    const checksumAddress = ['0x'];130131    for(let i = 0; i < address.length; i++) {132      // If ith character is 8 to f then make it uppercase133      if(parseInt(addressHash[i], 16) > 7) {134        checksumAddress.push(address[i].toUpperCase());135      } else {136        checksumAddress.push(address[i]);137      }138    }139    return checksumAddress.join('');140  },141  tokenIdToAddress(collectionId: number, tokenId: number) {142    return this.toChecksumAddress(`0xf8238ccfff8ed887463fd5e0${collectionId.toString(16).padStart(8, '0')}${tokenId.toString(16).padStart(8, '0')}`);143  },144};145146class UniqueUtil {147  static transactionStatus = {148    NOT_READY: 'NotReady',149    FAIL: 'Fail',150    SUCCESS: 'Success',151  };152153  static chainLogType = {154    EXTRINSIC: 'extrinsic',155    RPC: 'rpc',156  };157158  static getTokenAccount(token: IToken): ICrossAccountId {159    return {Ethereum: this.getTokenAddress(token)};160  }161162  static getTokenAddress(token: IToken): string {163    return nesting.tokenIdToAddress(token.collectionId, token.tokenId);164  }165166  static getDefaultLogger(): ILogger {167    return {168      log(msg: any, level = 'INFO') {169        console[level.toLocaleLowerCase() === 'error' ? 'error' : 'log'](...(Array.isArray(msg) ? msg : [msg]));170      },171      level: {172        ERROR: 'ERROR',173        WARNING: 'WARNING',174        INFO: 'INFO',175      },176    };177  }178179  static vec2str(arr: string[] | number[]) {180    return arr.map(x => String.fromCharCode(parseInt(x.toString()))).join('');181  }182183  static str2vec(string: string) {184    if(typeof string !== 'string') return string;185    return Array.from(string).map(x => x.charCodeAt(0));186  }187188  static fromSeed(seed: string, ss58Format = 42) {189    const keyring = new Keyring({type: 'sr25519', ss58Format});190    return keyring.addFromUri(seed);191  }192193  static extractCollectionIdFromCreationResult(creationResult: ITransactionResult): number {194    if(creationResult.status !== this.transactionStatus.SUCCESS) {195      throw Error('Unable to create collection!');196    }197198    let collectionId = null;199    creationResult.result.events.forEach(({event: {data, method, section}}) => {200      if((section === 'common') && (method === 'CollectionCreated')) {201        collectionId = parseInt(data[0].toString(), 10);202      }203    });204205    if(collectionId === null) {206      throw Error('No CollectionCreated event was found!');207    }208209    return collectionId;210  }211212  static extractTokensFromCreationResult(creationResult: ITransactionResult): {213    success: boolean,214    tokens: { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[],215  } {216    if(creationResult.status !== this.transactionStatus.SUCCESS) {217      throw Error('Unable to create tokens!');218    }219    let success = false;220    const tokens = [] as { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[];221    creationResult.result.events.forEach(({event: {data, method, section}}) => {222      if(method === 'ExtrinsicSuccess') {223        success = true;224      } else if((section === 'common') && (method === 'ItemCreated')) {225        tokens.push({226          collectionId: parseInt(data[0].toString(), 10),227          tokenId: parseInt(data[1].toString(), 10),228          owner: data[2].toHuman(),229          amount: data[3].toBigInt(),230        });231      }232    });233    return {success, tokens};234  }235236  static extractTokensFromBurnResult(burnResult: ITransactionResult): {237    success: boolean,238    tokens: { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[],239  } {240    if(burnResult.status !== this.transactionStatus.SUCCESS) {241      throw Error('Unable to burn tokens!');242    }243    let success = false;244    const tokens = [] as { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[];245    burnResult.result.events.forEach(({event: {data, method, section}}: any) => {246      if(method === 'ExtrinsicSuccess') {247        success = true;248      } else if((section === 'common') && (method === 'ItemDestroyed')) {249        tokens.push({250          collectionId: parseInt(data[0].toString(), 10),251          tokenId: parseInt(data[1].toString(), 10),252          owner: data[2].toHuman(),253          amount: data[3].toBigInt(),254        });255      }256    });257    return {success, tokens};258  }259260  static findCollectionInEvents(events: { event: IEvent }[], collectionId: number, expectedSection: string, expectedMethod: string): boolean {261    let eventId = null;262    events.forEach(({event: {data, method, section}}) => {263      if((section === expectedSection) && (method === expectedMethod)) {264        eventId = parseInt(data[0].toString(), 10);265      }266    });267268    if(eventId === null) {269      throw Error(`No ${expectedMethod} event was found!`);270    }271    return eventId === collectionId;272  }273274  static isTokenTransferSuccess(events: { event: IEvent }[], collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {275    const normalizeAddress = (address: string | ICrossAccountId) => {276      if(typeof address === 'string') return address;277      if('Substrate' in address) return CrossAccountId.withNormalizedSubstrate(address);278      if('Ethereum' in address) return CrossAccountId.toLowerCase(address);279      return address;280    };281    let transfer = {collectionId: null, tokenId: null, from: null, to: null, amount: 1} as any;282    events.forEach(({event: {data, method, section}}) => {283      if((section === 'common') && (method === 'Transfer')) {284        transfer = {285          collectionId: data[0].toJSON(),286          tokenId: data[1].toJSON(),287          from: normalizeAddress(data[2].toHuman()),288          to: normalizeAddress(data[3].toHuman()),289          amount: BigInt(data[4].toJSON()),290        };291      }292    });293    let isSuccess = parseInt(collectionId.toString()) === transfer.collectionId && parseInt(tokenId.toString()) === transfer.tokenId;294    isSuccess = isSuccess && JSON.stringify(normalizeAddress(fromAddressObj)) === JSON.stringify(transfer.from);295    isSuccess = isSuccess && JSON.stringify(normalizeAddress(toAddressObj)) === JSON.stringify(transfer.to);296    isSuccess = isSuccess && amount === transfer.amount;297    return isSuccess;298  }299300  static bigIntToDecimals(number: bigint, decimals = 18) {301    const numberStr = number.toString();302    const dotPos = numberStr.length - decimals;303304    if(dotPos <= 0) {305      return '0.' + '0'.repeat(Math.abs(dotPos)) + numberStr;306    } else {307      const intPart = numberStr.substring(0, dotPos);308      const fractPart = numberStr.substring(dotPos);309      return intPart + '.' + fractPart;310    }311  }312}313314class UniqueEventHelper {315  static extractIndex(index: any): [number, number] | string {316    if(index.toRawType() === '[u8;2]') return [index[0], index[1]];317    return index.toJSON();318  }319320  static extractSub(data: any, subTypes: any): { [key: string]: any } {321    let obj: any = {};322    let index = 0;323324    if(data.entries) {325      for(const [key, value] of data.entries()) {326        obj[key] = this.extractData(value, subTypes[index]);327        index++;328      }329    } else obj = data.toJSON();330331    return obj;332  }333334  static toHuman(data: any) {335    return data && data.toHuman ? data.toHuman() : `${data}`;336  }337338  static extractData(data: any, type: any): any {339    if(!type) return this.toHuman(data);340    if(['u16', 'u32'].indexOf(type.type) > -1) return data.toNumber();341    if(['u64', 'u128', 'u256'].indexOf(type.type) > -1) return data.toBigInt();342    if(type.hasOwnProperty('sub')) return this.extractSub(data, type.sub);343    return this.toHuman(data);344  }345346  public static extractEvents(events: { event: any, phase: any }[]): IEvent[] {347    const parsedEvents: IEvent[] = [];348349    events.forEach((record) => {350      const {event, phase} = record;351      const types = event.typeDef;352353      const eventData: IEvent = {354        section: event.section.toString(),355        method: event.method.toString(),356        index: this.extractIndex(event.index),357        data: [],358        phase: phase.toJSON(),359      };360361      event.data.forEach((val: any, index: number) => {362        eventData.data.push(this.extractData(val, types[index]));363      });364365      parsedEvents.push(eventData);366    });367368    return parsedEvents;369  }370}371const InvalidTypeSymbol = Symbol('Invalid type');372// eslint-disable-next-line @typescript-eslint/no-unused-vars373export type Invalid =374  | ((375    invalidType: typeof InvalidTypeSymbol,376    ..._: typeof InvalidTypeSymbol[]377  ) => typeof InvalidTypeSymbol)378  | null379  | undefined;380// Has slightly better error messages than Get381type Get2<T, P extends string, E> =382  P extends `${infer Key}.${infer Key2}` ? Key extends keyof T ? Key2 extends keyof T[Key] ? T[Key][Key2] : E : E : E;383type ForceFunction<T> = T extends (...args: any) => any ? T : (...args: any) => Invalid;384385export class ChainHelperBase {386  helperBase: any;387388  transactionStatus = UniqueUtil.transactionStatus;389  chainLogType = UniqueUtil.chainLogType;390  util: typeof UniqueUtil;391  eventHelper: typeof UniqueEventHelper;392  logger: ILogger;393  api: ApiPromise | null;394  forcedNetwork: TNetworks | null;395  network: TNetworks | null;396  wsEndpoint: string | null;397  chainLog: IUniqueHelperLog[];398  children: ChainHelperBase[];399  address: AddressGroup;400  chain: ChainGroup;401402  constructor(logger?: ILogger, helperBase?: any) {403    this.helperBase = helperBase;404405    this.util = UniqueUtil;406    this.eventHelper = UniqueEventHelper;407    if(typeof logger == 'undefined') logger = this.util.getDefaultLogger();408    this.logger = logger;409    this.api = null;410    this.forcedNetwork = null;411    this.network = null;412    this.wsEndpoint = null;413    this.chainLog = [];414    this.children = [];415    this.address = new AddressGroup(this);416    this.chain = new ChainGroup(this);417  }418419  clone(helperCls: ChainHelperBaseConstructor, options: { [key: string]: any } = {}) {420    Object.setPrototypeOf(helperCls.prototype, this);421    const newHelper = new helperCls(this.logger, options);422423    newHelper.api = this.api;424    newHelper.network = this.network;425    newHelper.forceNetwork = this.forceNetwork;426427    this.children.push(newHelper);428429    return newHelper;430  }431432  getEndpoint(): string {433    if(this.wsEndpoint === null) throw Error('No connection was established');434    return this.wsEndpoint;435  }436437  getApi(): ApiPromise {438    if(this.api === null) throw Error('API not initialized');439    return this.api;440  }441442  async subscribeEvents(expectedEvents: { section: string, names: string[] }[]) {443    const collectedEvents: IEvent[] = [];444    const unsubscribe = await this.getApi().query.system.events((events: any) => {445      const ievents = this.eventHelper.extractEvents(events);446      ievents.forEach((event) => {447        expectedEvents.forEach((e => {448          if(event.section === e.section && e.names.includes(event.method)) {449            collectedEvents.push(event);450          }451        }));452      });453    });454    return {unsubscribe: unsubscribe as any, collectedEvents};455  }456457  clearChainLog(): void {458    this.chainLog = [];459  }460461  forceNetwork(value: TNetworks): void {462    this.forcedNetwork = value;463  }464465  async connect(wsEndpoint: string, listeners?: IApiListeners) {466    if(this.api !== null) throw Error('Already connected');467    const {api, network} = await ChainHelperBase.createConnection(wsEndpoint, listeners, this.forcedNetwork);468    this.wsEndpoint = wsEndpoint;469    this.api = api;470    this.network = network;471  }472473  async disconnect() {474    for(const child of this.children) {475      child.clearApi();476    }477478    if(this.api === null) return;479    await this.api.disconnect();480    this.clearApi();481  }482483  clearApi() {484    this.api = null;485    this.network = null;486  }487488  static async detectNetwork(api: ApiPromise): Promise<TNetworks> {489    const spec = (await api.query.system.lastRuntimeUpgrade()).toJSON() as any;490    const xcmChains = ['rococo', 'westend', 'westmint', 'acala', 'karura', 'moonbeam', 'moonriver'];491492    if(xcmChains.indexOf(spec.specName) > -1) return spec.specName;493494    if(['quartz', 'unique', 'sapphire'].indexOf(spec.specName) > -1) return spec.specName;495    return 'opal';496  }497498  static async detectNetworkByWsEndpoint(wsEndpoint: string): Promise<TNetworks> {499    if(!wsEndpoint) throw new Error('wsEndpoint was not set');500    const api = new ApiPromise({provider: new WsProvider(wsEndpoint)});501    await api.isReady;502503    const network = await this.detectNetwork(api);504505    await api.disconnect();506507    return network;508  }509510  static async createConnection(wsEndpoint: string, listeners?: IApiListeners, network?: TNetworks | null): Promise<{511    api: ApiPromise;512    network: TNetworks;513  }> {514    if(typeof network === 'undefined' || network === null) network = 'opal';515    if(!wsEndpoint) throw new Error('wsEndpoint was not set');516    const supportedRPC = {517      opal: {518        unique: require('@unique-nft/opal-testnet-types/definitions').unique.rpc,519      },520      quartz: {521        unique: require('@unique-nft/quartz-mainnet-types/definitions').unique.rpc,522      },523      unique: {524        unique: require('@unique-nft/unique-mainnet-types/definitions').unique.rpc,525      },526      rococo: {},527      westend: {},528      moonbeam: {},529      moonriver: {},530      acala: {},531      karura: {},532      westmint: {},533    };534    if(!supportedRPC.hasOwnProperty(network)) network = await this.detectNetworkByWsEndpoint(wsEndpoint);535    const rpc = supportedRPC[network] as any;536537    // TODO: investigate how to replace rpc in runtime538    // api._rpcCore.addUserInterfaces(rpc);539540    const api = new ApiPromise({provider: new WsProvider(wsEndpoint), rpc});541542    await api.isReadyOrError;543544    if(typeof listeners === 'undefined') listeners = {};545    for(const event of ['connected', 'disconnected', 'error', 'ready', 'decorated']) {546      if(!listeners.hasOwnProperty(event) || typeof listeners[event as TApiAllowedListeners] === 'undefined') continue;547      api.on(event as ApiInterfaceEvents, listeners[event as TApiAllowedListeners] as (...args: any[]) => any);548    }549550    return {api, network};551  }552553  getTransactionStatus(data: { events: { event: IEvent }[], status: any }) {554    const {events, status} = data;555    if(status.isReady) {556      return this.transactionStatus.NOT_READY;557    }558    if(status.isBroadcast) {559      return this.transactionStatus.NOT_READY;560    }561    if(status.isInBlock || status.isFinalized) {562      const errors = events.filter(e => e.event.method === 'ExtrinsicFailed');563      if(errors.length > 0) {564        return this.transactionStatus.FAIL;565      }566      if(events.filter(e => e.event.method === 'ExtrinsicSuccess').length > 0) {567        return this.transactionStatus.SUCCESS;568      }569    }570571    return this.transactionStatus.FAIL;572  }573574  signTransaction(sender: TSigner, transaction: any, options: Partial<SignerOptions> | null = null, label = 'transaction') {575    const sign = (callback: any) => {576      if(options !== null) return transaction.signAndSend(sender, options, callback);577      return transaction.signAndSend(sender, callback);578    };579    // eslint-disable-next-line no-async-promise-executor580    return new Promise(async (resolve, reject) => {581      try {582        const unsub = await sign((result: any) => {583          const status = this.getTransactionStatus(result);584585          if(status === this.transactionStatus.SUCCESS) {586            this.logger.log(`${label} successful`);587            unsub();588            resolve({result, status, blockHash: result.status.asInBlock.toHuman()});589          } else if(status === this.transactionStatus.FAIL) {590            let moduleError = null;591592            if(result.hasOwnProperty('dispatchError')) {593              const dispatchError = result['dispatchError'];594595              if(dispatchError) {596                if(dispatchError.isModule) {597                  const modErr = dispatchError.asModule;598                  const errorMeta = dispatchError.registry.findMetaError(modErr);599600                  moduleError = `${errorMeta.section}.${errorMeta.name}`;601                } else if(dispatchError.isToken) {602                  moduleError = `Token: ${dispatchError.asToken}`;603                } else {604                  // May be [object Object] in case of unhandled non-unit enum605                  moduleError = `Misc: ${dispatchError.toHuman()}`;606                }607              } else {608                this.logger.log(result, this.logger.level.ERROR);609              }610            }611612            this.logger.log(`Something went wrong with ${label}. Status: ${status}`, this.logger.level.ERROR);613            unsub();614            reject({status, moduleError, result});615          }616        });617      } catch (e) {618        this.logger.log(e, this.logger.level.ERROR);619        reject(e);620      }621    });622  }623624  async signTransactionWithoutSending(signer: TSigner, tx: any) {625    const api = this.getApi();626    const signingInfo = await api.derive.tx.signingInfo(signer.address);627628    tx.sign(signer, {629      blockHash: api.genesisHash,630      genesisHash: api.genesisHash,631      runtimeVersion: api.runtimeVersion,632      nonce: signingInfo.nonce,633    });634635    return tx.toHex();636  }637638  async getPaymentInfo(signer: TSigner, tx: any, len: number | null) {639    const api = this.getApi();640    const signingInfo = await api.derive.tx.signingInfo(signer.address);641642    // We need to sign the tx because643    // unsigned transactions does not have an inclusion fee644    tx.sign(signer, {645      blockHash: api.genesisHash,646      genesisHash: api.genesisHash,647      runtimeVersion: api.runtimeVersion,648      nonce: signingInfo.nonce,649    });650651    if(len === null) {652      return (await this.callRpc('api.rpc.payment.queryInfo', [tx.toHex()])) as RuntimeDispatchInfo;653    } else {654      return (await api.call.transactionPaymentApi.queryInfo(tx, len)) as RuntimeDispatchInfo;655    }656  }657658  constructApiCall(apiCall: string, params: any[]) {659    if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);660    let call = this.getApi() as any;661    for(const part of apiCall.slice(4).split('.')) {662      call = call[part];663      if(!call) {664        const advice = part.includes('_') ? ' Looks like it needs to be converted to camel case.' : '';665        throw Error(`Function ${part} of api call ${apiCall} not found.${advice}`);666      }667    }668    return call(...params);669  }670671  encodeApiCall(apiCall: string, params: any[]) {672    return this.constructApiCall(apiCall, params).method.toHex();673  }674675  async executeExtrinsic<676    E extends string,677    V extends (678      ...args: any) => any = ForceFunction<679        Get2<680          AugmentedSubmittables<'promise'>,681          E, (...args: any) => Invalid682        >683      >684  >(685    sender: TSigner,686    extrinsic: `api.tx.${E}`,687    params: Parameters<V>,688    expectSuccess = true,689    options: Partial<SignerOptions> | null = null,/*, failureMessage='expected success'*/690  ): Promise<ITransactionResult> {691    if(this.api === null) throw Error('API not initialized');692693    const startTime = (new Date()).getTime();694    let result: ITransactionResult;695    let events: IEvent[] = [];696    try {697      result = await this.signTransaction(sender, this.constructApiCall(extrinsic, params), options, extrinsic) as ITransactionResult;698      events = this.eventHelper.extractEvents(result.result.events);699      const errorEvent = events.find((event) => event.method == 'ExecutedFailed' || event.method == 'CreatedFailed');700      if(errorEvent)701        throw Error(errorEvent.method + ': ' + extrinsic);702    }703    catch (e) {704      if(!(e as object).hasOwnProperty('status')) throw e;705      result = e as ITransactionResult;706    }707708    const endTime = (new Date()).getTime();709710    const log = {711      executedAt: endTime,712      executionTime: endTime - startTime,713      type: this.chainLogType.EXTRINSIC,714      status: result.status,715      call: extrinsic,716      signer: this.getSignerAddress(sender),717      params,718    } as IUniqueHelperLog;719720    let errorMessage = '';721722    if(result.status !== this.transactionStatus.SUCCESS) {723      if(result.moduleError) {724        errorMessage = typeof result.moduleError === 'string'725          ? result.moduleError726          : `${Object.keys(result.moduleError)[0]}: ${Object.values(result.moduleError)[0]}`;727        log.moduleError = errorMessage;728      }729      else if(result.result.dispatchError) log.dispatchError = result.result.dispatchError;730    }731    if(events.length > 0) log.events = events;732733    this.chainLog.push(log);734735    if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) {736      if(result.moduleError) throw Error(`${errorMessage}`);737      else if(result.result.dispatchError) throw Error(JSON.stringify(result.result.dispatchError));738    }739    return result as any;740  }741  executeExtrinsicUncheckedWeight<742      E extends string,743      V extends (744         ...args: any) => any = ForceFunction<745            Get2<746               AugmentedSubmittables<'promise'>,747               E, (...args: any) => Invalid748            >749         >750   >(751    _sender: TSigner,752    _extrinsic: `api.tx.${E}`,753    _params: Parameters<V>,754    _expectSuccess = true,755    _options: Partial<SignerOptions> | null = null,/*, failureMessage='expected success'*/756  ): Promise<ITransactionResult> {757    throw new Error('executeExtrinsicUncheckedWeight only supported in sudo');758  }759760  async callRpc761  // TODO: make it strongly typed, or use api.query/api.rpc directly762  // <763  // K extends 'rpc' | 'query',764  // E extends string,765  // V extends (...args: any) => any = ForceFunction<766  //   Get2<767  //     K extends 'rpc' ? DecoratedRpc<'promise', RpcInterface> : QueryableStorage<'promise'>,768  //     E, (...args: any) => Invalid<'not found'>769  //   >770  // >,771  // P = Parameters<V>,772  // >773  (rpc: string, params?: any[]): Promise<any> {774775    if(typeof params === 'undefined') params = [] as any;776    if(this.api === null) throw Error('API not initialized');777    if(!rpc.startsWith('api.rpc.') && !rpc.startsWith('api.query.')) throw Error(`${rpc} is not RPC call`);778779    const startTime = (new Date()).getTime();780    let result;781    let error = null;782    const log = {783      type: this.chainLogType.RPC,784      call: rpc,785      params,786    } as any as IUniqueHelperLog;787788    try {789      result = await this.constructApiCall(rpc, params as any);790    }791    catch (e) {792      error = e;793    }794795    const endTime = (new Date()).getTime();796797    log.executedAt = endTime;798    log.status = (error === null ? this.transactionStatus.SUCCESS : this.transactionStatus.FAIL) as 'Fail' | 'Success';799    log.executionTime = endTime - startTime;800801    this.chainLog.push(log);802803    if(error !== null) throw error;804805    return result;806  }807808  getSignerAddress(signer: IKeyringPair | string): string {809    if(typeof signer === 'string') return signer;810    return signer.address;811  }812813  fetchAllPalletNames(): string[] {814    if(this.api === null) throw Error('API not initialized');815    return this.api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase()).sort();816  }817818  fetchMissingPalletNames(requiredPallets: readonly string[]): string[] {819    const palletNames = this.fetchAllPalletNames();820    return requiredPallets.filter(p => !palletNames.includes(p));821  }822}823824825export class HelperGroup<T extends ChainHelperBase> {826  helper: T;827828  constructor(uniqueHelper: T) {829    this.helper = uniqueHelper;830  }831}832833834class CollectionGroup extends HelperGroup<UniqueHelper> {835  /**836 * Get number of blocks when sponsored transaction is available.837 *838 * @param collectionId ID of collection839 * @param tokenId ID of token840 * @param addressObj address for which the sponsorship is checked841 * @example await getTokenNextSponsored(1, 2, {Substrate: '5DfhbVfww7ThF8q6f3...'});842 * @returns number of blocks or null if sponsorship hasn't been set843 */844  async getTokenNextSponsored(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<number | null> {845    return (await this.helper.callRpc('api.rpc.unique.nextSponsored', [collectionId, addressObj, tokenId])).toJSON();846  }847848  /**849   * Get the number of created collections.850   *851   * @returns number of created collections852   */853  async getTotalCount(): Promise<number> {854    return (await this.helper.callRpc('api.rpc.unique.collectionStats')).created.toNumber();855  }856857  /**858   * Get information about the collection with additional data,859   * including the number of tokens it contains, its administrators,860   * the normalized address of the collection's owner, and decoded name and description.861   *862   * @param collectionId ID of collection863   * @example await getData(2)864   * @returns collection information object865   */866  async getData(collectionId: number): Promise<{867    id: number;868    name: string;869    description: string;870    tokensCount: number;871    admins: CrossAccountId[];872    normalizedOwner: TSubstrateAccount;873    raw: any874  } | null> {875    const collection = await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId]);876    const humanCollection = collection.toHuman(), collectionData = {877      id: collectionId, name: null, description: null, tokensCount: 0, admins: [],878      raw: humanCollection,879    } as any, jsonCollection = collection.toJSON();880    if(humanCollection === null) return null;881    collectionData.raw.limits = jsonCollection.limits;882    collectionData.raw.permissions = jsonCollection.permissions;883    collectionData.normalizedOwner = this.helper.address.normalizeSubstrate(collectionData.raw.owner);884    for(const key of ['name', 'description']) {885      collectionData[key] = this.helper.util.vec2str(humanCollection[key]);886    }887888    collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode))889      ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId)890      : 0;891    collectionData.admins = await this.getAdmins(collectionId);892893    return collectionData;894  }895896  /**897   * Get the addresses of the collection's administrators, optionally normalized.898   *899   * @param collectionId ID of collection900   * @param normalize whether to normalize the addresses to the default ss58 format901   * @example await getAdmins(1)902   * @returns array of administrators903   */904  async getAdmins(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {905    const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman() as ICrossAccountId[];906907    return normalize908      ? admins.map(address => CrossAccountId.withNormalizedSubstrate(address))909      : admins;910  }911912  /**913   * Get the addresses added to the collection allow-list, optionally normalized.914   * @param collectionId ID of collection915   * @param normalize whether to normalize the addresses to the default ss58 format916   * @example await getAllowList(1)917   * @returns array of allow-listed addresses918   */919  async getAllowList(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {920    const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman() as ICrossAccountId[];921    return normalize922      ? allowListed.map(address => CrossAccountId.withNormalizedSubstrate(address))923      : allowListed;924  }925926  /**927   * Get the effective limits of the collection instead of null for default values928   *929   * @param collectionId ID of collection930   * @example await getEffectiveLimits(2)931   * @returns object of collection limits932   */933  async getEffectiveLimits(collectionId: number): Promise<ICollectionLimits> {934    return (await this.helper.callRpc('api.rpc.unique.effectiveCollectionLimits', [collectionId])).toJSON();935  }936937  /**938   * Burns the collection if the signer has sufficient permissions and collection is empty.939   *940   * @param signer keyring of signer941   * @param collectionId ID of collection942   * @example await helper.collection.burn(aliceKeyring, 3);943   * @returns ```true``` if extrinsic success, otherwise ```false```944   */945  async burn(signer: TSigner, collectionId: number): Promise<boolean> {946    const result = await this.helper.executeExtrinsic(947      signer,948      'api.tx.unique.destroyCollection', [collectionId],949      true,950    );951952    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed');953  }954955  /**956   * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.957   *958   * @param signer keyring of signer959   * @param collectionId ID of collection960   * @param sponsorAddress Sponsor substrate address961   * @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")962   * @returns ```true``` if extrinsic success, otherwise ```false```963   */964  async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise<boolean> {965    const result = await this.helper.executeExtrinsic(966      signer,967      'api.tx.unique.setCollectionSponsor', [collectionId, sponsorAddress],968      true,969    );970971    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorSet');972  }973974  /**975   * Confirms consent to sponsor the collection on behalf of the signer.976   *977   * @param signer keyring of signer978   * @param collectionId ID of collection979   * @example confirmSponsorship(aliceKeyring, 10)980   * @returns ```true``` if extrinsic success, otherwise ```false```981   */982  async confirmSponsorship(signer: TSigner, collectionId: number): Promise<boolean> {983    const result = await this.helper.executeExtrinsic(984      signer,985      'api.tx.unique.confirmSponsorship', [collectionId],986      true,987    );988989    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'SponsorshipConfirmed');990  }991992  /**993   * Removes the sponsor of a collection, regardless if it consented or not.994   *995   * @param signer keyring of signer996   * @param collectionId ID of collection997   * @example removeSponsor(aliceKeyring, 10)998   * @returns ```true``` if extrinsic success, otherwise ```false```999   */1000  async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {1001    const result = await this.helper.executeExtrinsic(1002      signer,1003      'api.tx.unique.removeCollectionSponsor', [collectionId],1004      true,1005    );10061007    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorRemoved');1008  }10091010  /**1011   * Sets the limits of the collection. At least one limit must be specified for a correct call.1012   *1013   * @param signer keyring of signer1014   * @param collectionId ID of collection1015   * @param limits collection limits object1016   * @example1017   * await setLimits(1018   *   aliceKeyring,1019   *   10,1020   *   {1021   *     sponsorTransferTimeout: 0,1022   *     ownerCanDestroy: false1023   *   }1024   * )1025   * @returns ```true``` if extrinsic success, otherwise ```false```1026   */1027  async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise<boolean> {1028    const result = await this.helper.executeExtrinsic(1029      signer,1030      'api.tx.unique.setCollectionLimits', [collectionId, limits],1031      true,1032    );10331034    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionLimitSet');1035  }10361037  /**1038   * Changes the owner of the collection to the new Substrate address.1039   *1040   * @param signer keyring of signer1041   * @param collectionId ID of collection1042   * @param ownerAddress substrate address of new owner1043   * @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")1044   * @returns ```true``` if extrinsic success, otherwise ```false```1045   */1046  async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise<boolean> {1047    const result = await this.helper.executeExtrinsic(1048      signer,1049      'api.tx.unique.changeCollectionOwner', [collectionId, ownerAddress],1050      true,1051    );10521053    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionOwnerChanged');1054  }10551056  /**1057   * Adds a collection administrator.1058   *1059   * @param signer keyring of signer1060   * @param collectionId ID of collection1061   * @param adminAddressObj Administrator address (substrate or ethereum)1062   * @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})1063   * @returns ```true``` if extrinsic success, otherwise ```false```1064   */1065  async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {1066    const result = await this.helper.executeExtrinsic(1067      signer,1068      'api.tx.unique.addCollectionAdmin', [collectionId, adminAddressObj],1069      true,1070    );10711072    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminAdded');1073  }10741075  /**1076   * Removes a collection administrator.1077   *1078   * @param signer keyring of signer1079   * @param collectionId ID of collection1080   * @param adminAddressObj Administrator address (substrate or ethereum)1081   * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})1082   * @returns ```true``` if extrinsic success, otherwise ```false```1083   */1084  async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {1085    const result = await this.helper.executeExtrinsic(1086      signer,1087      'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj],1088      true,1089    );10901091    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminRemoved');1092  }10931094  /**1095   * Check if user is in allow list.1096   *1097   * @param collectionId ID of collection1098   * @param user Account to check1099   * @example await getAdmins(1)1100   * @returns is user in allow list1101   */1102  async allowed(collectionId: number, user: ICrossAccountId): Promise<boolean> {1103    return (await this.helper.callRpc('api.rpc.unique.allowed', [collectionId, user])).toJSON();1104  }11051106  /**1107   * Adds an address to allow list1108   * @param signer keyring of signer1109   * @param collectionId ID of collection1110   * @param addressObj address to add to the allow list1111   * @returns ```true``` if extrinsic success, otherwise ```false```1112   */1113  async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {1114    const result = await this.helper.executeExtrinsic(1115      signer,1116      'api.tx.unique.addToAllowList', [collectionId, addressObj],1117      true,1118    );11191120    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressAdded');1121  }11221123  /**1124   * Removes an address from allow list1125   *1126   * @param signer keyring of signer1127   * @param collectionId ID of collection1128   * @param addressObj address to remove from the allow list1129   * @returns ```true``` if extrinsic success, otherwise ```false```1130   */1131  async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {1132    const result = await this.helper.executeExtrinsic(1133      signer,1134      'api.tx.unique.removeFromAllowList', [collectionId, addressObj],1135      true,1136    );11371138    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressRemoved');1139  }11401141  /**1142   * Sets onchain permissions for selected collection.1143   *1144   * @param signer keyring of signer1145   * @param collectionId ID of collection1146   * @param permissions collection permissions object1147   * @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}});1148   * @returns ```true``` if extrinsic success, otherwise ```false```1149   */1150  async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise<boolean> {1151    const result = await this.helper.executeExtrinsic(1152      signer,1153      'api.tx.unique.setCollectionPermissions', [collectionId, permissions],1154      true,1155    );11561157    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPermissionSet');1158  }11591160  /**1161   * Enables nesting for selected collection. If `restricted` set, you can nest only tokens from specified collections.1162   *1163   * @param signer keyring of signer1164   * @param collectionId ID of collection1165   * @param permissions nesting permissions object1166   * @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true});1167   * @returns ```true``` if extrinsic success, otherwise ```false```1168   */1169  async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise<boolean> {1170    return await this.setPermissions(signer, collectionId, {nesting: permissions});1171  }11721173  /**1174   * Disables nesting for selected collection.1175   *1176   * @param signer keyring of signer1177   * @param collectionId ID of collection1178   * @example disableNesting(aliceKeyring, 10);1179   * @returns ```true``` if extrinsic success, otherwise ```false```1180   */1181  async disableNesting(signer: TSigner, collectionId: number): Promise<boolean> {1182    return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}});1183  }11841185  /**1186   * Sets onchain properties to the collection.1187   *1188   * @param signer keyring of signer1189   * @param collectionId ID of collection1190   * @param properties array of property objects1191   * @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]);1192   * @returns ```true``` if extrinsic success, otherwise ```false```1193   */1194  async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise<boolean> {1195    const result = await this.helper.executeExtrinsic(1196      signer,1197      'api.tx.unique.setCollectionProperties', [collectionId, properties],1198      true,1199    );12001201    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');1202  }12031204  /**1205   * Get collection properties.1206   *1207   * @param collectionId ID of collection1208   * @param propertyKeys optionally filter the returned properties to only these keys1209   * @example getProperties(1219, ['location', 'date', 'time', 'isParadise']);1210   * @returns array of key-value pairs1211   */1212  async getProperties(collectionId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1213    return (await this.helper.callRpc('api.rpc.unique.collectionProperties', [collectionId, propertyKeys])).toHuman();1214  }12151216  async getPropertiesConsumedSpace(collectionId: number): Promise<number> {1217    const api = this.helper.getApi();1218    const props = (await api.query.common.collectionProperties(collectionId)).toJSON();12191220    return (props! as any).consumedSpace;1221  }12221223  async getCollectionOptions(collectionId: number) {1224    return (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1225  }12261227  /**1228   * Deletes onchain properties from the collection.1229   *1230   * @param signer keyring of signer1231   * @param collectionId ID of collection1232   * @param propertyKeys array of property keys to delete1233   * @example deleteProperties(aliceKeyring, 10, ["gender", "age"]);1234   * @returns ```true``` if extrinsic success, otherwise ```false```1235   */1236  async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise<boolean> {1237    const result = await this.helper.executeExtrinsic(1238      signer,1239      'api.tx.unique.deleteCollectionProperties', [collectionId, propertyKeys],1240      true,1241    );12421243    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted');1244  }12451246  /**1247   * Changes the owner of the token.1248   *1249   * @param signer keyring of signer1250   * @param collectionId ID of collection1251   * @param tokenId ID of token1252   * @param addressObj address of a new owner1253   * @param amount amount of tokens to be transfered. For NFT must be set to 1n1254   * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1255   * @returns true if the token success, otherwise false1256   */1257  async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount = 1n): Promise<boolean> {1258    const result = await this.helper.executeExtrinsic(1259      signer,1260      'api.tx.unique.transfer', [addressObj, collectionId, tokenId, amount],1261      true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1262    );12631264    return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount);1265  }12661267  /**1268   *1269   * Change ownership of a token(s) on behalf of the owner.1270   *1271   * @param signer keyring of signer1272   * @param collectionId ID of collection1273   * @param tokenId ID of token1274   * @param fromAddressObj address on behalf of which the token will be sent1275   * @param toAddressObj new token owner1276   * @param amount amount of tokens to be transfered. For NFT must be set to 1n1277   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg"}, {Ethereum: "0x9F0583DbB85..."})1278   * @returns true if the token success, otherwise false1279   */1280  async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {1281    const result = await this.helper.executeExtrinsic(1282      signer,1283      'api.tx.unique.transferFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],1284      true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1285    );1286    return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1287  }12881289  /**1290   *1291   * Destroys a concrete instance of NFT/RFT or burns a specified amount of fungible tokens.1292   *1293   * @param signer keyring of signer1294   * @param collectionId ID of collection1295   * @param tokenId ID of token1296   * @param amount amount of tokens to be burned. For NFT must be set to 1n1297   * @example burnToken(aliceKeyring, 10, 5);1298   * @returns ```true``` if the extrinsic is successful, otherwise ```false```1299   */1300  async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount = 1n): Promise<boolean> {1301    const burnResult = await this.helper.executeExtrinsic(1302      signer,1303      'api.tx.unique.burnItem', [collectionId, tokenId, amount],1304      true, // `Unable to burn token for ${label}`,1305    );1306    const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1307    if(burnedTokens.tokens.length > 1) throw Error('Burned multiple tokens');1308    return burnedTokens.success;1309  }13101311  /**1312   * Destroys a concrete instance of NFT on behalf of the owner1313   *1314   * @param signer keyring of signer1315   * @param collectionId ID of collection1316   * @param tokenId ID of token1317   * @param fromAddressObj address on behalf of which the token will be burnt1318   * @param amount amount of tokens to be burned. For NFT must be set to 1n1319   * @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."})1320   * @returns ```true``` if extrinsic success, otherwise ```false```1321   */1322  async burnTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {1323    const burnResult = await this.helper.executeExtrinsic(1324      signer,1325      'api.tx.unique.burnFrom', [collectionId, fromAddressObj, tokenId, amount],1326      true, // `Unable to burn token from for ${label}`,1327    );1328    const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1329    return burnedTokens.success && burnedTokens.tokens.length > 0;1330  }13311332  /**1333   * Set, change, or remove approved address to transfer the ownership of the NFT.1334   *1335   * @param signer keyring of signer1336   * @param collectionId ID of collection1337   * @param tokenId ID of token1338   * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens1339   * @param amount amount of token to be approved. For NFT must be set to 1n1340   * @returns ```true``` if extrinsic success, otherwise ```false```1341   */1342  async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {1343    const approveResult = await this.helper.executeExtrinsic(1344      signer,1345      'api.tx.unique.approve', [toAddressObj, collectionId, tokenId, amount],1346      true, // `Unable to approve token for ${label}`,1347    );13481349    return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');1350  }13511352  /**1353   * Set, change, or remove approved address to transfer the ownership of the NFT from eth mirror.1354   *1355   * @param signer keyring of signer1356   * @param collectionId ID of collection1357   * @param tokenId ID of token1358   * @param fromAddressObj Signer's Ethereum address containing her tokens1359   * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens1360   * @param amount amount of token to be approved. For NFT must be set to 1n1361   * @returns ```true``` if extrinsic success, otherwise ```false```1362   */1363  async approveTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {1364    const approveResult = await this.helper.executeExtrinsic(1365      signer,1366      'api.tx.unique.approveFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],1367      true, // `Unable to approve token for ${label}`,1368    );13691370    return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');1371  }13721373  /**1374   * Set, change, or remove approved address to transfer the ownership of the NFT from eth mirror.1375   *1376   * @param signer keyring of signer1377   * @param collectionId ID of collection1378   * @param tokenId ID of token1379   * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens1380   * @param amount amount of token to be approved. For NFT must be set to 1n1381   * @returns ```true``` if extrinsic success, otherwise ```false```1382   */1383  async approveTokenFromEth(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {1384    const ethMirror = CrossAccountId.fromKeyring(signer).toEthereum().toICrossAccountId();1385    return await this.approveTokenFrom(signer, collectionId, tokenId, ethMirror, toAddressObj, amount);1386  }13871388  /**1389   * Get the amount of token pieces approved to transfer or burn. Normally 0.1390   *1391   * @param collectionId ID of collection1392   * @param tokenId ID of token1393   * @param toAccountObj address which is approved to use token pieces1394   * @param fromAccountObj address which may have allowed the use of its owned tokens1395   * @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."})1396   * @returns number of approved to transfer pieces1397   */1398  async getTokenApprovedPieces(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId, fromAccountObj: ICrossAccountId): Promise<bigint> {1399    return (await this.helper.callRpc('api.rpc.unique.allowance', [collectionId, fromAccountObj, toAccountObj, tokenId])).toBigInt();1400  }14011402  /**1403   * Get the last created token ID in a collection1404   *1405   * @param collectionId ID of collection1406   * @example getLastTokenId(10);1407   * @returns id of the last created token1408   */1409  async getLastTokenId(collectionId: number): Promise<number> {1410    return (await this.helper.callRpc('api.rpc.unique.lastTokenId', [collectionId])).toNumber();1411  }14121413  /**1414   * Check if token exists1415   *1416   * @param collectionId ID of collection1417   * @param tokenId ID of token1418   * @example doesTokenExist(10, 20);1419   * @returns true if the token exists, otherwise false1420   */1421  async doesTokenExist(collectionId: number, tokenId: number): Promise<boolean> {1422    return (await this.helper.callRpc('api.rpc.unique.tokenExists', [collectionId, tokenId])).toJSON();1423  }1424}14251426class NFTnRFT extends CollectionGroup {1427  /**1428   * Get tokens owned by account1429   *1430   * @param collectionId ID of collection1431   * @param addressObj tokens owner1432   * @example getTokensByAddress(10, {Substrate: "5DyN4Y92vZCjv38fg..."})1433   * @returns array of token ids owned by account1434   */1435  async getTokensByAddress(collectionId: number, addressObj: ICrossAccountId): Promise<number[]> {1436    return (await this.helper.callRpc('api.rpc.unique.accountTokens', [collectionId, addressObj])).toJSON();1437  }14381439  /**1440   * Get token data1441   *1442   * @param collectionId ID of collection1443   * @param tokenId ID of token1444   * @param propertyKeys optionally filter the token properties to only these keys1445   * @param blockHashAt optionally query the data at some block with this hash1446   * @example getToken(10, 5);1447   * @returns human readable token data1448   */1449  async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{1450    properties: IProperty[];1451    owner: ICrossAccountId;1452    normalizedOwner: ICrossAccountId;1453  } | null> {1454    let args;1455    if(typeof blockHashAt === 'undefined') {1456      args = [collectionId, tokenId];1457    }1458    else {1459      if(propertyKeys.length == 0) {1460        const collection = (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1461        if(!collection) return null;1462        propertyKeys = collection.tokenPropertyPermissions.map((x: ITokenPropertyPermission) => x.key);1463      }1464      args = [collectionId, tokenId, propertyKeys, blockHashAt];1465    }1466    const tokenData = (await this.helper.callRpc('api.rpc.unique.tokenData', args)).toHuman();1467    if(tokenData === null || tokenData.owner === null) return null;1468    tokenData.normalizedOwner = CrossAccountId.withNormalizedSubstrate(tokenData.owner);1469    return tokenData;1470  }14711472  /**1473   * Get token's owner1474   * @param collectionId ID of collection1475   * @param tokenId ID of token1476   * @param blockHashAt optionally query the data at the block with this hash1477   * @example getTokenOwner(10, 5);1478   * @returns Address in CrossAccountId format, e.g. {Substrate: "5DnSF6RRjwteE3BrCj..."}1479   */1480  async getTokenOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<ICrossAccountId> {1481    let owner;1482    if(typeof blockHashAt === 'undefined') {1483      owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId]);1484    } else {1485      owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId, blockHashAt]);1486    }1487    return CrossAccountId.fromLowerCaseKeys(owner.toJSON()).toICrossAccountId();1488  }14891490  /**1491   * Recursively find the address that owns the token1492   * @param collectionId ID of collection1493   * @param tokenId ID of token1494   * @param blockHashAt1495   * @example getTokenTopmostOwner(10, 5);1496   * @returns address in CrossAccountId format, e.g. {Substrate: "5DyN4Y92vZCjv38fg..."}1497   */1498  async getTokenTopmostOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<ICrossAccountId | null> {1499    let owner;1500    if(typeof blockHashAt === 'undefined') {1501      owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId]);1502    } else {1503      owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId, blockHashAt]);1504    }15051506    if(owner === null) return null;15071508    return owner.toHuman();1509  }15101511  /**1512   * Nest one token into another1513   * @param signer keyring of signer1514   * @param tokenObj token to be nested1515   * @param rootTokenObj token to be parent1516   * @example nestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4});1517   * @returns ```true``` if extrinsic success, otherwise ```false```1518   */1519  async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise<boolean> {1520    const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1521    const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress);1522    if(!result) {1523      throw Error('Unable to nest token!');1524    }1525    return result;1526  }15271528  /**1529     * Remove token from nested state1530     * @param signer keyring of signer1531     * @param tokenObj token to unnest1532     * @param rootTokenObj parent of a token1533     * @param toAddressObj address of a new token owner1534     * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});1535     * @returns ```true``` if extrinsic success, otherwise ```false```1536     */1537  async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {1538    const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1539    const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);1540    if(!result) {1541      throw Error('Unable to unnest token!');1542    }1543    return result;1544  }15451546  /**1547   * Set permissions to change token properties1548   *1549   * @param signer keyring of signer1550   * @param collectionId ID of collection1551   * @param permissions permissions to change a property by the collection admin or token owner1552   * @example setTokenPropertyPermissions(1553   *   aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}]1554   * )1555   * @returns true if extrinsic success otherwise false1556   */1557  async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise<boolean> {1558    const result = await this.helper.executeExtrinsic(1559      signer,1560      'api.tx.unique.setTokenPropertyPermissions', [collectionId, permissions],1561      true,1562    );15631564    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');1565  }15661567  /**1568   * Get token property permissions.1569   *1570   * @param collectionId ID of collection1571   * @param propertyKeys optionally filter the returned property permissions to only these keys1572   * @example getPropertyPermissions(1219, ['location', 'date', 'time', 'isParadise']);1573   * @returns array of key-permission pairs1574   */1575  async getPropertyPermissions(collectionId: number, propertyKeys: string[] | null = null): Promise<ITokenPropertyPermission[]> {1576    return (await this.helper.callRpc('api.rpc.unique.propertyPermissions', [collectionId, ...(propertyKeys === null ? [] : [propertyKeys])])).toHuman();1577  }15781579  /**1580   * Set token properties1581   *1582   * @param signer keyring of signer1583   * @param collectionId ID of collection1584   * @param tokenId ID of token1585   * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection1586   * @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}])1587   * @returns ```true``` if extrinsic success, otherwise ```false```1588   */1589  async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise<boolean> {1590    const result = await this.helper.executeExtrinsic(1591      signer,1592      'api.tx.unique.setTokenProperties', [collectionId, tokenId, properties],1593      true,1594    );15951596    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');1597  }15981599  /**1600   * Get properties, metadata assigned to a token.1601   *1602   * @param collectionId ID of collection1603   * @param tokenId ID of token1604   * @param propertyKeys optionally filter the returned properties to only these keys1605   * @example getTokenProperties(1219, ['location', 'date', 'time', 'isParadise']);1606   * @returns array of key-value pairs1607   */1608  async getTokenProperties(collectionId: number, tokenId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1609    return (await this.helper.callRpc('api.rpc.unique.tokenProperties', [collectionId, tokenId, propertyKeys])).toHuman();1610  }16111612  /**1613   * Delete the provided properties of a token1614   * @param signer keyring of signer1615   * @param collectionId ID of collection1616   * @param tokenId ID of token1617   * @param propertyKeys property keys to be deleted1618   * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"])1619   * @returns ```true``` if extrinsic success, otherwise ```false```1620   */1621  async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise<boolean> {1622    const result = await this.helper.executeExtrinsic(1623      signer,1624      'api.tx.unique.deleteTokenProperties', [collectionId, tokenId, propertyKeys],1625      true,1626    );16271628    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted');1629  }16301631  /**1632   * Mint new collection1633   *1634   * @param signer keyring of signer1635   * @param collectionOptions basic collection options and properties1636   * @param mode NFT or RFT type of a collection1637   * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")1638   * @returns object of the created collection1639   */1640  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueBaseCollection> {1641    collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1642    collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};1643    for(const key of ['name', 'description', 'tokenPrefix']) {1644      if(typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);1645    }16461647    let flags = 0;1648    // convert CollectionFlags to number and join them in one number1649    if(collectionOptions.flags) {1650      for(let i = 0; i < collectionOptions.flags.length; i++){1651        const flag = collectionOptions.flags[i];1652        flags = flags | flag;1653      }1654    }1655    collectionOptions.flags = [flags];16561657    const creationResult = await this.helper.executeExtrinsic(1658      signer,1659      'api.tx.unique.createCollectionEx', [collectionOptions],1660      true, // errorLabel,1661    );1662    return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));1663  }16641665  getCollectionObject(_collectionId: number): any {1666    return null;1667  }16681669  getTokenObject(_collectionId: number, _tokenId: number): any {1670    return null;1671  }16721673  /**1674   * Tells whether the given `owner` approves the `operator`.1675   * @param collectionId ID of collection1676   * @param owner owner address1677   * @param operator operator addrees1678   * @returns true if operator is enabled1679   */1680  async allowanceForAll(collectionId: number, owner: ICrossAccountId, operator: ICrossAccountId): Promise<boolean> {1681    return (await this.helper.callRpc('api.rpc.unique.allowanceForAll', [collectionId, owner, operator])).toJSON();1682  }16831684  /** Sets or unsets the approval of a given operator.1685   *  The `operator` is allowed to transfer all tokens of the `caller` on their behalf.1686   *  @param operator Operator1687   *  @param approved Should operator status be granted or revoked?1688   *  @returns ```true``` if extrinsic success, otherwise ```false```1689   */1690  async setAllowanceForAll(signer: TSigner, collectionId: number, operator: ICrossAccountId, approved: boolean): Promise<boolean> {1691    const result = await this.helper.executeExtrinsic(1692      signer,1693      'api.tx.unique.setAllowanceForAll', [collectionId, operator, approved],1694      true,1695    );1696    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'ApprovedForAll');1697  }1698}169917001701class NFTGroup extends NFTnRFT {1702  /**1703   * Get collection object1704   * @param collectionId ID of collection1705   * @example getCollectionObject(2);1706   * @returns instance of UniqueNFTCollection1707   */1708  override getCollectionObject(collectionId: number): UniqueNFTCollection {1709    return new UniqueNFTCollection(collectionId, this.helper);1710  }17111712  /**1713   * Get token object1714   * @param collectionId ID of collection1715   * @param tokenId ID of token1716   * @example getTokenObject(10, 5);1717   * @returns instance of UniqueNFTToken1718   */1719  override getTokenObject(collectionId: number, tokenId: number): UniqueNFToken {1720    return new UniqueNFToken(tokenId, this.getCollectionObject(collectionId));1721  }17221723  /**1724   * Is token approved to transfer1725   * @param collectionId ID of collection1726   * @param tokenId ID of token1727   * @param toAccountObj address to be approved1728   * @returns ```true``` if extrinsic success, otherwise ```false```1729   */1730  async isTokenApproved(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId): Promise<boolean> {1731    return (await this.getTokenApprovedPieces(collectionId, tokenId, toAccountObj, (await this.getTokenOwner(collectionId, tokenId)))) === 1n;1732  }17331734  /**1735   * Changes the owner of the token.1736   *1737   * @param signer keyring of signer1738   * @param collectionId ID of collection1739   * @param tokenId ID of token1740   * @param addressObj address of a new owner1741   * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1742   * @returns ```true``` if extrinsic success, otherwise ```false```1743   */1744  override async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<boolean> {1745    return await super.transferToken(signer, collectionId, tokenId, addressObj, 1n);1746  }17471748  /**1749   *1750   * Change ownership of a NFT on behalf of the owner.1751   *1752   * @param signer keyring of signer1753   * @param collectionId ID of collection1754   * @param tokenId ID of token1755   * @param fromAddressObj address on behalf of which the token will be sent1756   * @param toAddressObj new token owner1757   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Ethereum: "0x9F0583DbB85..."})1758   * @returns ```true``` if extrinsic success, otherwise ```false```1759   */1760  override async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId): Promise<boolean> {1761    return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, 1n);1762  }17631764  /**1765   * Get tokens nested in the provided token1766   * @param collectionId ID of collection1767   * @param tokenId ID of token1768   * @param blockHashAt optionally query the data at the block with this hash1769   * @example getTokenChildren(10, 5);1770   * @returns tokens whose depth of nesting is <= 51771   */1772  async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {1773    let children;1774    if(typeof blockHashAt === 'undefined') {1775      children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId]);1776    } else {1777      children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId, blockHashAt]);1778    }17791780    return children.toJSON().map((x: any) => ({collectionId: x.collection, tokenId: x.token}));1781  }17821783  /**1784   * Mint new collection1785   * @param signer keyring of signer1786   * @param collectionOptions Collection options1787   * @example1788   * mintCollection(aliceKeyring, {1789   *   name: 'New',1790   *   description: 'New collection',1791   *   tokenPrefix: 'NEW',1792   * })1793   * @returns object of the created collection1794   */1795  override async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueNFTCollection> {1796    return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection;1797  }17981799  /**1800   * Mint new token1801   * @param signer keyring of signer1802   * @param data token data1803   * @returns created token object1804   */1805  async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise<UniqueNFToken> {1806    const creationResult = await this.helper.executeExtrinsic(1807      signer,1808      'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1809        NFT: {1810          properties: data.properties,1811        },1812      }],1813      true,1814    );1815    const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1816    if(createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1817    if(createdTokens.tokens.length < 1) throw Error('No tokens minted');1818    return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1819  }18201821  /**1822   * Mint multiple NFT tokens1823   * @param signer keyring of signer1824   * @param collectionId ID of collection1825   * @param tokens array of tokens with owner and properties1826   * @example1827   * mintMultipleTokens(aliceKeyring, 10, [{1828   *     owner: {Substrate: "5DyN4Y92vZCjv38fg..."},1829   *     properties: [{key: "gender", value: "male"},{key: "age", value: "45"}],1830   *   },{1831   *     owner: {Ethereum: "0x9F0583DbB855d..."},1832   *     properties: [{key: "gender", value: "female"},{key: "age", value: "22"}],1833   * }]);1834   * @returns ```true``` if extrinsic success, otherwise ```false```1835   */1836  async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: { owner: ICrossAccountId, properties?: IProperty[] }[]): Promise<UniqueNFToken[]> {1837    const creationResult = await this.helper.executeExtrinsic(1838      signer,1839      'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}],1840      true,1841    );1842    const collection = this.getCollectionObject(collectionId);1843    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1844  }18451846  /**1847   * Mint multiple NFT tokens with one owner1848   * @param signer keyring of signer1849   * @param collectionId ID of collection1850   * @param owner tokens owner1851   * @param tokens array of tokens with owner and properties1852   * @example1853   * mintMultipleTokensWithOneOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...", [{1854   *   properties: [{1855   *   key: "gender",1856   *   value: "female",1857   *  },{1858   *   key: "age",1859   *   value: "33",1860   *  }],1861   * }]);1862   * @returns array of newly created tokens1863   */1864  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: { properties?: IProperty[] }[]): Promise<UniqueNFToken[]> {1865    const rawTokens = [];1866    for(const token of tokens) {1867      const raw = {NFT: {properties: token.properties}};1868      rawTokens.push(raw);1869    }1870    const creationResult = await this.helper.executeExtrinsic(1871      signer,1872      'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1873      true,1874    );1875    const collection = this.getCollectionObject(collectionId);1876    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1877  }18781879  /**1880   * Set, change, or remove approved address to transfer the ownership of the NFT.1881   *1882   * @param signer keyring of signer1883   * @param collectionId ID of collection1884   * @param tokenId ID of token1885   * @param toAddressObj address to approve1886   * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1887   * @returns ```true``` if extrinsic success, otherwise ```false```1888   */1889  override approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {1890    return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);1891  }1892}189318941895class RFTGroup extends NFTnRFT {1896  /**1897   * Get collection object1898   * @param collectionId ID of collection1899   * @example getCollectionObject(2);1900   * @returns instance of UniqueRFTCollection1901   */1902  override getCollectionObject(collectionId: number): UniqueRFTCollection {1903    return new UniqueRFTCollection(collectionId, this.helper);1904  }19051906  /**1907   * Get token object1908   * @param collectionId ID of collection1909   * @param tokenId ID of token1910   * @example getTokenObject(10, 5);1911   * @returns instance of UniqueNFTToken1912   */1913  override getTokenObject(collectionId: number, tokenId: number): UniqueRFToken {1914    return new UniqueRFToken(tokenId, this.getCollectionObject(collectionId));1915  }19161917  /**1918   * Get top 10 token owners with the largest number of pieces1919   * @param collectionId ID of collection1920   * @param tokenId ID of token1921   * @example getTokenTop10Owners(10, 5);1922   * @returns array of top 10 owners1923   */1924  async getTokenTop10Owners(collectionId: number, tokenId: number): Promise<ICrossAccountId[]> {1925    return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, tokenId])).toJSON().map(CrossAccountId.fromLowerCaseKeys).map((a: CrossAccountId) => a.toICrossAccountId());1926  }19271928  /**1929   * Get number of pieces owned by address1930   * @param collectionId ID of collection1931   * @param tokenId ID of token1932   * @param addressObj address token owner1933   * @example getTokenBalance(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."});1934   * @returns number of pieces ownerd by address1935   */1936  async getTokenBalance(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<bigint> {1937    return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, tokenId])).toBigInt();1938  }19391940  /**1941   * Transfer pieces of token to another address1942   * @param signer keyring of signer1943   * @param collectionId ID of collection1944   * @param tokenId ID of token1945   * @param addressObj address of a new owner1946   * @param amount number of pieces to be transfered1947   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2000n)1948   * @returns ```true``` if extrinsic success, otherwise ```false```1949   */1950  override async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount = 1n): Promise<boolean> {1951    return await super.transferToken(signer, collectionId, tokenId, addressObj, amount);1952  }19531954  /**1955   * Change ownership of some pieces of RFT on behalf of the owner.1956   * @param signer keyring of signer1957   * @param collectionId ID of collection1958   * @param tokenId ID of token1959   * @param fromAddressObj address on behalf of which the token will be sent1960   * @param toAddressObj new token owner1961   * @param amount number of pieces to be transfered1962   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n)1963   * @returns ```true``` if extrinsic success, otherwise ```false```1964   */1965  override async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {1966    return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1967  }19681969  /**1970   * Mint new collection1971   * @param signer keyring of signer1972   * @param collectionOptions Collection options1973   * @example1974   * mintCollection(aliceKeyring, {1975   *   name: 'New',1976   *   description: 'New collection',1977   *   tokenPrefix: 'NEW',1978   * })1979   * @returns object of the created collection1980   */1981  override async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueRFTCollection> {1982    return await super.mintCollection(signer, collectionOptions, 'RFT') as UniqueRFTCollection;1983  }19841985  /**1986   * Mint new token1987   * @param signer keyring of signer1988   * @param data token data1989   * @example mintToken(aliceKeyring, {collectionId: 10, owner: {Substrate: '5GHoZe9c73RYbVzq...'}, pieces: 10000n});1990   * @returns created token object1991   */1992  async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise<UniqueRFToken> {1993    const creationResult = await this.helper.executeExtrinsic(1994      signer,1995      'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1996        ReFungible: {1997          pieces: data.pieces,1998          properties: data.properties,1999        },2000      }],2001      true,2002    );2003    const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);2004    if(createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');2005    if(createdTokens.tokens.length < 1) throw Error('No tokens minted');2006    return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);2007  }20082009  mintMultipleTokens(_signer: TSigner, _collectionId: number, _tokens: { owner: ICrossAccountId, pieces: bigint, properties?: IProperty[] }[]): Promise<UniqueRFToken[]> {2010    throw Error('Not implemented');2011    // const creationResult = await this.helper.executeExtrinsic(2012    //   signer,2013    //   'api.tx.unique.createMultipleItemsEx', [collectionId, {RefungibleMultipleOwners: tokens}],2014    //   true, // `Unable to mint RFT tokens for ${label}`,2015    // );2016    // const collection = this.getCollectionObject(collectionId);2017    // return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));2018  }20192020  /**2021   * Mint multiple RFT tokens with one owner2022   * @param signer keyring of signer2023   * @param collectionId ID of collection2024   * @param owner tokens owner2025   * @param tokens array of tokens with properties and pieces2026   * @example mintMultipleTokensWithOneOwner(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, [{pieces: 100000n, properties: [{key: "gender", value: "male"}]}]);2027   * @returns array of newly created RFT tokens2028   */2029  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: { pieces: bigint, properties?: IProperty[] }[]): Promise<UniqueRFToken[]> {2030    const rawTokens = [];2031    for(const token of tokens) {2032      const raw = {ReFungible: {pieces: token.pieces, properties: token.properties}};2033      rawTokens.push(raw);2034    }2035    const creationResult = await this.helper.executeExtrinsic(2036      signer,2037      'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],2038      true,2039    );2040    const collection = this.getCollectionObject(collectionId);2041    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));2042  }20432044  /**2045   * Destroys a concrete instance of RFT.2046   * @param signer keyring of signer2047   * @param collectionId ID of collection2048   * @param tokenId ID of token2049   * @param amount number of pieces to be burnt2050   * @example burnToken(aliceKeyring, 10, 5);2051   * @returns ```true``` if the extrinsic is successful, otherwise ```false```2052   */2053  override async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount = 1n): Promise<boolean> {2054    return await super.burnToken(signer, collectionId, tokenId, amount);2055  }20562057  /**2058   * Destroys a concrete instance of RFT on behalf of the owner.2059   * @param signer keyring of signer2060   * @param collectionId ID of collection2061   * @param tokenId ID of token2062   * @param fromAddressObj address on behalf of which the token will be burnt2063   * @param amount number of pieces to be burnt2064   * @example burnTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2n)2065   * @returns ```true``` if extrinsic success, otherwise ```false```2066   */2067  override async burnTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {2068    return await super.burnTokenFrom(signer, collectionId, tokenId, fromAddressObj, amount);2069  }20702071  /**2072   * Set, change, or remove approved address to transfer the ownership of the RFT.2073   *2074   * @param signer keyring of signer2075   * @param collectionId ID of collection2076   * @param tokenId ID of token2077   * @param toAddressObj address to approve2078   * @param amount number of pieces to be approved2079   * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n);2080   * @returns true if the token success, otherwise false2081   */2082  override approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {2083    return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);2084  }20852086  /**2087   * Get total number of pieces2088   * @param collectionId ID of collection2089   * @param tokenId ID of token2090   * @example getTokenTotalPieces(10, 5);2091   * @returns number of pieces2092   */2093  async getTokenTotalPieces(collectionId: number, tokenId: number): Promise<bigint> {2094    return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, tokenId])).unwrap().toBigInt();2095  }20962097  /**2098   * Change number of token pieces. Signer must be the owner of all token pieces.2099   * @param signer keyring of signer2100   * @param collectionId ID of collection2101   * @param tokenId ID of token2102   * @param amount new number of pieces2103   * @example repartitionToken(aliceKeyring, 10, 5, 12345n);2104   * @returns true if the repartion was success, otherwise false2105   */2106  async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint): Promise<boolean> {2107    const currentAmount = await this.getTokenTotalPieces(collectionId, tokenId);2108    const repartitionResult = await this.helper.executeExtrinsic(2109      signer,2110      'api.tx.unique.repartition', [collectionId, tokenId, amount],2111      true,2112    );2113    if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated');2114    return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed');2115  }2116}211721182119class FTGroup extends CollectionGroup {2120  /**2121   * Get collection object2122   * @param collectionId ID of collection2123   * @example getCollectionObject(2);2124   * @returns instance of UniqueFTCollection2125   */2126  getCollectionObject(collectionId: number): UniqueFTCollection {2127    return new UniqueFTCollection(collectionId, this.helper);2128  }21292130  /**2131   * Mint new fungible collection2132   * @param signer keyring of signer2133   * @param collectionOptions Collection options2134   * @param decimalPoints number of token decimals2135   * @example2136   * mintCollection(aliceKeyring, {2137   *   name: 'New',2138   *   description: 'New collection',2139   *   tokenPrefix: 'NEW',2140   * }, 18)2141   * @returns newly created fungible collection2142   */2143  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}, decimalPoints = 0): Promise<UniqueFTCollection> {2144    collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object2145    if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions');2146    collectionOptions.mode = {fungible: decimalPoints};2147    for(const key of ['name', 'description', 'tokenPrefix']) {2148      if(typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);2149    }2150    const creationResult = await this.helper.executeExtrinsic(2151      signer,2152      'api.tx.unique.createCollectionEx', [collectionOptions],2153      true,2154    );2155    return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));2156  }21572158  /**2159   * Mint tokens2160   * @param signer keyring of signer2161   * @param collectionId ID of collection2162   * @param owner address owner of new tokens2163   * @param amount amount of tokens to be meanted2164   * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n);2165   * @returns ```true``` if extrinsic success, otherwise ```false```2166   */2167  async mintTokens(signer: TSigner, collectionId: number, amount: bigint, owner: ICrossAccountId | string): Promise<boolean> {2168    const creationResult = await this.helper.executeExtrinsic(2169      signer,2170      'api.tx.unique.createItem', [collectionId, (typeof owner === 'string') ? {Substrate: owner} : owner, {2171        Fungible: {2172          value: amount,2173        },2174      }],2175      true, // `Unable to mint fungible tokens for ${label}`,2176    );2177    return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');2178  }21792180  /**2181   * Mint multiple Fungible tokens with one owner2182   * @param signer keyring of signer2183   * @param collectionId ID of collection2184   * @param owner tokens owner2185   * @param tokens array of tokens with properties and pieces2186   * @returns ```true``` if extrinsic success, otherwise ```false```2187   */2188  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, tokens: { value: bigint }[], owner: ICrossAccountId): Promise<boolean> {2189    const rawTokens = [];2190    for(const token of tokens) {2191      const raw = {Fungible: {Value: token.value}};2192      rawTokens.push(raw);2193    }2194    const creationResult = await this.helper.executeExtrinsic(2195      signer,2196      'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],2197      true,2198    );2199    return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');2200  }22012202  /**2203   * Get the top 10 owners with the largest balance for the Fungible collection2204   * @param collectionId ID of collection2205   * @example getTop10Owners(10);2206   * @returns array of ```ICrossAccountId```2207   */2208  async getTop10Owners(collectionId: number): Promise<ICrossAccountId[]> {2209    return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, 0])).toJSON().map(CrossAccountId.fromLowerCaseKeys).map((a: CrossAccountId) => a.toICrossAccountId());2210  }22112212  /**2213   * Get account balance2214   * @param collectionId ID of collection2215   * @param addressObj address of owner2216   * @example getBalance(10, {Substrate: "5GHoZe9c73RYbVzq..."})2217   * @returns amount of fungible tokens owned by address2218   */2219  async getBalance(collectionId: number, addressObj: ICrossAccountId): Promise<bigint> {2220    return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, 0])).toBigInt();2221  }22222223  /**2224   * Transfer tokens to address2225   * @param signer keyring of signer2226   * @param collectionId ID of collection2227   * @param toAddressObj address recipient2228   * @param amount amount of tokens to be sent2229   * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2230   * @returns ```true``` if extrinsic success, otherwise ```false```2231   */2232  async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount = 1n) {2233    return await super.transferToken(signer, collectionId, 0, toAddressObj, amount);2234  }22352236  /**2237   * Transfer some tokens on behalf of the owner.2238   * @param signer keyring of signer2239   * @param collectionId ID of collection2240   * @param fromAddressObj address on behalf of which tokens will be sent2241   * @param toAddressObj address where token to be sent2242   * @param amount number of tokens to be sent2243   * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n);2244   * @returns ```true``` if extrinsic success, otherwise ```false```2245   */2246  async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {2247    return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount);2248  }22492250  /**2251   * Destroy some amount of tokens2252   * @param signer keyring of signer2253   * @param collectionId ID of collection2254   * @param amount amount of tokens to be destroyed2255   * @example burnTokens(aliceKeyring, 10, 1000n);2256   * @returns ```true``` if extrinsic success, otherwise ```false```2257   */2258  async burnTokens(signer: IKeyringPair, collectionId: number, amount = 1n): Promise<boolean> {2259    return await super.burnToken(signer, collectionId, 0, amount);2260  }22612262  /**2263   * Burn some tokens on behalf of the owner.2264   * @param signer keyring of signer2265   * @param collectionId ID of collection2266   * @param fromAddressObj address on behalf of which tokens will be burnt2267   * @param amount amount of tokens to be burnt2268   * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2269   * @returns ```true``` if extrinsic success, otherwise ```false```2270   */2271  async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {2272    return await super.burnTokenFrom(signer, collectionId, 0, fromAddressObj, amount);2273  }22742275  /**2276   * Get total collection supply2277   * @param collectionId2278   * @returns2279   */2280  async getTotalPieces(collectionId: number): Promise<bigint> {2281    return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, 0])).unwrap().toBigInt();2282  }22832284  /**2285   * Set, change, or remove approved address to transfer tokens.2286   *2287   * @param signer keyring of signer2288   * @param collectionId ID of collection2289   * @param toAddressObj address to be approved2290   * @param amount amount of tokens to be approved2291   * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n)2292   * @returns ```true``` if extrinsic success, otherwise ```false```2293   */2294  approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount = 1n) {2295    return super.approveToken(signer, collectionId, 0, toAddressObj, amount);2296  }22972298  /**2299   * Get amount of fungible tokens approved to transfer2300   * @param collectionId ID of collection2301   * @param fromAddressObj owner of tokens2302   * @param toAddressObj the address approved for the transfer of tokens on behalf of the owner2303   * @returns number of tokens approved for the transfer2304   */2305  getApprovedTokens(collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {2306    return super.getTokenApprovedPieces(collectionId, 0, toAddressObj, fromAddressObj);2307  }2308}230923102311class ChainGroup extends HelperGroup<ChainHelperBase> {2312  /**2313   * Get system properties of a chain2314   * @example getChainProperties();2315   * @returns ss58Format, token decimals, and token symbol2316   */2317  getChainProperties(): IChainProperties {2318    const properties = (this.helper.getApi() as any).registry.getChainProperties().toJSON();2319    return {2320      ss58Format: properties.ss58Format.toJSON(),2321      tokenDecimals: properties.tokenDecimals.toJSON(),2322      tokenSymbol: properties.tokenSymbol.toJSON(),2323    };2324  }23252326  /**2327   * Get chain header2328   * @example getLatestBlockNumber();2329   * @returns the number of the last block2330   */2331  async getLatestBlockNumber(): Promise<number> {2332    return (await this.helper.callRpc('api.rpc.chain.getHeader')).number.toNumber();2333  }23342335  /**2336   * Get block hash by block number2337   * @param blockNumber number of block2338   * @example getBlockHashByNumber(12345);2339   * @returns hash of a block2340   */2341  async getBlockHashByNumber(blockNumber: number): Promise<string | null> {2342    const blockHash = (await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber])).toJSON();2343    if(blockHash === '0x0000000000000000000000000000000000000000000000000000000000000000') return null;2344    return blockHash;2345  }23462347  // TODO add docs2348  async getBlock(blockHashOrNumber: string | number): Promise<IBlock | null> {2349    const blockHash = typeof blockHashOrNumber === 'string' ? blockHashOrNumber : await this.getBlockHashByNumber(blockHashOrNumber);2350    if(!blockHash) return null;2351    return (await this.helper.callRpc('api.rpc.chain.getBlock', [blockHash])).toHuman().block;2352  }23532354  /**2355   * Get latest relay block2356   * @returns {number} relay block2357   */2358  async getRelayBlockNumber(): Promise<bigint> {2359    const blockNumber = (await this.helper.callRpc('api.query.parachainSystem.validationData')).toJSON().relayParentNumber;2360    return BigInt(blockNumber);2361  }23622363  /**2364   * Get account nonce2365   * @param address substrate address2366   * @example getNonce("5GrwvaEF5zXb26Fz...");2367   * @returns number, account's nonce2368   */2369  async getNonce(address: TSubstrateAccount): Promise<number> {2370    return (await this.helper.callRpc('api.query.system.account', [address])).nonce.toNumber();2371  }2372}23732374export class SubstrateBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2375  /**2376 * Get substrate address balance2377 * @param address substrate address2378 * @example getSubstrate("5GrwvaEF5zXb26Fz...")2379 * @returns amount of tokens on address2380 */2381  async getSubstrate(address: TSubstrateAccount): Promise<bigint> {2382    return (await this.helper.callRpc('api.query.system.account', [address])).data.free.toBigInt();2383  }23842385  /**2386   * Transfer tokens to substrate address2387   * @param signer keyring of signer2388   * @param address substrate address of a recipient2389   * @param amount amount of tokens to be transfered2390   * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2391   * @returns ```true``` if extrinsic success, otherwise ```false```2392   */2393  async transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2394    const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true/*, `Unable to transfer balance from ${this.helper.getSignerAddress(signer)} to ${address}`*/);23952396    let transfer = {from: null, to: null, amount: 0n} as any;2397    result.result.events.forEach(({event: {data, method, section}}: any) => {2398      if((section === 'balances') && (method === 'Transfer')) {2399        transfer = {2400          from: this.helper.address.normalizeSubstrate(data[0]),2401          to: this.helper.address.normalizeSubstrate(data[1]),2402          amount: BigInt(data[2]),2403        };2404      }2405    });2406    const isSuccess = this.helper.address.normalizeSubstrate(typeof signer === 'string' ? signer : signer.address) === transfer.from2407      && this.helper.address.normalizeSubstrate(address) === transfer.to2408      && BigInt(amount) === transfer.amount;2409    return isSuccess;2410  }24112412  /**2413   * Get full substrate balance including free, frozen, and reserved2414   * @param address substrate address2415   * @returns2416   */2417  async getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2418    const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data;2419    return {free: accountInfo.free.toBigInt(), frozen: accountInfo.frozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};2420  }24212422  /**2423   * Get total issuance2424   * @returns2425   */2426  async getTotalIssuance(): Promise<bigint> {2427    const total = (await this.helper.callRpc('api.query.balances.totalIssuance', []));2428    return total.toBigInt();2429  }24302431  async getLocked(address: TSubstrateAccount): Promise<{ id: string, amount: bigint, reason: string }[]> {2432    const locks = (await this.helper.callRpc('api.query.balances.locks', [address])).toHuman();2433    return locks.map((lock: any) => ({id: lock.id, amount: BigInt(lock.amount.replace(/,/g, '')), reasons: lock.reasons}));2434  }2435  async getFrozen(address: TSubstrateAccount): Promise<{ id: string, amount: bigint }[]> {2436    const locks = (await this.helper.api!.query.balances.freezes(address)) as unknown as Array<any>;2437    return locks.map(lock => ({id: lock.id.toUtf8(), amount: lock.amount.toBigInt()}));2438  }2439}24402441export class EthereumBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2442  /**2443   * Get ethereum address balance2444   * @param address ethereum address2445   * @example getEthereum("0x9F0583DbB855d...")2446   * @returns amount of tokens on address2447   */2448  async getEthereum(address: TEthereumAccount): Promise<bigint> {2449    return (await this.helper.callRpc('api.rpc.eth.getBalance', [address])).toBigInt();2450  }24512452  /**2453   * Transfer tokens to address2454   * @param signer keyring of signer2455   * @param address Ethereum address of a recipient2456   * @param amount amount of tokens to be transfered2457   * @example transferToEthereum(alithKeyring, "0x9F0583DbB855d...", 100_000_000_000n);2458   * @returns ```true``` if extrinsic success, otherwise ```false```2459   */2460  async transferToEthereum(signer: TSigner, address: TEthereumAccount, amount: bigint | string): Promise<boolean> {2461    const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true);24622463    let transfer = {from: null, to: null, amount: 0n} as any;2464    result.result.events.forEach(({event: {data, method, section}}: any) => {2465      if((section === 'balances') && (method === 'Transfer')) {2466        transfer = {2467          from: data[0].toString(),2468          to: data[1].toString(),2469          amount: BigInt(data[2]),2470        };2471      }2472    });2473    const isSuccess = (typeof signer === 'string' ? signer : signer.address) === transfer.from2474      && address === transfer.to2475      && BigInt(amount) === transfer.amount;2476    return isSuccess;2477  }2478}24792480class BalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2481  subBalanceGroup: SubstrateBalanceGroup<T>;2482  ethBalanceGroup: EthereumBalanceGroup<T>;24832484  constructor(helper: T) {2485    super(helper);2486    this.subBalanceGroup = new SubstrateBalanceGroup(helper);2487    this.ethBalanceGroup = new EthereumBalanceGroup(helper);2488  }24892490  getCollectionCreationPrice(): bigint {2491    return 2n * this.getOneTokenNominal();2492  }2493  /**2494   * Representation of the native token in the smallest unit - one OPAL (OPL), QUARTZ (QTZ), or UNIQUE (UNQ).2495   * @example getOneTokenNominal()2496   * @returns ```BigInt``` representation of the native token in the smallest unit, e.g. ```1_000_000_000_000_000_000n``` for QTZ.2497   */2498  getOneTokenNominal(): bigint {2499    const chainProperties = this.helper.chain.getChainProperties();2500    return 10n ** BigInt((chainProperties.tokenDecimals || [18])[0]);2501  }25022503  /**2504   * Get substrate address balance2505   * @param address substrate address2506   * @example getSubstrate("5GrwvaEF5zXb26Fz...")2507   * @returns amount of tokens on address2508   */2509  getSubstrate(address: TSubstrateAccount): Promise<bigint> {2510    return this.subBalanceGroup.getSubstrate(address);2511  }25122513  /**2514   * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2515   * @param address substrate address2516   * @returns2517   */2518  getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2519    return this.subBalanceGroup.getSubstrateFull(address);2520  }25212522  /**2523   * Get total issuance2524   * @returns2525   */2526  getTotalIssuance(): Promise<bigint> {2527    return this.subBalanceGroup.getTotalIssuance();2528  }25292530  /**2531   * Get locked balances2532   * @param address substrate address2533   * @returns locked balances with reason via api.query.balances.locks2534   * @deprecated all the methods should switch to getFrozen2535   */2536  getLocked(address: TSubstrateAccount) {2537    return this.subBalanceGroup.getLocked(address);2538  }25392540  /**2541   * Get frozen balances2542   * @param address substrate address2543   * @returns frozen balances with id via api.query.balances.freezes2544   */2545  getFrozen(address: TSubstrateAccount) {2546    return this.subBalanceGroup.getFrozen(address);2547  }25482549  /**2550   * Get ethereum address balance2551   * @param address ethereum address2552   * @example getEthereum("0x9F0583DbB855d...")2553   * @returns amount of tokens on address2554   */2555  getEthereum(address: TEthereumAccount): Promise<bigint> {2556    return this.ethBalanceGroup.getEthereum(address);2557  }25582559  async setBalanceSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint) {2560    await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceSetBalance', [address, amount], true);2561  }25622563  /**2564   * Transfer tokens to substrate address2565   * @param signer keyring of signer2566   * @param address substrate address of a recipient2567   * @param amount amount of tokens to be transfered2568   * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2569   * @returns ```true``` if extrinsic success, otherwise ```false```2570   */2571  transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2572    return this.subBalanceGroup.transferToSubstrate(signer, address, amount);2573  }25742575  async forceTransferToSubstrate(signer: TSigner, from: TSubstrateAccount, to: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2576    const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceTransfer', [from, to, amount], true);25772578    let transfer = {from: null, to: null, amount: 0n} as any;2579    result.result.events.forEach(({event: {data, method, section}}: any) => {2580      if((section === 'balances') && (method === 'Transfer')) {2581        transfer = {2582          from: this.helper.address.normalizeSubstrate(data[0]),2583          to: this.helper.address.normalizeSubstrate(data[1]),2584          amount: BigInt(data[2]),2585        };2586      }2587    });2588    let isSuccess = this.helper.address.normalizeSubstrate(from) === transfer.from;2589    isSuccess = isSuccess && this.helper.address.normalizeSubstrate(to) === transfer.to;2590    isSuccess = isSuccess && BigInt(amount) === transfer.amount;2591    return isSuccess;2592  }25932594  /**2595   * Transfer tokens with the unlock period2596   * @param signer signers Keyring2597   * @param address Substrate address of recipient2598   * @param schedule Schedule params2599   * @example vestedTransfer(signer, recepient.address, 20000, 100, 10, 50 * nominal); // total amount of vested tokens will be 100 * 50 = 50002600   */2601  async vestedTransfer(signer: TSigner, address: TSubstrateAccount, schedule: { start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint }): Promise<void> {2602    const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.vestedTransfer', [address, schedule]);2603    const event = result.result.events2604      .find((e: any) => e.event.section === 'vesting' &&2605        e.event.method === 'VestingScheduleAdded' &&2606        e.event.data[0].toHuman() === signer.address);2607    if(!event) throw Error('Cannot find transfer in events');2608  }26092610  /**2611   * Get schedule for recepient of vested transfer2612   * @param address Substrate address of recipient2613   * @returns2614   */2615  async getVestingSchedules(address: TSubstrateAccount): Promise<{ start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint }[]> {2616    const schedule = (await this.helper.callRpc('api.query.vesting.vestingSchedules', [address])).toJSON();2617    return schedule.map((schedule: any) => ({2618      start: BigInt(schedule.start),2619      period: BigInt(schedule.period),2620      periodCount: BigInt(schedule.periodCount),2621      perPeriod: BigInt(schedule.perPeriod),2622    }));2623  }26242625  /**2626   * Claim vested tokens2627   * @param signer signers Keyring2628   */2629  async claim(signer: TSigner) {2630    const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.claim', []);2631    const event = result.result.events2632      .find((e: any) => e.event.section === 'vesting' &&2633        e.event.method === 'Claimed' &&2634        e.event.data[0].toHuman() === signer.address);2635    if(!event) throw Error('Cannot find claim in events');2636  }2637}26382639class AddressGroup extends HelperGroup<ChainHelperBase> {2640  /**2641   * Normalizes the address to the specified ss58 format, by default ```42```.2642   * @param address substrate address2643   * @param ss58Format format for address conversion, by default ```42```2644   * @example normalizeSubstrate("unjKJQJrRd238pkUZZvzDQrfKuM39zBSnQ5zjAGAGcdRhaJTx") // returns 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY2645   * @returns substrate address converted to normalized (i.e., starting with 5) or specified explicitly representation2646   */2647  normalizeSubstrate(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {2648    return CrossAccountId.normalizeSubstrateAddress({Substrate: address}, ss58Format);2649  }26502651  /**2652   * Get address in the connected chain format2653   * @param address substrate address2654   * @example normalizeSubstrateToChainFormat("5GrwvaEF5zXb26Fz...") // returns unjKJQJrRd238pkUZZ... for Unique Network2655   * @returns address in chain format2656   */2657  normalizeSubstrateToChainFormat(address: TSubstrateAccount): TSubstrateAccount {2658    return this.normalizeSubstrate(address, this.helper.chain.getChainProperties().ss58Format);2659  }26602661  /**2662   * Get substrate mirror of an ethereum address2663   * @param ethAddress ethereum address2664   * @param toChainFormat false for normalized account2665   * @example ethToSubstrate('0x9F0583DbB855d...')2666   * @returns substrate mirror of a provided ethereum address2667   */2668  ethToSubstrate(ethAddress: TEthereumAccount, toChainFormat = false): TSubstrateAccount {2669    return CrossAccountId.translateEthToSub(ethAddress, toChainFormat ? this.helper.chain.getChainProperties().ss58Format : undefined);2670  }26712672  /**2673   * Get ethereum mirror of a substrate address2674   * @param subAddress substrate account2675   * @example substrateToEth("5DnSF6RRjwteE3BrC...")2676   * @returns ethereum mirror of a provided substrate address2677   */2678  substrateToEth(subAddress: TSubstrateAccount): TEthereumAccount {2679    return CrossAccountId.translateSubToEth(subAddress);2680  }26812682  /**2683   * Encode key to substrate address2684   * @param key key for encoding address2685   * @param ss58Format prefix for encoding to the address of the corresponding network2686   * @returns encoded substrate address2687   */2688  encodeSubstrateAddress(key: Uint8Array | string | bigint, ss58Format = 42): string {2689    const u8a: Uint8Array = typeof key === 'string'2690      ? hexToU8a(key)2691      : typeof key === 'bigint'2692        ? hexToU8a(key.toString(16))2693        : key;26942695    if(ss58Format < 0 || ss58Format > 16383 || [46, 47].includes(ss58Format)) {2696      throw new Error(`ss58Format is not valid, received ${typeof ss58Format} "${ss58Format}"`);2697    }26982699    const allowedDecodedLengths = [1, 2, 4, 8, 32, 33];2700    if(!allowedDecodedLengths.includes(u8a.length)) {2701      throw new Error(`key length is not valid, received ${u8a.length}, valid values are ${allowedDecodedLengths.join(', ')}`);2702    }27032704    const u8aPrefix = ss58Format < 642705      ? new Uint8Array([ss58Format])2706      : new Uint8Array([2707        ((ss58Format & 0xfc) >> 2) | 0x40,2708        (ss58Format >> 8) | ((ss58Format & 0x03) << 6),2709      ]);27102711    const input = u8aConcat(u8aPrefix, u8a);27122713    return base58Encode(u8aConcat(2714      input,2715      blake2AsU8a(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1),2716    ));2717  }27182719  /**2720   * Restore substrate address from bigint representation2721   * @param number decimal representation of substrate address2722   * @returns substrate address2723   */2724  restoreCrossAccountFromBigInt(number: bigint): TSubstrateAccount {2725    if(this.helper.api === null) {2726      throw 'Not connected';2727    }2728    const res = this.helper.api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();2729    if(res === undefined || res === null) {2730      throw 'Restore address error';2731    }2732    return res.toString();2733  }27342735  /**2736   * Convert etherium cross account id to substrate cross account id2737   * @param ethCrossAccount etherium cross account2738   * @returns substrate cross account id2739   */2740  convertCrossAccountFromEthCrossAccount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId {2741    if(ethCrossAccount.sub === '0') {2742      return {Ethereum: ethCrossAccount.eth.toLocaleLowerCase()};2743    }27442745    const ss58 = this.restoreCrossAccountFromBigInt(BigInt(ethCrossAccount.sub));2746    return {Substrate: ss58};2747  }27482749  paraSiblingSovereignAccount(paraid: number) {2750    // We are getting a *sibling* parachain sovereign account,2751    // so we need a sibling prefix: encoded(b"sibl") == 0x7369626c2752    const siblingPrefix = '0x7369626c';27532754    const encodedParaId = this.helper.getApi().createType('u32', paraid).toHex(true).substring(2);2755    const suffix = '000000000000000000000000000000000000000000000000';27562757    return siblingPrefix + encodedParaId + suffix;2758  }2759}276027612762class StakingGroup extends HelperGroup<UniqueHelper> {2763  /**2764   * Stake tokens for App Promotion2765   * @param signer keyring of signer2766   * @param amountToStake amount of tokens to stake2767   * @param label extra label for log2768   * @returns2769   */2770  async stake(signer: TSigner, amountToStake: bigint, label?: string): Promise<boolean> {2771    if(typeof label === 'undefined') label = `${signer.address} amount: ${amountToStake}`;2772    await this.helper.executeExtrinsic(2773      signer, 'api.tx.appPromotion.stake',2774      [amountToStake], true,2775    );2776    // TODO extract info from stakeResult2777    return true;2778  }27792780  /**2781   * Unstake all staked tokens2782   * @param signer keyring of signer2783   * @param amountToUnstake amount of tokens to unstake2784   * @param label extra label for log2785   * @returns block hash where unstake happened2786   */2787  async unstakeAll(signer: TSigner, label?: string): Promise<string> {2788    if(typeof label === 'undefined') label = `${signer.address}`;2789    const unstakeResult = await this.helper.executeExtrinsic(2790      signer, 'api.tx.appPromotion.unstakeAll',2791      [], true,2792    );2793    return unstakeResult.blockHash;2794  }27952796  /**2797   * Unstake the part of a staked tokens2798   * @param signer keyring of signer2799   * @param amount amount of tokens to unstake2800   * @param label extra label for log2801   * @returns block hash where unstake happened2802   */2803  async unstakePartial(signer: TSigner, amount: bigint, label?: string): Promise<string> {2804    if(typeof label === 'undefined') label = `${signer.address}`;2805    const unstakeResult = await this.helper.executeExtrinsic(2806      signer, 'api.tx.appPromotion.unstakePartial',2807      [amount], true,2808    );2809    return unstakeResult.blockHash;2810  }28112812  /**2813   * Get total number of active stakes2814   * @param address substrate address2815   * @returns {number}2816   */2817  async getStakesNumber(address: ICrossAccountId): Promise<number> {2818    if('Ethereum' in address) throw Error('only substrate address');2819    return (await this.helper.callRpc('api.query.appPromotion.stakesPerAccount', [address.Substrate])).toNumber();2820  }28212822  /**2823   * Get total staked amount for address2824   * @param address substrate or ethereum address2825   * @returns total staked amount2826   */2827  async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {2828    if(address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();2829    return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();2830  }28312832  /**2833   * Get total staked per block2834   * @param address substrate or ethereum address2835   * @returns array of stakes. `block` – the number of the block in which the stake was made. `amount` - the number of tokens staked in the block2836   */2837  async getTotalStakedPerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2838    const rawTotalStakerdPerBlock = await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address]);2839    return rawTotalStakerdPerBlock.map(([block, amount]: any[]) => ({2840      block: block.toBigInt(),2841      amount: amount.toBigInt(),2842    }));2843  }28442845  /**2846   * Get total pending unstake amount for address2847   * @param address substrate or ethereum address2848   * @returns total pending unstake amount2849   */2850  async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {2851    return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();2852  }28532854  /**2855   * Get pending unstake amount per block for address2856   * @param address substrate or ethereum address2857   * @returns array of pending stakes. `block` – the number of the block in which the unstake was made. `amount` - the number of tokens unstaked in the block2858   */2859  async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2860    const rawUnstakedPerBlock = await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address]);2861    const result = rawUnstakedPerBlock.map(([block, amount]: any[]) => ({2862      block: block.toBigInt(),2863      amount: amount.toBigInt(),2864    }));2865    return result;2866  }2867}286828692870class PreimageGroup extends HelperGroup<UniqueHelper> {2871  async getPreimageInfo(h256: string) {2872    return (await this.helper.callRpc('api.query.preimage.statusFor', [h256])).toJSON();2873  }28742875  /**2876   * Create a preimage from an API call.2877   * @param signer keyring of the signer.2878   * @param call an extrinsic call2879   * @example await notePreimageFromCall(preimageMaker,2880   *   helper.constructApiCall('api.tx.identity.forceInsertIdentities', [identitiesToAdd])2881   * );2882   * @returns promise of extrinsic execution.2883   */2884  notePreimageFromCall(signer: TSigner, call: any, returnPreimageHash = false) {2885    return this.notePreimage(signer, call.method.toHex(), returnPreimageHash);2886  }28872888  /**2889   * Create a preimage with a hex or a byte array.2890   * @param signer keyring of the signer.2891   * @param bytes preimage encoded in hex or a byte array, e.g. an extrinsic call.2892   * @example await notePreimage(preimageMaker,2893   *   helper.constructApiCall('api.tx.identity.forceInsertIdentities', [identitiesToAdd]).method.toHex()2894   * );2895   * @returns promise of extrinsic execution.2896   */2897  async notePreimage(signer: TSigner, bytes: string | Uint8Array, returnPreimageHash = false) {2898    const promise = this.helper.executeExtrinsic(signer, 'api.tx.preimage.notePreimage', [bytes]);2899    if(returnPreimageHash) {2900      const result = await promise;2901      const events = result.result.events.filter((x: any) => x.event.method === 'Noted' && x.event.section === 'preimage');2902      const preimageHash = events[0].event.data[0].toHuman();2903      return preimageHash;2904    }2905    return promise;2906  }29072908  /**2909   * Delete an existing preimage and return the deposit.2910   * @param signer keyring of the signer - either the owner or the preimage manager (sudo).2911   * @param h256 hash of the preimage.2912   * @returns promise of extrinsic execution.2913   */2914  unnotePreimage(signer: TSigner, h256: string) {2915    return this.helper.executeExtrinsic(signer, 'api.tx.preimage.unnotePreimage', [h256]);2916  }29172918  /**2919   * Request a preimage be uploaded to the chain without paying any fees or deposits.2920   * @param signer keyring of the signer - either the owner or the preimage manager (sudo).2921   * @param h256 hash of the preimage.2922   * @returns promise of extrinsic execution.2923   */2924  requestPreimage(signer: TSigner, h256: string) {2925    return this.helper.executeExtrinsic(signer, 'api.tx.preimage.requestPreimage', [h256]);2926  }29272928  /**2929   * Clear a previously made request for a preimage.2930   * @param signer keyring of the signer - either the owner or the preimage manager (sudo).2931   * @param h256 hash of the preimage.2932   * @returns promise of extrinsic execution.2933   */2934  unrequestPreimage(signer: TSigner, h256: string) {2935    return this.helper.executeExtrinsic(signer, 'api.tx.preimage.unrequestPreimage', [h256]);2936  }2937}29382939class UtilityGroup<T extends ChainHelperBase> extends HelperGroup<T> {2940  async batch(signer: TSigner, txs: any[]) {2941    return await this.helper.executeExtrinsic(signer, 'api.tx.utility.batch', [txs]);2942  }29432944  async batchAll(signer: TSigner, txs: any[]) {2945    return await this.helper.executeExtrinsic(signer, 'api.tx.utility.batchAll', [txs]);2946  }29472948  batchAllCall(txs: any[]) {2949    return this.helper.constructApiCall('api.tx.utility.batchAll', [txs]);2950  }2951}29522953export type ChainHelperBaseConstructor = new (...args: any[]) => ChainHelperBase;2954export type UniqueHelperConstructor = new (...args: any[]) => UniqueHelper;29552956export class UniqueHelper extends ChainHelperBase {2957  balance: BalanceGroup<UniqueHelper>;2958  collection: CollectionGroup;2959  nft: NFTGroup;2960  rft: RFTGroup;2961  ft: FTGroup;2962  staking: StakingGroup;2963  preimage: PreimageGroup;2964  utility: UtilityGroup<UniqueHelper>;29652966  constructor(logger?: ILogger, options: { [key: string]: any } = {}) {2967    super(logger, options.helperBase ?? UniqueHelper);29682969    this.balance = new BalanceGroup(this);2970    this.collection = new CollectionGroup(this);2971    this.nft = new NFTGroup(this);2972    this.rft = new RFTGroup(this);2973    this.ft = new FTGroup(this);2974    this.staking = new StakingGroup(this);2975    this.preimage = new PreimageGroup(this);2976    this.utility = new UtilityGroup(this);2977  }2978}29792980export class UniqueBaseCollection {2981  helper: UniqueHelper;2982  collectionId: number;29832984  constructor(collectionId: number, uniqueHelper: UniqueHelper) {2985    this.collectionId = collectionId;2986    this.helper = uniqueHelper;2987  }29882989  async getData() {2990    return await this.helper.collection.getData(this.collectionId);2991  }29922993  async getLastTokenId() {2994    return await this.helper.collection.getLastTokenId(this.collectionId);2995  }29962997  async doesTokenExist(tokenId: number) {2998    return await this.helper.collection.doesTokenExist(this.collectionId, tokenId);2999  }30003001  async getAdmins() {3002    return await this.helper.collection.getAdmins(this.collectionId);3003  }30043005  async getAllowList() {3006    return await this.helper.collection.getAllowList(this.collectionId);3007  }30083009  async getEffectiveLimits() {3010    return await this.helper.collection.getEffectiveLimits(this.collectionId);3011  }30123013  async getProperties(propertyKeys?: string[] | null) {3014    return await this.helper.collection.getProperties(this.collectionId, propertyKeys);3015  }30163017  async getPropertiesConsumedSpace() {3018    return await this.helper.collection.getPropertiesConsumedSpace(this.collectionId);3019  }30203021  async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) {3022    return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj);3023  }30243025  async getOptions() {3026    return await this.helper.collection.getCollectionOptions(this.collectionId);3027  }30283029  async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) {3030    return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress);3031  }30323033  async confirmSponsorship(signer: TSigner) {3034    return await this.helper.collection.confirmSponsorship(signer, this.collectionId);3035  }30363037  async removeSponsor(signer: TSigner) {3038    return await this.helper.collection.removeSponsor(signer, this.collectionId);3039  }30403041  async setLimits(signer: TSigner, limits: ICollectionLimits) {3042    return await this.helper.collection.setLimits(signer, this.collectionId, limits);3043  }30443045  async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount) {3046    return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress);3047  }30483049  async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3050    return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj);3051  }30523053  async addToAllowList(signer: TSigner, addressObj: ICrossAccountId) {3054    return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj);3055  }30563057  async removeFromAllowList(signer: TSigner, addressObj: ICrossAccountId) {3058    return await this.helper.collection.removeFromAllowList(signer, this.collectionId, addressObj);3059  }30603061  async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3062    return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj);3063  }30643065  async setProperties(signer: TSigner, properties: IProperty[]) {3066    return await this.helper.collection.setProperties(signer, this.collectionId, properties);3067  }30683069  async deleteProperties(signer: TSigner, propertyKeys: string[]) {3070    return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys);3071  }30723073  async setPermissions(signer: TSigner, permissions: ICollectionPermissions) {3074    return await this.helper.collection.setPermissions(signer, this.collectionId, permissions);3075  }30763077  async enableNesting(signer: TSigner, permissions: INestingPermissions) {3078    return await this.helper.collection.enableNesting(signer, this.collectionId, permissions);3079  }30803081  async disableNesting(signer: TSigner) {3082    return await this.helper.collection.disableNesting(signer, this.collectionId);3083  }30843085  async burn(signer: TSigner) {3086    return await this.helper.collection.burn(signer, this.collectionId);3087  }3088}30893090export class UniqueNFTCollection extends UniqueBaseCollection {3091  getTokenObject(tokenId: number) {3092    return new UniqueNFToken(tokenId, this);3093  }30943095  async getTokensByAddress(addressObj: ICrossAccountId) {3096    return await this.helper.nft.getTokensByAddress(this.collectionId, addressObj);3097  }30983099  async getToken(tokenId: number, blockHashAt?: string) {3100    return await this.helper.nft.getToken(this.collectionId, tokenId, [], blockHashAt);3101  }31023103  async getTokenOwner(tokenId: number, blockHashAt?: string) {3104    return await this.helper.nft.getTokenOwner(this.collectionId, tokenId, blockHashAt);3105  }31063107  async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {3108    return await this.helper.nft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);3109  }31103111  async getTokenChildren(tokenId: number, blockHashAt?: string) {3112    return await this.helper.nft.getTokenChildren(this.collectionId, tokenId, blockHashAt);3113  }31143115  async getPropertyPermissions(propertyKeys: string[] | null = null) {3116    return await this.helper.nft.getPropertyPermissions(this.collectionId, propertyKeys);3117  }31183119  async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3120    return await this.helper.nft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3121  }31223123  async getTokenPropertiesConsumedSpace(tokenId: number): Promise<number> {3124    const api = this.helper.getApi();3125    const props = (await api.query.nonfungible.tokenProperties(this.collectionId, tokenId)).toJSON() as any;31263127    return props?.consumedSpace ?? 0;3128  }31293130  async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId) {3131    return await this.helper.nft.transferToken(signer, this.collectionId, tokenId, addressObj);3132  }31333134  async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3135    return await this.helper.nft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj);3136  }31373138  async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId) {3139    return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj);3140  }31413142  async isTokenApproved(tokenId: number, toAddressObj: ICrossAccountId) {3143    return await this.helper.nft.isTokenApproved(this.collectionId, tokenId, toAddressObj);3144  }31453146  async mintToken(signer: TSigner, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3147    return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties});3148  }31493150  async mintMultipleTokens(signer: TSigner, tokens: { owner: ICrossAccountId, properties?: IProperty[] }[]) {3151    return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens);3152  }31533154  async burnToken(signer: TSigner, tokenId: number) {3155    return await this.helper.nft.burnToken(signer, this.collectionId, tokenId);3156  }31573158  async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId) {3159    return await this.helper.nft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj);3160  }31613162  async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3163    return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties);3164  }31653166  async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3167    return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3168  }31693170  async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3171    return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3172  }31733174  async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {3175    return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);3176  }31773178  async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3179    return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);3180  }3181}31823183export class UniqueRFTCollection extends UniqueBaseCollection {3184  getTokenObject(tokenId: number) {3185    return new UniqueRFToken(tokenId, this);3186  }31873188  async getToken(tokenId: number, blockHashAt?: string) {3189    return await this.helper.rft.getToken(this.collectionId, tokenId, [], blockHashAt);3190  }31913192  async getTokenOwner(tokenId: number, blockHashAt?: string) {3193    return await this.helper.rft.getTokenOwner(this.collectionId, tokenId, blockHashAt);3194  }31953196  async getTokensByAddress(addressObj: ICrossAccountId) {3197    return await this.helper.rft.getTokensByAddress(this.collectionId, addressObj);3198  }31993200  async getTop10TokenOwners(tokenId: number) {3201    return await this.helper.rft.getTokenTop10Owners(this.collectionId, tokenId);3202  }32033204  async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {3205    return await this.helper.rft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);3206  }32073208  async getTokenBalance(tokenId: number, addressObj: ICrossAccountId) {3209    return await this.helper.rft.getTokenBalance(this.collectionId, tokenId, addressObj);3210  }32113212  async getTokenTotalPieces(tokenId: number) {3213    return await this.helper.rft.getTokenTotalPieces(this.collectionId, tokenId);3214  }32153216  async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3217    return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj);3218  }32193220  async getPropertyPermissions(propertyKeys: string[] | null = null) {3221    return await this.helper.rft.getPropertyPermissions(this.collectionId, propertyKeys);3222  }32233224  async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3225    return await this.helper.rft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3226  }32273228  async getTokenPropertiesConsumedSpace(tokenId: number): Promise<number> {3229    const api = this.helper.getApi();3230    const props = (await api.query.refungible.tokenProperties(this.collectionId, tokenId)).toJSON() as any;32313232    return props?.consumedSpace ?? 0;3233  }32343235  async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount = 1n) {3236    return await this.helper.rft.transferToken(signer, this.collectionId, tokenId, addressObj, amount);3237  }32383239  async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {3240    return await this.helper.rft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj, amount);3241  }32423243  async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {3244    return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, amount);3245  }32463247  async repartitionToken(signer: TSigner, tokenId: number, amount: bigint) {3248    return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount);3249  }32503251  async mintToken(signer: TSigner, pieces = 1n, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3252    return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties});3253  }32543255  async mintMultipleTokens(signer: TSigner, tokens: { pieces: bigint, owner: ICrossAccountId, properties?: IProperty[] }[]) {3256    return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens);3257  }32583259  async burnToken(signer: TSigner, tokenId: number, amount = 1n) {3260    return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, amount);3261  }32623263  async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, amount = 1n) {3264    return await this.helper.rft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, amount);3265  }32663267  async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3268    return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties);3269  }32703271  async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3272    return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3273  }32743275  async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3276    return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3277  }32783279  async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {3280    return await this.helper.rft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);3281  }32823283  async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3284    return await this.helper.rft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);3285  }3286}32873288export class UniqueFTCollection extends UniqueBaseCollection {3289  async getBalance(addressObj: ICrossAccountId) {3290    return await this.helper.ft.getBalance(this.collectionId, addressObj);3291  }32923293  async getTotalPieces() {3294    return await this.helper.ft.getTotalPieces(this.collectionId);3295  }32963297  async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3298    return await this.helper.ft.getApprovedTokens(this.collectionId, fromAddressObj, toAddressObj);3299  }33003301  async getTop10Owners() {3302    return await this.helper.ft.getTop10Owners(this.collectionId);3303  }33043305  async mint(signer: TSigner, amount = 1n, owner: ICrossAccountId = {Substrate: signer.address}) {3306    return await this.helper.ft.mintTokens(signer, this.collectionId, amount, owner);3307  }33083309  async mintWithOneOwner(signer: TSigner, tokens: { value: bigint }[], owner: ICrossAccountId = {Substrate: signer.address}) {3310    return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, tokens, owner);3311  }33123313  async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount = 1n) {3314    return await this.helper.ft.transfer(signer, this.collectionId, toAddressObj, amount);3315  }33163317  async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {3318    return await this.helper.ft.transferFrom(signer, this.collectionId, fromAddressObj, toAddressObj, amount);3319  }33203321  async burnTokens(signer: TSigner, amount = 1n) {3322    return await this.helper.ft.burnTokens(signer, this.collectionId, amount);3323  }33243325  async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount = 1n) {3326    return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount);3327  }33283329  async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount = 1n) {3330    return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);3331  }3332}33333334export class UniqueBaseToken {3335  collection: UniqueNFTCollection | UniqueRFTCollection;3336  collectionId: number;3337  tokenId: number;33383339  constructor(tokenId: number, collection: UniqueNFTCollection | UniqueRFTCollection) {3340    this.collection = collection;3341    this.collectionId = collection.collectionId;3342    this.tokenId = tokenId;3343  }33443345  async getNextSponsored(addressObj: ICrossAccountId) {3346    return await this.collection.getTokenNextSponsored(this.tokenId, addressObj);3347  }33483349  async getProperties(propertyKeys?: string[] | null) {3350    return await this.collection.getTokenProperties(this.tokenId, propertyKeys);3351  }33523353  async getTokenPropertiesConsumedSpace() {3354    return await this.collection.getTokenPropertiesConsumedSpace(this.tokenId);3355  }33563357  async setProperties(signer: TSigner, properties: IProperty[]) {3358    return await this.collection.setTokenProperties(signer, this.tokenId, properties);3359  }33603361  async deleteProperties(signer: TSigner, propertyKeys: string[]) {3362    return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys);3363  }33643365  async doesExist() {3366    return await this.collection.doesTokenExist(this.tokenId);3367  }33683369  nestingAccount(): ICrossAccountId {3370    return this.collection.helper.util.getTokenAccount(this);3371  }3372}33733374export class UniqueNFToken extends UniqueBaseToken {3375  declare collection: UniqueNFTCollection;33763377  constructor(tokenId: number, collection: UniqueNFTCollection) {3378    super(tokenId, collection);3379    this.collection = collection;3380  }33813382  async getData(blockHashAt?: string) {3383    return await this.collection.getToken(this.tokenId, blockHashAt);3384  }33853386  async getOwner(blockHashAt?: string) {3387    return await this.collection.getTokenOwner(this.tokenId, blockHashAt);3388  }33893390  async getTopmostOwner(blockHashAt?: string) {3391    return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);3392  }33933394  async getChildren(blockHashAt?: string) {3395    return await this.collection.getTokenChildren(this.tokenId, blockHashAt);3396  }33973398  async nest(signer: TSigner, toTokenObj: IToken) {3399    return await this.collection.nestToken(signer, this.tokenId, toTokenObj);3400  }34013402  async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3403    return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);3404  }34053406  async transfer(signer: TSigner, addressObj: ICrossAccountId) {3407    return await this.collection.transferToken(signer, this.tokenId, addressObj);3408  }34093410  async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3411    return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj);3412  }34133414  async approve(signer: TSigner, toAddressObj: ICrossAccountId) {3415    return await this.collection.approveToken(signer, this.tokenId, toAddressObj);3416  }34173418  async isApproved(toAddressObj: ICrossAccountId) {3419    return await this.collection.isTokenApproved(this.tokenId, toAddressObj);3420  }34213422  async burn(signer: TSigner) {3423    return await this.collection.burnToken(signer, this.tokenId);3424  }34253426  async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId) {3427    return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj);3428  }3429}34303431export class UniqueRFToken extends UniqueBaseToken {3432  declare collection: UniqueRFTCollection;34333434  constructor(tokenId: number, collection: UniqueRFTCollection) {3435    super(tokenId, collection);3436    this.collection = collection;3437  }34383439  async getData(blockHashAt?: string) {3440    return await this.collection.getToken(this.tokenId, blockHashAt);3441  }34423443  async getOwner(blockHashAt?: string) {3444    return await this.collection.getTokenOwner(this.tokenId, blockHashAt);3445  }34463447  async getTop10Owners() {3448    return await this.collection.getTop10TokenOwners(this.tokenId);3449  }34503451  async getTopmostOwner(blockHashAt?: string) {3452    return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);3453  }34543455  async nest(signer: TSigner, toTokenObj: IToken) {3456    return await this.collection.nestToken(signer, this.tokenId, toTokenObj);3457  }34583459  async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3460    return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);3461  }34623463  async getBalance(addressObj: ICrossAccountId) {3464    return await this.collection.getTokenBalance(this.tokenId, addressObj);3465  }34663467  async getTotalPieces() {3468    return await this.collection.getTokenTotalPieces(this.tokenId);3469  }34703471  async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) {3472    return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj);3473  }34743475  async transfer(signer: TSigner, addressObj: ICrossAccountId, amount = 1n) {3476    return await this.collection.transferToken(signer, this.tokenId, addressObj, amount);3477  }34783479  async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {3480    return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj, amount);3481  }34823483  async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount = 1n) {3484    return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount);3485  }34863487  async repartition(signer: TSigner, amount: bigint) {3488    return await this.collection.repartitionToken(signer, this.tokenId, amount);3489  }34903491  async burn(signer: TSigner, amount = 1n) {3492    return await this.collection.burnToken(signer, this.tokenId, amount);3493  }34943495  async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount = 1n) {3496    return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj, amount);3497  }3498}
after · js-packages/playgrounds/unique.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034/* eslint-disable @typescript-eslint/no-var-requires */5/* eslint-disable function-call-argument-newline */6/* eslint-disable no-prototype-builtins */78import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';9import type {SignerOptions} from '@polkadot/api/types';10import type {AugmentedSubmittables} from '@polkadot/api-base/types/submittable';11import type {ApiInterfaceEvents} from '@polkadot/api/types';12import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto';13import type {IKeyringPair} from '@polkadot/types/types';14import {hexToU8a} from '@polkadot/util/hex';15import {u8aConcat} from '@polkadot/util/u8a';16import type {17  IApiListeners,18  IBlock,19  IEvent,20  IChainProperties,21  ICollectionCreationOptions,22  ICollectionLimits,23  ICollectionPermissions,24  ICrossAccountId,25  ICrossAccountIdLower,26  ILogger,27  INestingPermissions,28  IProperty,29  IStakingInfo,30  ISubstrateBalance,31  IToken,32  ITokenPropertyPermission,33  ITransactionResult,34  IUniqueHelperLog,35  TApiAllowedListeners,36  TEthereumAccount,37  TSigner,38  TSubstrateAccount,39  TNetworks,40  IEthCrossAccountId,41} from './types.js';42import type {RuntimeDispatchInfo} from '@polkadot/types/interfaces';4344export class CrossAccountId {45  account: ICrossAccountId;4647  constructor(account: ICrossAccountId) {48    this.account = account;49  }5051  static fromKeyring(account: IKeyringPair, domain: 'Substrate' | 'Ethereum' = 'Substrate') {52    switch (domain) {53      case 'Substrate': return new CrossAccountId({Substrate: account.address});54      case 'Ethereum': return new CrossAccountId({Substrate: account.address}).toEthereum();55    }56  }5758  static fromLowerCaseKeys(address: ICrossAccountIdLower): CrossAccountId {59    if('substrate' in address) return new CrossAccountId({Substrate: address.substrate});60    else return new CrossAccountId({Ethereum: address.ethereum});61  }6263  static normalizeSubstrateAddress(address: {Substrate: TSubstrateAccount}, ss58Format = 42): TSubstrateAccount {64    return encodeAddress(decodeAddress(address.Substrate), ss58Format);65  }6667  static withNormalizedSubstrate(address: ICrossAccountId, ss58Format = 42): ICrossAccountId {68    if('Substrate' in address) return {Substrate: CrossAccountId.normalizeSubstrateAddress(address, ss58Format)};69    return address;70  }7172  withNormalizedSubstrate(ss58Format = 42): CrossAccountId {73    if('Substrate' in this.account) this.account = CrossAccountId.withNormalizedSubstrate(this.account, ss58Format);74    return this;75  }7677  static translateSubToEth(address: TSubstrateAccount): TEthereumAccount {78    return nesting.toChecksumAddress('0x' + Array.from(addressToEvm(address), i => i.toString(16).padStart(2, '0')).join(''));79  }8081  toEthereum(): CrossAccountId {82    this.account = CrossAccountId.toEthereum(this.account);83    return this;84  }8586  static toEthereum(account: ICrossAccountId): ICrossAccountId {87    if('Substrate' in account) return {Ethereum: CrossAccountId.translateSubToEth(account.Substrate)};88    return account;89  }9091  static translateEthToSub(address: TEthereumAccount, ss58Format?: number): TSubstrateAccount {92    return evmToAddress(address, ss58Format);93  }9495  toSubstrate(ss58Format?: number): CrossAccountId {96    this.account = CrossAccountId.toSubstrate(this.account, ss58Format);97    return this;98  }99100  static toSubstrate(account: ICrossAccountId, ss58Format?: number): ICrossAccountId {101    if('Ethereum' in account) return {Substrate: CrossAccountId.translateEthToSub(account.Ethereum, ss58Format)};102    return account;103  }104105  toLowerCase(): CrossAccountId {106    this.account = CrossAccountId.toLowerCase(this.account);107    return this;108  }109110  static toLowerCase(account: ICrossAccountId) {111    if('Substrate' in account) return {Substrate: account.Substrate.toLowerCase()};112    if('Ethereum' in account) return {Ethereum: account.Ethereum.toLowerCase()};113    return account;114  }115116  toICrossAccountId(): ICrossAccountId {117    return this.account;118  }119}120121const nesting = {122  toChecksumAddress(address: string): string {123    if(typeof address === 'undefined') return '';124125    if(!/^(0x)?[0-9a-f]{40}$/i.test(address)) throw new Error(`Given address "${address}" is not a valid Ethereum address.`);126127    address = address.toLowerCase().replace(/^0x/i, '');128    const addressHash = keccakAsHex(address).replace(/^0x/i, '');129    const checksumAddress = ['0x'];130131    for(let i = 0; i < address.length; i++) {132      // If ith character is 8 to f then make it uppercase133      if(parseInt(addressHash[i], 16) > 7) {134        checksumAddress.push(address[i].toUpperCase());135      } else {136        checksumAddress.push(address[i]);137      }138    }139    return checksumAddress.join('');140  },141  tokenIdToAddress(collectionId: number, tokenId: number) {142    return this.toChecksumAddress(`0xf8238ccfff8ed887463fd5e0${collectionId.toString(16).padStart(8, '0')}${tokenId.toString(16).padStart(8, '0')}`);143  },144};145146class UniqueUtil {147  static transactionStatus = {148    NOT_READY: 'NotReady',149    FAIL: 'Fail',150    SUCCESS: 'Success',151  };152153  static chainLogType = {154    EXTRINSIC: 'extrinsic',155    RPC: 'rpc',156  };157158  static getTokenAccount(token: IToken): ICrossAccountId {159    return {Ethereum: this.getTokenAddress(token)};160  }161162  static getTokenAddress(token: IToken): string {163    return nesting.tokenIdToAddress(token.collectionId, token.tokenId);164  }165166  static getDefaultLogger(): ILogger {167    return {168      log(msg: any, level = 'INFO') {169        console[level.toLocaleLowerCase() === 'error' ? 'error' : 'log'](...(Array.isArray(msg) ? msg : [msg]));170      },171      level: {172        ERROR: 'ERROR',173        WARNING: 'WARNING',174        INFO: 'INFO',175      },176    };177  }178179  static vec2str(arr: string[] | number[]) {180    return arr.map(x => String.fromCharCode(parseInt(x.toString()))).join('');181  }182183  static str2vec(string: string) {184    if(typeof string !== 'string') return string;185    return Array.from(string).map(x => x.charCodeAt(0));186  }187188  static fromSeed(seed: string, ss58Format = 42) {189    const keyring = new Keyring({type: 'sr25519', ss58Format});190    return keyring.addFromUri(seed);191  }192193  static extractCollectionIdFromCreationResult(creationResult: ITransactionResult): number {194    if(creationResult.status !== this.transactionStatus.SUCCESS) {195      throw Error('Unable to create collection!');196    }197198    let collectionId = null;199    creationResult.result.events.forEach(({event: {data, method, section}}) => {200      if((section === 'common') && (method === 'CollectionCreated')) {201        collectionId = parseInt(data[0].toString(), 10);202      }203    });204205    if(collectionId === null) {206      throw Error('No CollectionCreated event was found!');207    }208209    return collectionId;210  }211212  static extractTokensFromCreationResult(creationResult: ITransactionResult): {213    success: boolean,214    tokens: { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[],215  } {216    if(creationResult.status !== this.transactionStatus.SUCCESS) {217      throw Error('Unable to create tokens!');218    }219    let success = false;220    const tokens = [] as { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[];221    creationResult.result.events.forEach(({event: {data, method, section}}) => {222      if(method === 'ExtrinsicSuccess') {223        success = true;224      } else if((section === 'common') && (method === 'ItemCreated')) {225        tokens.push({226          collectionId: parseInt(data[0].toString(), 10),227          tokenId: parseInt(data[1].toString(), 10),228          owner: data[2].toHuman(),229          amount: data[3].toBigInt(),230        });231      }232    });233    return {success, tokens};234  }235236  static extractTokensFromBurnResult(burnResult: ITransactionResult): {237    success: boolean,238    tokens: { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[],239  } {240    if(burnResult.status !== this.transactionStatus.SUCCESS) {241      throw Error('Unable to burn tokens!');242    }243    let success = false;244    const tokens = [] as { collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint }[];245    burnResult.result.events.forEach(({event: {data, method, section}}: any) => {246      if(method === 'ExtrinsicSuccess') {247        success = true;248      } else if((section === 'common') && (method === 'ItemDestroyed')) {249        tokens.push({250          collectionId: parseInt(data[0].toString(), 10),251          tokenId: parseInt(data[1].toString(), 10),252          owner: data[2].toHuman(),253          amount: data[3].toBigInt(),254        });255      }256    });257    return {success, tokens};258  }259260  static findCollectionInEvents(events: { event: IEvent }[], collectionId: number, expectedSection: string, expectedMethod: string): boolean {261    let eventId = null;262    events.forEach(({event: {data, method, section}}) => {263      if((section === expectedSection) && (method === expectedMethod)) {264        eventId = parseInt(data[0].toString(), 10);265      }266    });267268    if(eventId === null) {269      throw Error(`No ${expectedMethod} event was found!`);270    }271    return eventId === collectionId;272  }273274  static isTokenTransferSuccess(events: { event: IEvent }[], collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {275    const normalizeAddress = (address: string | ICrossAccountId) => {276      if(typeof address === 'string') return address;277      if('Substrate' in address) return CrossAccountId.withNormalizedSubstrate(address);278      if('Ethereum' in address) return CrossAccountId.toLowerCase(address);279      return address;280    };281    let transfer = {collectionId: null, tokenId: null, from: null, to: null, amount: 1} as any;282    events.forEach(({event: {data, method, section}}) => {283      if((section === 'common') && (method === 'Transfer')) {284        transfer = {285          collectionId: data[0].toJSON(),286          tokenId: data[1].toJSON(),287          from: normalizeAddress(data[2].toHuman()),288          to: normalizeAddress(data[3].toHuman()),289          amount: BigInt(data[4].toJSON()),290        };291      }292    });293    let isSuccess = parseInt(collectionId.toString()) === transfer.collectionId && parseInt(tokenId.toString()) === transfer.tokenId;294    isSuccess = isSuccess && JSON.stringify(normalizeAddress(fromAddressObj)) === JSON.stringify(transfer.from);295    isSuccess = isSuccess && JSON.stringify(normalizeAddress(toAddressObj)) === JSON.stringify(transfer.to);296    isSuccess = isSuccess && amount === transfer.amount;297    return isSuccess;298  }299300  static bigIntToDecimals(number: bigint, decimals = 18) {301    const numberStr = number.toString();302    const dotPos = numberStr.length - decimals;303304    if(dotPos <= 0) {305      return '0.' + '0'.repeat(Math.abs(dotPos)) + numberStr;306    } else {307      const intPart = numberStr.substring(0, dotPos);308      const fractPart = numberStr.substring(dotPos);309      return intPart + '.' + fractPart;310    }311  }312}313314class UniqueEventHelper {315  static extractIndex(index: any): [number, number] | string {316    if(index.toRawType() === '[u8;2]') return [index[0], index[1]];317    return index.toJSON();318  }319320  static extractSub(data: any, subTypes: any): { [key: string]: any } {321    let obj: any = {};322    let index = 0;323324    if(data.entries) {325      for(const [key, value] of data.entries()) {326        obj[key] = this.extractData(value, subTypes[index]);327        index++;328      }329    } else obj = data.toJSON();330331    return obj;332  }333334  static toHuman(data: any) {335    return data && data.toHuman ? data.toHuman() : `${data}`;336  }337338  static extractData(data: any, type: any): any {339    if(!type) return this.toHuman(data);340    if(['u16', 'u32'].indexOf(type.type) > -1) return data.toNumber();341    if(['u64', 'u128', 'u256'].indexOf(type.type) > -1) return data.toBigInt();342    if(type.hasOwnProperty('sub')) return this.extractSub(data, type.sub);343    return this.toHuman(data);344  }345346  public static extractEvents(events: { event: any, phase: any }[]): IEvent[] {347    const parsedEvents: IEvent[] = [];348349    events.forEach((record) => {350      const {event, phase} = record;351      const types = event.typeDef;352353      const eventData: IEvent = {354        section: event.section.toString(),355        method: event.method.toString(),356        index: this.extractIndex(event.index),357        data: [],358        phase: phase.toJSON(),359      };360361      event.data.forEach((val: any, index: number) => {362        eventData.data.push(this.extractData(val, types[index]));363      });364365      parsedEvents.push(eventData);366    });367368    return parsedEvents;369  }370}371const InvalidTypeSymbol = Symbol('Invalid type');372// eslint-disable-next-line @typescript-eslint/no-unused-vars373export type Invalid =374  | ((375    invalidType: typeof InvalidTypeSymbol,376    ..._: typeof InvalidTypeSymbol[]377  ) => typeof InvalidTypeSymbol)378  | null379  | undefined;380// Has slightly better error messages than Get381type Get2<T, P extends string, E> =382  P extends `${infer Key}.${infer Key2}` ? Key extends keyof T ? Key2 extends keyof T[Key] ? T[Key][Key2] : E : E : E;383type ForceFunction<T> = T extends (...args: any) => any ? T : (...args: any) => Invalid;384385export class ChainHelperBase {386  helperBase: any;387388  transactionStatus = UniqueUtil.transactionStatus;389  chainLogType = UniqueUtil.chainLogType;390  util: typeof UniqueUtil;391  eventHelper: typeof UniqueEventHelper;392  logger: ILogger;393  api: ApiPromise | null;394  forcedNetwork: TNetworks | null;395  network: TNetworks | null;396  wsEndpoint: string | null;397  chainLog: IUniqueHelperLog[];398  children: ChainHelperBase[];399  address: AddressGroup;400  chain: ChainGroup;401402  constructor(logger?: ILogger, helperBase?: any) {403    this.helperBase = helperBase;404405    this.util = UniqueUtil;406    this.eventHelper = UniqueEventHelper;407    if(typeof logger == 'undefined') logger = this.util.getDefaultLogger();408    this.logger = logger;409    this.api = null;410    this.forcedNetwork = null;411    this.network = null;412    this.wsEndpoint = null;413    this.chainLog = [];414    this.children = [];415    this.address = new AddressGroup(this);416    this.chain = new ChainGroup(this);417  }418419  clone(helperCls: ChainHelperBaseConstructor, options: { [key: string]: any } = {}) {420    Object.setPrototypeOf(helperCls.prototype, this);421    const newHelper = new helperCls(this.logger, options);422423    newHelper.api = this.api;424    newHelper.network = this.network;425    newHelper.forceNetwork = this.forceNetwork;426427    this.children.push(newHelper);428429    return newHelper;430  }431432  getEndpoint(): string {433    if(this.wsEndpoint === null) throw Error('No connection was established');434    return this.wsEndpoint;435  }436437  getApi(): ApiPromise {438    if(this.api === null) throw Error('API not initialized');439    return this.api;440  }441442  async subscribeEvents(expectedEvents: { section: string, names: string[] }[]) {443    const collectedEvents: IEvent[] = [];444    const unsubscribe = await this.getApi().query.system.events((events: any) => {445      const ievents = this.eventHelper.extractEvents(events);446      ievents.forEach((event) => {447        expectedEvents.forEach((e => {448          if(event.section === e.section && e.names.includes(event.method)) {449            collectedEvents.push(event);450          }451        }));452      });453    });454    return {unsubscribe: unsubscribe as any, collectedEvents};455  }456457  clearChainLog(): void {458    this.chainLog = [];459  }460461  forceNetwork(value: TNetworks): void {462    this.forcedNetwork = value;463  }464465  async connect(wsEndpoint: string, listeners?: IApiListeners) {466    if(this.api !== null) throw Error('Already connected');467    const {api, network} = await ChainHelperBase.createConnection(wsEndpoint, listeners, this.forcedNetwork);468    this.wsEndpoint = wsEndpoint;469    this.api = api;470    this.network = network;471  }472473  async disconnect() {474    for(const child of this.children) {475      child.clearApi();476    }477478    if(this.api === null) return;479    await this.api.disconnect();480    this.clearApi();481  }482483  clearApi() {484    this.api = null;485    this.network = null;486  }487488  static async detectNetwork(api: ApiPromise): Promise<TNetworks> {489    const spec = (await api.query.system.lastRuntimeUpgrade()).toJSON() as any;490    const xcmChains = ['rococo', 'westend', 'westmint', 'acala', 'karura', 'moonbeam', 'moonriver'];491492    if(xcmChains.indexOf(spec.specName) > -1) return spec.specName;493494    if(['quartz', 'unique', 'sapphire'].indexOf(spec.specName) > -1) return spec.specName;495    return 'opal';496  }497498  static async detectNetworkByWsEndpoint(wsEndpoint: string): Promise<TNetworks> {499    if(!wsEndpoint) throw new Error('wsEndpoint was not set');500    const api = new ApiPromise({provider: new WsProvider(wsEndpoint)});501    await api.isReady;502503    const network = await this.detectNetwork(api);504505    await api.disconnect();506507    return network;508  }509510  static async createConnection(wsEndpoint: string, listeners?: IApiListeners, network?: TNetworks | null): Promise<{511    api: ApiPromise;512    network: TNetworks;513  }> {514    if(typeof network === 'undefined' || network === null) network = 'opal';515    if(!wsEndpoint) throw new Error('wsEndpoint was not set');516    const supportedRPC = {517      opal: {518        unique: require('@unique-nft/opal-testnet-types/definitions').unique.rpc,519      },520      quartz: {521        unique: require('@unique-nft/quartz-mainnet-types/definitions').unique.rpc,522      },523      unique: {524        unique: require('@unique-nft/unique-mainnet-types/definitions').unique.rpc,525      },526      rococo: {},527      westend: {},528      moonbeam: {},529      moonriver: {},530      acala: {},531      karura: {},532      westmint: {},533    };534    if(!supportedRPC.hasOwnProperty(network)) network = await this.detectNetworkByWsEndpoint(wsEndpoint);535    const rpc = supportedRPC[network] as any;536537    // TODO: investigate how to replace rpc in runtime538    // api._rpcCore.addUserInterfaces(rpc);539540    const api = new ApiPromise({provider: new WsProvider(wsEndpoint), rpc});541542    await api.isReadyOrError;543544    if(typeof listeners === 'undefined') listeners = {};545    for(const event of ['connected', 'disconnected', 'error', 'ready', 'decorated']) {546      if(!listeners.hasOwnProperty(event) || typeof listeners[event as TApiAllowedListeners] === 'undefined') continue;547      api.on(event as ApiInterfaceEvents, listeners[event as TApiAllowedListeners] as (...args: any[]) => any);548    }549550    return {api, network};551  }552553  getTransactionStatus(data: { events: { event: IEvent }[], status: any }) {554    const {events, status} = data;555    if(status.isReady) {556      return this.transactionStatus.NOT_READY;557    }558    if(status.isBroadcast) {559      return this.transactionStatus.NOT_READY;560    }561    if(status.isInBlock || status.isFinalized) {562      const errors = events.filter(e => e.event.method === 'ExtrinsicFailed');563      if(errors.length > 0) {564        return this.transactionStatus.FAIL;565      }566      if(events.filter(e => e.event.method === 'ExtrinsicSuccess').length > 0) {567        return this.transactionStatus.SUCCESS;568      }569    }570571    return this.transactionStatus.FAIL;572  }573574  signTransaction(sender: TSigner, transaction: any, options: Partial<SignerOptions> | null = null, label = 'transaction') {575    const sign = (callback: any) => {576      if(options !== null) return transaction.signAndSend(sender, options, callback);577      return transaction.signAndSend(sender, callback);578    };579    // eslint-disable-next-line no-async-promise-executor580    return new Promise(async (resolve, reject) => {581      try {582        const unsub = await sign((result: any) => {583          const status = this.getTransactionStatus(result);584585          if(status === this.transactionStatus.SUCCESS) {586            this.logger.log(`${label} successful`);587            unsub();588            resolve({result, status, blockHash: result.status.asInBlock.toHuman()});589          } else if(status === this.transactionStatus.FAIL) {590            let moduleError = null;591592            if(result.hasOwnProperty('dispatchError')) {593              const dispatchError = result['dispatchError'];594595              if(dispatchError) {596                if(dispatchError.isModule) {597                  const modErr = dispatchError.asModule;598                  const errorMeta = dispatchError.registry.findMetaError(modErr);599600                  moduleError = `${errorMeta.section}.${errorMeta.name}`;601                } else if(dispatchError.isToken) {602                  moduleError = `Token: ${dispatchError.asToken}`;603                } else {604                  // May be [object Object] in case of unhandled non-unit enum605                  moduleError = `Misc: ${dispatchError.toHuman()}`;606                }607              } else {608                this.logger.log(result, this.logger.level.ERROR);609              }610            }611612            this.logger.log(`Something went wrong with ${label}. Status: ${status}`, this.logger.level.ERROR);613            unsub();614            reject({status, moduleError, result});615          }616        });617      } catch (e) {618        this.logger.log(e, this.logger.level.ERROR);619        reject(e);620      }621    });622  }623624  async signTransactionWithoutSending(signer: TSigner, tx: any) {625    const api = this.getApi();626    const signingInfo = await api.derive.tx.signingInfo(signer.address);627628    tx.sign(signer, {629      blockHash: api.genesisHash,630      genesisHash: api.genesisHash,631      runtimeVersion: api.runtimeVersion,632      nonce: signingInfo.nonce,633    });634635    return tx.toHex();636  }637638  async getPaymentInfo(signer: TSigner, tx: any, len: number | null) {639    const api = this.getApi();640    const signingInfo = await api.derive.tx.signingInfo(signer.address);641642    // We need to sign the tx because643    // unsigned transactions does not have an inclusion fee644    tx.sign(signer, {645      blockHash: api.genesisHash,646      genesisHash: api.genesisHash,647      runtimeVersion: api.runtimeVersion,648      nonce: signingInfo.nonce,649    });650651    if(len === null) {652      return (await this.callRpc('api.rpc.payment.queryInfo', [tx.toHex()])) as RuntimeDispatchInfo;653    } else {654      return (await api.call.transactionPaymentApi.queryInfo(tx, len)) as RuntimeDispatchInfo;655    }656  }657658  constructApiCall(apiCall: string, params: any[]) {659    if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);660    let call = this.getApi() as any;661    for(const part of apiCall.slice(4).split('.')) {662      call = call[part];663      if(!call) {664        const advice = part.includes('_') ? ' Looks like it needs to be converted to camel case.' : '';665        throw Error(`Function ${part} of api call ${apiCall} not found.${advice}`);666      }667    }668    return call(...params);669  }670671  encodeApiCall(apiCall: string, params: any[]) {672    return this.constructApiCall(apiCall, params).method.toHex();673  }674675  async executeExtrinsic<676    E extends string,677    V extends (678      ...args: any) => any = ForceFunction<679        Get2<680          AugmentedSubmittables<'promise'>,681          E, (...args: any) => Invalid682        >683      >684  >(685    sender: TSigner,686    extrinsic: `api.tx.${E}`,687    params: Parameters<V>,688    expectSuccess = true,689    options: Partial<SignerOptions> | null = null,/*, failureMessage='expected success'*/690  ): Promise<ITransactionResult> {691    if(this.api === null) throw Error('API not initialized');692693    const startTime = (new Date()).getTime();694    let result: ITransactionResult;695    let events: IEvent[] = [];696    try {697      result = await this.signTransaction(sender, this.constructApiCall(extrinsic, params), options, extrinsic) as ITransactionResult;698      events = this.eventHelper.extractEvents(result.result.events);699      const errorEvent = events.find((event) => event.method == 'ExecutedFailed' || event.method == 'CreatedFailed');700      if(errorEvent)701        throw Error(errorEvent.method + ': ' + extrinsic);702    }703    catch (e) {704      if(!(e as object).hasOwnProperty('status')) throw e;705      result = e as ITransactionResult;706    }707708    const endTime = (new Date()).getTime();709710    const log = {711      executedAt: endTime,712      executionTime: endTime - startTime,713      type: this.chainLogType.EXTRINSIC,714      status: result.status,715      call: extrinsic,716      signer: this.getSignerAddress(sender),717      params,718    } as IUniqueHelperLog;719720    let errorMessage = '';721722    if(result.status !== this.transactionStatus.SUCCESS) {723      if(result.moduleError) {724        errorMessage = typeof result.moduleError === 'string'725          ? result.moduleError726          : `${Object.keys(result.moduleError)[0]}: ${Object.values(result.moduleError)[0]}`;727        log.moduleError = errorMessage;728      }729      else if(result.result.dispatchError) log.dispatchError = result.result.dispatchError;730    }731    if(events.length > 0) log.events = events;732733    this.chainLog.push(log);734735    if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) {736      if(result.moduleError) throw Error(`${errorMessage}`);737      else if(result.result.dispatchError) throw Error(JSON.stringify(result.result.dispatchError));738    }739    return result as any;740  }741  executeExtrinsicUncheckedWeight<742      E extends string,743      V extends (744         ...args: any) => any = ForceFunction<745            Get2<746               AugmentedSubmittables<'promise'>,747               E, (...args: any) => Invalid748            >749         >750   >(751    _sender: TSigner,752    _extrinsic: `api.tx.${E}`,753    _params: Parameters<V>,754    _expectSuccess = true,755    _options: Partial<SignerOptions> | null = null,/*, failureMessage='expected success'*/756  ): Promise<ITransactionResult> {757    throw new Error('executeExtrinsicUncheckedWeight only supported in sudo');758  }759760  async callRpc761  // TODO: make it strongly typed, or use api.query/api.rpc directly762  // <763  // K extends 'rpc' | 'query',764  // E extends string,765  // V extends (...args: any) => any = ForceFunction<766  //   Get2<767  //     K extends 'rpc' ? DecoratedRpc<'promise', RpcInterface> : QueryableStorage<'promise'>,768  //     E, (...args: any) => Invalid<'not found'>769  //   >770  // >,771  // P = Parameters<V>,772  // >773  (rpc: string, params?: any[]): Promise<any> {774775    if(typeof params === 'undefined') params = [] as any;776    if(this.api === null) throw Error('API not initialized');777    if(!rpc.startsWith('api.rpc.') && !rpc.startsWith('api.query.')) throw Error(`${rpc} is not RPC call`);778779    const startTime = (new Date()).getTime();780    let result;781    let error = null;782    const log = {783      type: this.chainLogType.RPC,784      call: rpc,785      params,786    } as any as IUniqueHelperLog;787788    try {789      result = await this.constructApiCall(rpc, params as any);790    }791    catch (e) {792      error = e;793    }794795    const endTime = (new Date()).getTime();796797    log.executedAt = endTime;798    log.status = (error === null ? this.transactionStatus.SUCCESS : this.transactionStatus.FAIL) as 'Fail' | 'Success';799    log.executionTime = endTime - startTime;800801    this.chainLog.push(log);802803    if(error !== null) throw error;804805    return result;806  }807808  getSignerAddress(signer: IKeyringPair | string): string {809    if(typeof signer === 'string') return signer;810    return signer.address;811  }812813  fetchAllPalletNames(): string[] {814    if(this.api === null) throw Error('API not initialized');815    return this.api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase()).sort();816  }817818  fetchMissingPalletNames(requiredPallets: readonly string[]): string[] {819    const palletNames = this.fetchAllPalletNames();820    return requiredPallets.filter(p => !palletNames.includes(p));821  }822}823824825export class HelperGroup<T extends ChainHelperBase> {826  helper: T;827828  constructor(uniqueHelper: T) {829    this.helper = uniqueHelper;830  }831}832833834class CollectionGroup extends HelperGroup<UniqueHelper> {835  /**836 * Get number of blocks when sponsored transaction is available.837 *838 * @param collectionId ID of collection839 * @param tokenId ID of token840 * @param addressObj address for which the sponsorship is checked841 * @example await getTokenNextSponsored(1, 2, {Substrate: '5DfhbVfww7ThF8q6f3...'});842 * @returns number of blocks or null if sponsorship hasn't been set843 */844  async getTokenNextSponsored(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<number | null> {845    return (await this.helper.callRpc('api.rpc.unique.nextSponsored', [collectionId, addressObj, tokenId])).toJSON();846  }847848  /**849   * Get the number of created collections.850   *851   * @returns number of created collections852   */853  async getTotalCount(): Promise<number> {854    return (await this.helper.callRpc('api.rpc.unique.collectionStats')).created.toNumber();855  }856857  /**858   * Get information about the collection with additional data,859   * including the number of tokens it contains, its administrators,860   * the normalized address of the collection's owner, and decoded name and description.861   *862   * @param collectionId ID of collection863   * @example await getData(2)864   * @returns collection information object865   */866  async getData(collectionId: number): Promise<{867    id: number;868    name: string;869    description: string;870    tokensCount: number;871    admins: CrossAccountId[];872    normalizedOwner: TSubstrateAccount;873    raw: any874  } | null> {875    const collection = await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId]);876    const humanCollection = collection.toHuman(), collectionData = {877      id: collectionId, name: null, description: null, tokensCount: 0, admins: [],878      raw: humanCollection,879    } as any, jsonCollection = collection.toJSON();880    if(humanCollection === null) return null;881    collectionData.raw.limits = jsonCollection.limits;882    collectionData.raw.permissions = jsonCollection.permissions;883    collectionData.normalizedOwner = this.helper.address.normalizeSubstrate(collectionData.raw.owner);884    for(const key of ['name', 'description']) {885      collectionData[key] = this.helper.util.vec2str(humanCollection[key]);886    }887888    collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode))889      ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId)890      : 0;891    collectionData.admins = await this.getAdmins(collectionId);892893    return collectionData;894  }895896  /**897   * Get the addresses of the collection's administrators, optionally normalized.898   *899   * @param collectionId ID of collection900   * @param normalize whether to normalize the addresses to the default ss58 format901   * @example await getAdmins(1)902   * @returns array of administrators903   */904  async getAdmins(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {905    const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman() as ICrossAccountId[];906907    return normalize908      ? admins.map(address => CrossAccountId.withNormalizedSubstrate(address))909      : admins;910  }911912  /**913   * Get the addresses added to the collection allow-list, optionally normalized.914   * @param collectionId ID of collection915   * @param normalize whether to normalize the addresses to the default ss58 format916   * @example await getAllowList(1)917   * @returns array of allow-listed addresses918   */919  async getAllowList(collectionId: number, normalize = false): Promise<ICrossAccountId[]> {920    const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman() as ICrossAccountId[];921    return normalize922      ? allowListed.map(address => CrossAccountId.withNormalizedSubstrate(address))923      : allowListed;924  }925926  /**927   * Get the effective limits of the collection instead of null for default values928   *929   * @param collectionId ID of collection930   * @example await getEffectiveLimits(2)931   * @returns object of collection limits932   */933  async getEffectiveLimits(collectionId: number): Promise<ICollectionLimits> {934    return (await this.helper.callRpc('api.rpc.unique.effectiveCollectionLimits', [collectionId])).toJSON();935  }936937  /**938   * Burns the collection if the signer has sufficient permissions and collection is empty.939   *940   * @param signer keyring of signer941   * @param collectionId ID of collection942   * @example await helper.collection.burn(aliceKeyring, 3);943   * @returns ```true``` if extrinsic success, otherwise ```false```944   */945  async burn(signer: TSigner, collectionId: number): Promise<boolean> {946    const result = await this.helper.executeExtrinsic(947      signer,948      'api.tx.unique.destroyCollection', [collectionId],949      true,950    );951952    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed');953  }954955  /**956   * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.957   *958   * @param signer keyring of signer959   * @param collectionId ID of collection960   * @param sponsorAddress Sponsor substrate address961   * @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")962   * @returns ```true``` if extrinsic success, otherwise ```false```963   */964  async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise<boolean> {965    const result = await this.helper.executeExtrinsic(966      signer,967      'api.tx.unique.setCollectionSponsor', [collectionId, sponsorAddress],968      true,969    );970971    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorSet');972  }973974  /**975   * Confirms consent to sponsor the collection on behalf of the signer.976   *977   * @param signer keyring of signer978   * @param collectionId ID of collection979   * @example confirmSponsorship(aliceKeyring, 10)980   * @returns ```true``` if extrinsic success, otherwise ```false```981   */982  async confirmSponsorship(signer: TSigner, collectionId: number): Promise<boolean> {983    const result = await this.helper.executeExtrinsic(984      signer,985      'api.tx.unique.confirmSponsorship', [collectionId],986      true,987    );988989    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'SponsorshipConfirmed');990  }991992  /**993   * Removes the sponsor of a collection, regardless if it consented or not.994   *995   * @param signer keyring of signer996   * @param collectionId ID of collection997   * @example removeSponsor(aliceKeyring, 10)998   * @returns ```true``` if extrinsic success, otherwise ```false```999   */1000  async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {1001    const result = await this.helper.executeExtrinsic(1002      signer,1003      'api.tx.unique.removeCollectionSponsor', [collectionId],1004      true,1005    );10061007    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorRemoved');1008  }10091010  /**1011   * Sets the limits of the collection. At least one limit must be specified for a correct call.1012   *1013   * @param signer keyring of signer1014   * @param collectionId ID of collection1015   * @param limits collection limits object1016   * @example1017   * await setLimits(1018   *   aliceKeyring,1019   *   10,1020   *   {1021   *     sponsorTransferTimeout: 0,1022   *     ownerCanDestroy: false1023   *   }1024   * )1025   * @returns ```true``` if extrinsic success, otherwise ```false```1026   */1027  async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise<boolean> {1028    const result = await this.helper.executeExtrinsic(1029      signer,1030      'api.tx.unique.setCollectionLimits', [collectionId, limits],1031      true,1032    );10331034    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionLimitSet');1035  }10361037  /**1038   * Changes the owner of the collection to the new Substrate address.1039   *1040   * @param signer keyring of signer1041   * @param collectionId ID of collection1042   * @param ownerAddress substrate address of new owner1043   * @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")1044   * @returns ```true``` if extrinsic success, otherwise ```false```1045   */1046  async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise<boolean> {1047    const result = await this.helper.executeExtrinsic(1048      signer,1049      'api.tx.unique.changeCollectionOwner', [collectionId, ownerAddress],1050      true,1051    );10521053    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionOwnerChanged');1054  }10551056  /**1057   * Adds a collection administrator.1058   *1059   * @param signer keyring of signer1060   * @param collectionId ID of collection1061   * @param adminAddressObj Administrator address (substrate or ethereum)1062   * @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})1063   * @returns ```true``` if extrinsic success, otherwise ```false```1064   */1065  async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {1066    const result = await this.helper.executeExtrinsic(1067      signer,1068      'api.tx.unique.addCollectionAdmin', [collectionId, adminAddressObj],1069      true,1070    );10711072    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminAdded');1073  }10741075  /**1076   * Removes a collection administrator.1077   *1078   * @param signer keyring of signer1079   * @param collectionId ID of collection1080   * @param adminAddressObj Administrator address (substrate or ethereum)1081   * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})1082   * @returns ```true``` if extrinsic success, otherwise ```false```1083   */1084  async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {1085    const result = await this.helper.executeExtrinsic(1086      signer,1087      'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj],1088      true,1089    );10901091    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminRemoved');1092  }10931094  /**1095   * Check if user is in allow list.1096   *1097   * @param collectionId ID of collection1098   * @param user Account to check1099   * @example await getAdmins(1)1100   * @returns is user in allow list1101   */1102  async allowed(collectionId: number, user: ICrossAccountId): Promise<boolean> {1103    return (await this.helper.callRpc('api.rpc.unique.allowed', [collectionId, user])).toJSON();1104  }11051106  /**1107   * Adds an address to allow list1108   * @param signer keyring of signer1109   * @param collectionId ID of collection1110   * @param addressObj address to add to the allow list1111   * @returns ```true``` if extrinsic success, otherwise ```false```1112   */1113  async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {1114    const result = await this.helper.executeExtrinsic(1115      signer,1116      'api.tx.unique.addToAllowList', [collectionId, addressObj],1117      true,1118    );11191120    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressAdded');1121  }11221123  /**1124   * Removes an address from allow list1125   *1126   * @param signer keyring of signer1127   * @param collectionId ID of collection1128   * @param addressObj address to remove from the allow list1129   * @returns ```true``` if extrinsic success, otherwise ```false```1130   */1131  async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {1132    const result = await this.helper.executeExtrinsic(1133      signer,1134      'api.tx.unique.removeFromAllowList', [collectionId, addressObj],1135      true,1136    );11371138    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressRemoved');1139  }11401141  /**1142   * Sets onchain permissions for selected collection.1143   *1144   * @param signer keyring of signer1145   * @param collectionId ID of collection1146   * @param permissions collection permissions object1147   * @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}});1148   * @returns ```true``` if extrinsic success, otherwise ```false```1149   */1150  async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise<boolean> {1151    const result = await this.helper.executeExtrinsic(1152      signer,1153      'api.tx.unique.setCollectionPermissions', [collectionId, permissions],1154      true,1155    );11561157    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPermissionSet');1158  }11591160  /**1161   * Enables nesting for selected collection. If `restricted` set, you can nest only tokens from specified collections.1162   *1163   * @param signer keyring of signer1164   * @param collectionId ID of collection1165   * @param permissions nesting permissions object1166   * @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true});1167   * @returns ```true``` if extrinsic success, otherwise ```false```1168   */1169  async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise<boolean> {1170    return await this.setPermissions(signer, collectionId, {nesting: permissions});1171  }11721173  /**1174   * Disables nesting for selected collection.1175   *1176   * @param signer keyring of signer1177   * @param collectionId ID of collection1178   * @example disableNesting(aliceKeyring, 10);1179   * @returns ```true``` if extrinsic success, otherwise ```false```1180   */1181  async disableNesting(signer: TSigner, collectionId: number): Promise<boolean> {1182    return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}});1183  }11841185  /**1186   * Sets onchain properties to the collection.1187   *1188   * @param signer keyring of signer1189   * @param collectionId ID of collection1190   * @param properties array of property objects1191   * @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]);1192   * @returns ```true``` if extrinsic success, otherwise ```false```1193   */1194  async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise<boolean> {1195    const result = await this.helper.executeExtrinsic(1196      signer,1197      'api.tx.unique.setCollectionProperties', [collectionId, properties],1198      true,1199    );12001201    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');1202  }12031204  /**1205   * Get collection properties.1206   *1207   * @param collectionId ID of collection1208   * @param propertyKeys optionally filter the returned properties to only these keys1209   * @example getProperties(1219, ['location', 'date', 'time', 'isParadise']);1210   * @returns array of key-value pairs1211   */1212  async getProperties(collectionId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1213    return (await this.helper.callRpc('api.rpc.unique.collectionProperties', [collectionId, propertyKeys])).toHuman();1214  }12151216  async getPropertiesConsumedSpace(collectionId: number): Promise<number> {1217    const api = this.helper.getApi();1218    const props = (await api.query.common.collectionProperties(collectionId)).toJSON();12191220    return (props! as any).consumedSpace;1221  }12221223  async getCollectionOptions(collectionId: number) {1224    return (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1225  }12261227  /**1228   * Deletes onchain properties from the collection.1229   *1230   * @param signer keyring of signer1231   * @param collectionId ID of collection1232   * @param propertyKeys array of property keys to delete1233   * @example deleteProperties(aliceKeyring, 10, ["gender", "age"]);1234   * @returns ```true``` if extrinsic success, otherwise ```false```1235   */1236  async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise<boolean> {1237    const result = await this.helper.executeExtrinsic(1238      signer,1239      'api.tx.unique.deleteCollectionProperties', [collectionId, propertyKeys],1240      true,1241    );12421243    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted');1244  }12451246  /**1247   * Changes the owner of the token.1248   *1249   * @param signer keyring of signer1250   * @param collectionId ID of collection1251   * @param tokenId ID of token1252   * @param addressObj address of a new owner1253   * @param amount amount of tokens to be transfered. For NFT must be set to 1n1254   * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1255   * @returns true if the token success, otherwise false1256   */1257  async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount = 1n): Promise<boolean> {1258    const result = await this.helper.executeExtrinsic(1259      signer,1260      'api.tx.unique.transfer', [addressObj, collectionId, tokenId, amount],1261      true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1262    );12631264    return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount);1265  }12661267  /**1268   *1269   * Change ownership of a token(s) on behalf of the owner.1270   *1271   * @param signer keyring of signer1272   * @param collectionId ID of collection1273   * @param tokenId ID of token1274   * @param fromAddressObj address on behalf of which the token will be sent1275   * @param toAddressObj new token owner1276   * @param amount amount of tokens to be transfered. For NFT must be set to 1n1277   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg"}, {Ethereum: "0x9F0583DbB85..."})1278   * @returns true if the token success, otherwise false1279   */1280  async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {1281    const result = await this.helper.executeExtrinsic(1282      signer,1283      'api.tx.unique.transferFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],1284      true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1285    );1286    return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1287  }12881289  /**1290   *1291   * Destroys a concrete instance of NFT/RFT or burns a specified amount of fungible tokens.1292   *1293   * @param signer keyring of signer1294   * @param collectionId ID of collection1295   * @param tokenId ID of token1296   * @param amount amount of tokens to be burned. For NFT must be set to 1n1297   * @example burnToken(aliceKeyring, 10, 5);1298   * @returns ```true``` if the extrinsic is successful, otherwise ```false```1299   */1300  async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount = 1n): Promise<boolean> {1301    const burnResult = await this.helper.executeExtrinsic(1302      signer,1303      'api.tx.unique.burnItem', [collectionId, tokenId, amount],1304      true, // `Unable to burn token for ${label}`,1305    );1306    const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1307    if(burnedTokens.tokens.length > 1) throw Error('Burned multiple tokens');1308    return burnedTokens.success;1309  }13101311  /**1312   * Destroys a concrete instance of NFT on behalf of the owner1313   *1314   * @param signer keyring of signer1315   * @param collectionId ID of collection1316   * @param tokenId ID of token1317   * @param fromAddressObj address on behalf of which the token will be burnt1318   * @param amount amount of tokens to be burned. For NFT must be set to 1n1319   * @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."})1320   * @returns ```true``` if extrinsic success, otherwise ```false```1321   */1322  async burnTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {1323    const burnResult = await this.helper.executeExtrinsic(1324      signer,1325      'api.tx.unique.burnFrom', [collectionId, fromAddressObj, tokenId, amount],1326      true, // `Unable to burn token from for ${label}`,1327    );1328    const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1329    return burnedTokens.success && burnedTokens.tokens.length > 0;1330  }13311332  /**1333   * Set, change, or remove approved address to transfer the ownership of the NFT.1334   *1335   * @param signer keyring of signer1336   * @param collectionId ID of collection1337   * @param tokenId ID of token1338   * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens1339   * @param amount amount of token to be approved. For NFT must be set to 1n1340   * @returns ```true``` if extrinsic success, otherwise ```false```1341   */1342  async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {1343    const approveResult = await this.helper.executeExtrinsic(1344      signer,1345      'api.tx.unique.approve', [toAddressObj, collectionId, tokenId, amount],1346      true, // `Unable to approve token for ${label}`,1347    );13481349    return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');1350  }13511352  /**1353   * Set, change, or remove approved address to transfer the ownership of the NFT from eth mirror.1354   *1355   * @param signer keyring of signer1356   * @param collectionId ID of collection1357   * @param tokenId ID of token1358   * @param fromAddressObj Signer's Ethereum address containing her tokens1359   * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens1360   * @param amount amount of token to be approved. For NFT must be set to 1n1361   * @returns ```true``` if extrinsic success, otherwise ```false```1362   */1363  async approveTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {1364    const approveResult = await this.helper.executeExtrinsic(1365      signer,1366      'api.tx.unique.approveFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],1367      true, // `Unable to approve token for ${label}`,1368    );13691370    return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');1371  }13721373  /**1374   * Set, change, or remove approved address to transfer the ownership of the NFT from eth mirror.1375   *1376   * @param signer keyring of signer1377   * @param collectionId ID of collection1378   * @param tokenId ID of token1379   * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens1380   * @param amount amount of token to be approved. For NFT must be set to 1n1381   * @returns ```true``` if extrinsic success, otherwise ```false```1382   */1383  async approveTokenFromEth(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {1384    const ethMirror = CrossAccountId.fromKeyring(signer).toEthereum().toICrossAccountId();1385    return await this.approveTokenFrom(signer, collectionId, tokenId, ethMirror, toAddressObj, amount);1386  }13871388  /**1389   * Get the amount of token pieces approved to transfer or burn. Normally 0.1390   *1391   * @param collectionId ID of collection1392   * @param tokenId ID of token1393   * @param toAccountObj address which is approved to use token pieces1394   * @param fromAccountObj address which may have allowed the use of its owned tokens1395   * @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."})1396   * @returns number of approved to transfer pieces1397   */1398  async getTokenApprovedPieces(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId, fromAccountObj: ICrossAccountId): Promise<bigint> {1399    return (await this.helper.callRpc('api.rpc.unique.allowance', [collectionId, fromAccountObj, toAccountObj, tokenId])).toBigInt();1400  }14011402  /**1403   * Get the last created token ID in a collection1404   *1405   * @param collectionId ID of collection1406   * @example getLastTokenId(10);1407   * @returns id of the last created token1408   */1409  async getLastTokenId(collectionId: number): Promise<number> {1410    return (await this.helper.callRpc('api.rpc.unique.lastTokenId', [collectionId])).toNumber();1411  }14121413  /**1414   * Check if token exists1415   *1416   * @param collectionId ID of collection1417   * @param tokenId ID of token1418   * @example doesTokenExist(10, 20);1419   * @returns true if the token exists, otherwise false1420   */1421  async doesTokenExist(collectionId: number, tokenId: number): Promise<boolean> {1422    return (await this.helper.callRpc('api.rpc.unique.tokenExists', [collectionId, tokenId])).toJSON();1423  }1424}14251426class NFTnRFT extends CollectionGroup {1427  /**1428   * Get tokens owned by account1429   *1430   * @param collectionId ID of collection1431   * @param addressObj tokens owner1432   * @example getTokensByAddress(10, {Substrate: "5DyN4Y92vZCjv38fg..."})1433   * @returns array of token ids owned by account1434   */1435  async getTokensByAddress(collectionId: number, addressObj: ICrossAccountId): Promise<number[]> {1436    return (await this.helper.callRpc('api.rpc.unique.accountTokens', [collectionId, addressObj])).toJSON();1437  }14381439  /**1440   * Get token data1441   *1442   * @param collectionId ID of collection1443   * @param tokenId ID of token1444   * @param propertyKeys optionally filter the token properties to only these keys1445   * @param blockHashAt optionally query the data at some block with this hash1446   * @example getToken(10, 5);1447   * @returns human readable token data1448   */1449  async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{1450    properties: IProperty[];1451    owner: ICrossAccountId;1452    normalizedOwner: ICrossAccountId;1453  } | null> {1454    let args;1455    if(typeof blockHashAt === 'undefined') {1456      args = [collectionId, tokenId];1457    }1458    else {1459      if(propertyKeys.length == 0) {1460        const collection = (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1461        if(!collection) return null;1462        propertyKeys = collection.tokenPropertyPermissions.map((x: ITokenPropertyPermission) => x.key);1463      }1464      args = [collectionId, tokenId, propertyKeys, blockHashAt];1465    }1466    const tokenData = (await this.helper.callRpc('api.rpc.unique.tokenData', args)).toHuman();1467    if(tokenData === null || tokenData.owner === null) return null;1468    tokenData.normalizedOwner = CrossAccountId.withNormalizedSubstrate(tokenData.owner);1469    return tokenData;1470  }14711472  /**1473   * Get token's owner1474   * @param collectionId ID of collection1475   * @param tokenId ID of token1476   * @param blockHashAt optionally query the data at the block with this hash1477   * @example getTokenOwner(10, 5);1478   * @returns Address in CrossAccountId format, e.g. {Substrate: "5DnSF6RRjwteE3BrCj..."}1479   */1480  async getTokenOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<ICrossAccountId> {1481    let owner;1482    if(typeof blockHashAt === 'undefined') {1483      owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId]);1484    } else {1485      owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId, blockHashAt]);1486    }1487    return CrossAccountId.fromLowerCaseKeys(owner.toJSON()).toICrossAccountId();1488  }14891490  /**1491   * Recursively find the address that owns the token1492   * @param collectionId ID of collection1493   * @param tokenId ID of token1494   * @param blockHashAt1495   * @example getTokenTopmostOwner(10, 5);1496   * @returns address in CrossAccountId format, e.g. {Substrate: "5DyN4Y92vZCjv38fg..."}1497   */1498  async getTokenTopmostOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<ICrossAccountId | null> {1499    let owner;1500    if(typeof blockHashAt === 'undefined') {1501      owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId]);1502    } else {1503      owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId, blockHashAt]);1504    }15051506    if(owner === null) return null;15071508    return owner.toHuman();1509  }15101511  /**1512   * Nest one token into another1513   * @param signer keyring of signer1514   * @param tokenObj token to be nested1515   * @param rootTokenObj token to be parent1516   * @example nestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4});1517   * @returns ```true``` if extrinsic success, otherwise ```false```1518   */1519  async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise<boolean> {1520    const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1521    const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress);1522    if(!result) {1523      throw Error('Unable to nest token!');1524    }1525    return result;1526  }15271528  /**1529     * Remove token from nested state1530     * @param signer keyring of signer1531     * @param tokenObj token to unnest1532     * @param rootTokenObj parent of a token1533     * @param toAddressObj address of a new token owner1534     * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});1535     * @returns ```true``` if extrinsic success, otherwise ```false```1536     */1537  async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {1538    const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1539    const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);1540    if(!result) {1541      throw Error('Unable to unnest token!');1542    }1543    return result;1544  }15451546  /**1547   * Set permissions to change token properties1548   *1549   * @param signer keyring of signer1550   * @param collectionId ID of collection1551   * @param permissions permissions to change a property by the collection admin or token owner1552   * @example setTokenPropertyPermissions(1553   *   aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}]1554   * )1555   * @returns true if extrinsic success otherwise false1556   */1557  async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise<boolean> {1558    const result = await this.helper.executeExtrinsic(1559      signer,1560      'api.tx.unique.setTokenPropertyPermissions', [collectionId, permissions],1561      true,1562    );15631564    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');1565  }15661567  /**1568   * Get token property permissions.1569   *1570   * @param collectionId ID of collection1571   * @param propertyKeys optionally filter the returned property permissions to only these keys1572   * @example getPropertyPermissions(1219, ['location', 'date', 'time', 'isParadise']);1573   * @returns array of key-permission pairs1574   */1575  async getPropertyPermissions(collectionId: number, propertyKeys: string[] | null = null): Promise<ITokenPropertyPermission[]> {1576    return (await this.helper.callRpc('api.rpc.unique.propertyPermissions', [collectionId, ...(propertyKeys === null ? [] : [propertyKeys])])).toHuman();1577  }15781579  /**1580   * Set token properties1581   *1582   * @param signer keyring of signer1583   * @param collectionId ID of collection1584   * @param tokenId ID of token1585   * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection1586   * @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}])1587   * @returns ```true``` if extrinsic success, otherwise ```false```1588   */1589  async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise<boolean> {1590    const result = await this.helper.executeExtrinsic(1591      signer,1592      'api.tx.unique.setTokenProperties', [collectionId, tokenId, properties],1593      true,1594    );15951596    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');1597  }15981599  /**1600   * Get properties, metadata assigned to a token.1601   *1602   * @param collectionId ID of collection1603   * @param tokenId ID of token1604   * @param propertyKeys optionally filter the returned properties to only these keys1605   * @example getTokenProperties(1219, ['location', 'date', 'time', 'isParadise']);1606   * @returns array of key-value pairs1607   */1608  async getTokenProperties(collectionId: number, tokenId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1609    return (await this.helper.callRpc('api.rpc.unique.tokenProperties', [collectionId, tokenId, propertyKeys])).toHuman();1610  }16111612  /**1613   * Delete the provided properties of a token1614   * @param signer keyring of signer1615   * @param collectionId ID of collection1616   * @param tokenId ID of token1617   * @param propertyKeys property keys to be deleted1618   * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"])1619   * @returns ```true``` if extrinsic success, otherwise ```false```1620   */1621  async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise<boolean> {1622    const result = await this.helper.executeExtrinsic(1623      signer,1624      'api.tx.unique.deleteTokenProperties', [collectionId, tokenId, propertyKeys],1625      true,1626    );16271628    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted');1629  }16301631  /**1632   * Mint new collection1633   *1634   * @param signer keyring of signer1635   * @param collectionOptions basic collection options and properties1636   * @param mode NFT or RFT type of a collection1637   * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")1638   * @returns object of the created collection1639   */1640  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueBaseCollection> {1641    collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1642    collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};1643    for(const key of ['name', 'description', 'tokenPrefix']) {1644      if(typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);1645    }16461647    let flags = 0;1648    // convert CollectionFlags to number and join them in one number1649    if(collectionOptions.flags) {1650      for(let i = 0; i < collectionOptions.flags.length; i++){1651        const flag = collectionOptions.flags[i];1652        flags = flags | flag;1653      }1654    }1655    collectionOptions.flags = [flags];16561657    const creationResult = await this.helper.executeExtrinsic(1658      signer,1659      'api.tx.unique.createCollectionEx', [collectionOptions],1660      true, // errorLabel,1661    );1662    return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));1663  }16641665  getCollectionObject(_collectionId: number): any {1666    return null;1667  }16681669  getTokenObject(_collectionId: number, _tokenId: number): any {1670    return null;1671  }16721673  /**1674   * Tells whether the given `owner` approves the `operator`.1675   * @param collectionId ID of collection1676   * @param owner owner address1677   * @param operator operator addrees1678   * @returns true if operator is enabled1679   */1680  async allowanceForAll(collectionId: number, owner: ICrossAccountId, operator: ICrossAccountId): Promise<boolean> {1681    return (await this.helper.callRpc('api.rpc.unique.allowanceForAll', [collectionId, owner, operator])).toJSON();1682  }16831684  /** Sets or unsets the approval of a given operator.1685   *  The `operator` is allowed to transfer all tokens of the `caller` on their behalf.1686   *  @param operator Operator1687   *  @param approved Should operator status be granted or revoked?1688   *  @returns ```true``` if extrinsic success, otherwise ```false```1689   */1690  async setAllowanceForAll(signer: TSigner, collectionId: number, operator: ICrossAccountId, approved: boolean): Promise<boolean> {1691    const result = await this.helper.executeExtrinsic(1692      signer,1693      'api.tx.unique.setAllowanceForAll', [collectionId, operator, approved],1694      true,1695    );1696    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'ApprovedForAll');1697  }1698}169917001701class NFTGroup extends NFTnRFT {1702  /**1703   * Get collection object1704   * @param collectionId ID of collection1705   * @example getCollectionObject(2);1706   * @returns instance of UniqueNFTCollection1707   */1708  override getCollectionObject(collectionId: number): UniqueNFTCollection {1709    return new UniqueNFTCollection(collectionId, this.helper);1710  }17111712  /**1713   * Get token object1714   * @param collectionId ID of collection1715   * @param tokenId ID of token1716   * @example getTokenObject(10, 5);1717   * @returns instance of UniqueNFTToken1718   */1719  override getTokenObject(collectionId: number, tokenId: number): UniqueNFToken {1720    return new UniqueNFToken(tokenId, this.getCollectionObject(collectionId));1721  }17221723  /**1724   * Is token approved to transfer1725   * @param collectionId ID of collection1726   * @param tokenId ID of token1727   * @param toAccountObj address to be approved1728   * @returns ```true``` if extrinsic success, otherwise ```false```1729   */1730  async isTokenApproved(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId): Promise<boolean> {1731    return (await this.getTokenApprovedPieces(collectionId, tokenId, toAccountObj, (await this.getTokenOwner(collectionId, tokenId)))) === 1n;1732  }17331734  /**1735   * Changes the owner of the token.1736   *1737   * @param signer keyring of signer1738   * @param collectionId ID of collection1739   * @param tokenId ID of token1740   * @param addressObj address of a new owner1741   * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1742   * @returns ```true``` if extrinsic success, otherwise ```false```1743   */1744  override async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<boolean> {1745    return await super.transferToken(signer, collectionId, tokenId, addressObj, 1n);1746  }17471748  /**1749   *1750   * Change ownership of a NFT on behalf of the owner.1751   *1752   * @param signer keyring of signer1753   * @param collectionId ID of collection1754   * @param tokenId ID of token1755   * @param fromAddressObj address on behalf of which the token will be sent1756   * @param toAddressObj new token owner1757   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Ethereum: "0x9F0583DbB85..."})1758   * @returns ```true``` if extrinsic success, otherwise ```false```1759   */1760  override async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId): Promise<boolean> {1761    return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, 1n);1762  }17631764  /**1765   * Get tokens nested in the provided token1766   * @param collectionId ID of collection1767   * @param tokenId ID of token1768   * @param blockHashAt optionally query the data at the block with this hash1769   * @example getTokenChildren(10, 5);1770   * @returns tokens whose depth of nesting is <= 51771   */1772  async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {1773    let children;1774    if(typeof blockHashAt === 'undefined') {1775      children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId]);1776    } else {1777      children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId, blockHashAt]);1778    }17791780    return children.toJSON().map((x: any) => ({collectionId: x.collection, tokenId: x.token}));1781  }17821783  /**1784   * Mint new collection1785   * @param signer keyring of signer1786   * @param collectionOptions Collection options1787   * @example1788   * mintCollection(aliceKeyring, {1789   *   name: 'New',1790   *   description: 'New collection',1791   *   tokenPrefix: 'NEW',1792   * })1793   * @returns object of the created collection1794   */1795  override async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueNFTCollection> {1796    return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection;1797  }17981799  /**1800   * Mint new token1801   * @param signer keyring of signer1802   * @param data token data1803   * @returns created token object1804   */1805  async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise<UniqueNFToken> {1806    const creationResult = await this.helper.executeExtrinsic(1807      signer,1808      'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1809        NFT: {1810          properties: data.properties,1811        },1812      }],1813      true,1814    );1815    const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1816    if(createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1817    if(createdTokens.tokens.length < 1) throw Error('No tokens minted');1818    return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1819  }18201821  /**1822   * Mint multiple NFT tokens1823   * @param signer keyring of signer1824   * @param collectionId ID of collection1825   * @param tokens array of tokens with owner and properties1826   * @example1827   * mintMultipleTokens(aliceKeyring, 10, [{1828   *     owner: {Substrate: "5DyN4Y92vZCjv38fg..."},1829   *     properties: [{key: "gender", value: "male"},{key: "age", value: "45"}],1830   *   },{1831   *     owner: {Ethereum: "0x9F0583DbB855d..."},1832   *     properties: [{key: "gender", value: "female"},{key: "age", value: "22"}],1833   * }]);1834   * @returns ```true``` if extrinsic success, otherwise ```false```1835   */1836  async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: { owner: ICrossAccountId, properties?: IProperty[] }[]): Promise<UniqueNFToken[]> {1837    const creationResult = await this.helper.executeExtrinsic(1838      signer,1839      'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}],1840      true,1841    );1842    const collection = this.getCollectionObject(collectionId);1843    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1844  }18451846  /**1847   * Mint multiple NFT tokens with one owner1848   * @param signer keyring of signer1849   * @param collectionId ID of collection1850   * @param owner tokens owner1851   * @param tokens array of tokens with owner and properties1852   * @example1853   * mintMultipleTokensWithOneOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...", [{1854   *   properties: [{1855   *   key: "gender",1856   *   value: "female",1857   *  },{1858   *   key: "age",1859   *   value: "33",1860   *  }],1861   * }]);1862   * @returns array of newly created tokens1863   */1864  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: { properties?: IProperty[] }[]): Promise<UniqueNFToken[]> {1865    const rawTokens = [];1866    for(const token of tokens) {1867      const raw = {NFT: {properties: token.properties}};1868      rawTokens.push(raw);1869    }1870    const creationResult = await this.helper.executeExtrinsic(1871      signer,1872      'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1873      true,1874    );1875    const collection = this.getCollectionObject(collectionId);1876    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1877  }18781879  /**1880   * Set, change, or remove approved address to transfer the ownership of the NFT.1881   *1882   * @param signer keyring of signer1883   * @param collectionId ID of collection1884   * @param tokenId ID of token1885   * @param toAddressObj address to approve1886   * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1887   * @returns ```true``` if extrinsic success, otherwise ```false```1888   */1889  override approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {1890    return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);1891  }1892}189318941895class RFTGroup extends NFTnRFT {1896  /**1897   * Get collection object1898   * @param collectionId ID of collection1899   * @example getCollectionObject(2);1900   * @returns instance of UniqueRFTCollection1901   */1902  override getCollectionObject(collectionId: number): UniqueRFTCollection {1903    return new UniqueRFTCollection(collectionId, this.helper);1904  }19051906  /**1907   * Get token object1908   * @param collectionId ID of collection1909   * @param tokenId ID of token1910   * @example getTokenObject(10, 5);1911   * @returns instance of UniqueNFTToken1912   */1913  override getTokenObject(collectionId: number, tokenId: number): UniqueRFToken {1914    return new UniqueRFToken(tokenId, this.getCollectionObject(collectionId));1915  }19161917  /**1918   * Get top 10 token owners with the largest number of pieces1919   * @param collectionId ID of collection1920   * @param tokenId ID of token1921   * @example getTokenTop10Owners(10, 5);1922   * @returns array of top 10 owners1923   */1924  async getTokenTop10Owners(collectionId: number, tokenId: number): Promise<ICrossAccountId[]> {1925    return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, tokenId])).toJSON().map(CrossAccountId.fromLowerCaseKeys).map((a: CrossAccountId) => a.toICrossAccountId());1926  }19271928  /**1929   * Get number of pieces owned by address1930   * @param collectionId ID of collection1931   * @param tokenId ID of token1932   * @param addressObj address token owner1933   * @example getTokenBalance(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."});1934   * @returns number of pieces ownerd by address1935   */1936  async getTokenBalance(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<bigint> {1937    return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, tokenId])).toBigInt();1938  }19391940  /**1941   * Transfer pieces of token to another address1942   * @param signer keyring of signer1943   * @param collectionId ID of collection1944   * @param tokenId ID of token1945   * @param addressObj address of a new owner1946   * @param amount number of pieces to be transfered1947   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2000n)1948   * @returns ```true``` if extrinsic success, otherwise ```false```1949   */1950  override async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount = 1n): Promise<boolean> {1951    return await super.transferToken(signer, collectionId, tokenId, addressObj, amount);1952  }19531954  /**1955   * Change ownership of some pieces of RFT on behalf of the owner.1956   * @param signer keyring of signer1957   * @param collectionId ID of collection1958   * @param tokenId ID of token1959   * @param fromAddressObj address on behalf of which the token will be sent1960   * @param toAddressObj new token owner1961   * @param amount number of pieces to be transfered1962   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n)1963   * @returns ```true``` if extrinsic success, otherwise ```false```1964   */1965  override async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {1966    return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1967  }19681969  /**1970   * Mint new collection1971   * @param signer keyring of signer1972   * @param collectionOptions Collection options1973   * @example1974   * mintCollection(aliceKeyring, {1975   *   name: 'New',1976   *   description: 'New collection',1977   *   tokenPrefix: 'NEW',1978   * })1979   * @returns object of the created collection1980   */1981  override async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueRFTCollection> {1982    return await super.mintCollection(signer, collectionOptions, 'RFT') as UniqueRFTCollection;1983  }19841985  /**1986   * Mint new token1987   * @param signer keyring of signer1988   * @param data token data1989   * @example mintToken(aliceKeyring, {collectionId: 10, owner: {Substrate: '5GHoZe9c73RYbVzq...'}, pieces: 10000n});1990   * @returns created token object1991   */1992  async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise<UniqueRFToken> {1993    const creationResult = await this.helper.executeExtrinsic(1994      signer,1995      'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1996        ReFungible: {1997          pieces: data.pieces,1998          properties: data.properties,1999        },2000      }],2001      true,2002    );2003    const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);2004    if(createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');2005    if(createdTokens.tokens.length < 1) throw Error('No tokens minted');2006    return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);2007  }20082009  mintMultipleTokens(_signer: TSigner, _collectionId: number, _tokens: { owner: ICrossAccountId, pieces: bigint, properties?: IProperty[] }[]): Promise<UniqueRFToken[]> {2010    throw Error('Not implemented');2011    // const creationResult = await this.helper.executeExtrinsic(2012    //   signer,2013    //   'api.tx.unique.createMultipleItemsEx', [collectionId, {RefungibleMultipleOwners: tokens}],2014    //   true, // `Unable to mint RFT tokens for ${label}`,2015    // );2016    // const collection = this.getCollectionObject(collectionId);2017    // return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));2018  }20192020  /**2021   * Mint multiple RFT tokens with one owner2022   * @param signer keyring of signer2023   * @param collectionId ID of collection2024   * @param owner tokens owner2025   * @param tokens array of tokens with properties and pieces2026   * @example mintMultipleTokensWithOneOwner(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, [{pieces: 100000n, properties: [{key: "gender", value: "male"}]}]);2027   * @returns array of newly created RFT tokens2028   */2029  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: { pieces: bigint, properties?: IProperty[] }[]): Promise<UniqueRFToken[]> {2030    const rawTokens = [];2031    for(const token of tokens) {2032      const raw = {ReFungible: {pieces: token.pieces, properties: token.properties}};2033      rawTokens.push(raw);2034    }2035    const creationResult = await this.helper.executeExtrinsic(2036      signer,2037      'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],2038      true,2039    );2040    const collection = this.getCollectionObject(collectionId);2041    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));2042  }20432044  /**2045   * Destroys a concrete instance of RFT.2046   * @param signer keyring of signer2047   * @param collectionId ID of collection2048   * @param tokenId ID of token2049   * @param amount number of pieces to be burnt2050   * @example burnToken(aliceKeyring, 10, 5);2051   * @returns ```true``` if the extrinsic is successful, otherwise ```false```2052   */2053  override async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount = 1n): Promise<boolean> {2054    return await super.burnToken(signer, collectionId, tokenId, amount);2055  }20562057  /**2058   * Destroys a concrete instance of RFT on behalf of the owner.2059   * @param signer keyring of signer2060   * @param collectionId ID of collection2061   * @param tokenId ID of token2062   * @param fromAddressObj address on behalf of which the token will be burnt2063   * @param amount number of pieces to be burnt2064   * @example burnTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2n)2065   * @returns ```true``` if extrinsic success, otherwise ```false```2066   */2067  override async burnTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {2068    return await super.burnTokenFrom(signer, collectionId, tokenId, fromAddressObj, amount);2069  }20702071  /**2072   * Set, change, or remove approved address to transfer the ownership of the RFT.2073   *2074   * @param signer keyring of signer2075   * @param collectionId ID of collection2076   * @param tokenId ID of token2077   * @param toAddressObj address to approve2078   * @param amount number of pieces to be approved2079   * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n);2080   * @returns true if the token success, otherwise false2081   */2082  override approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {2083    return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);2084  }20852086  /**2087   * Get total number of pieces2088   * @param collectionId ID of collection2089   * @param tokenId ID of token2090   * @example getTokenTotalPieces(10, 5);2091   * @returns number of pieces2092   */2093  async getTokenTotalPieces(collectionId: number, tokenId: number): Promise<bigint> {2094    return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, tokenId])).unwrap().toBigInt();2095  }20962097  /**2098   * Change number of token pieces. Signer must be the owner of all token pieces.2099   * @param signer keyring of signer2100   * @param collectionId ID of collection2101   * @param tokenId ID of token2102   * @param amount new number of pieces2103   * @example repartitionToken(aliceKeyring, 10, 5, 12345n);2104   * @returns true if the repartion was success, otherwise false2105   */2106  async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint): Promise<boolean> {2107    const currentAmount = await this.getTokenTotalPieces(collectionId, tokenId);2108    const repartitionResult = await this.helper.executeExtrinsic(2109      signer,2110      'api.tx.unique.repartition', [collectionId, tokenId, amount],2111      true,2112    );2113    if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated');2114    return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed');2115  }2116}211721182119class FTGroup extends CollectionGroup {2120  /**2121   * Get collection object2122   * @param collectionId ID of collection2123   * @example getCollectionObject(2);2124   * @returns instance of UniqueFTCollection2125   */2126  getCollectionObject(collectionId: number): UniqueFTCollection {2127    return new UniqueFTCollection(collectionId, this.helper);2128  }21292130  /**2131   * Mint new fungible collection2132   * @param signer keyring of signer2133   * @param collectionOptions Collection options2134   * @param decimalPoints number of token decimals2135   * @example2136   * mintCollection(aliceKeyring, {2137   *   name: 'New',2138   *   description: 'New collection',2139   *   tokenPrefix: 'NEW',2140   * }, 18)2141   * @returns newly created fungible collection2142   */2143  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}, decimalPoints = 0): Promise<UniqueFTCollection> {2144    collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object2145    if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions');2146    collectionOptions.mode = {fungible: decimalPoints};2147    for(const key of ['name', 'description', 'tokenPrefix']) {2148      if(typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);2149    }2150    const creationResult = await this.helper.executeExtrinsic(2151      signer,2152      'api.tx.unique.createCollectionEx', [collectionOptions],2153      true,2154    );2155    return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));2156  }21572158  /**2159   * Mint tokens2160   * @param signer keyring of signer2161   * @param collectionId ID of collection2162   * @param owner address owner of new tokens2163   * @param amount amount of tokens to be meanted2164   * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n);2165   * @returns ```true``` if extrinsic success, otherwise ```false```2166   */2167  async mintTokens(signer: TSigner, collectionId: number, amount: bigint, owner: ICrossAccountId | string): Promise<boolean> {2168    const creationResult = await this.helper.executeExtrinsic(2169      signer,2170      'api.tx.unique.createItem', [collectionId, (typeof owner === 'string') ? {Substrate: owner} : owner, {2171        Fungible: {2172          value: amount,2173        },2174      }],2175      true, // `Unable to mint fungible tokens for ${label}`,2176    );2177    return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');2178  }21792180  /**2181   * Mint multiple Fungible tokens with one owner2182   * @param signer keyring of signer2183   * @param collectionId ID of collection2184   * @param owner tokens owner2185   * @param tokens array of tokens with properties and pieces2186   * @returns ```true``` if extrinsic success, otherwise ```false```2187   */2188  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, tokens: { value: bigint }[], owner: ICrossAccountId): Promise<boolean> {2189    const rawTokens = [];2190    for(const token of tokens) {2191      const raw = {Fungible: {Value: token.value}};2192      rawTokens.push(raw);2193    }2194    const creationResult = await this.helper.executeExtrinsic(2195      signer,2196      'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],2197      true,2198    );2199    return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');2200  }22012202  /**2203   * Get the top 10 owners with the largest balance for the Fungible collection2204   * @param collectionId ID of collection2205   * @example getTop10Owners(10);2206   * @returns array of ```ICrossAccountId```2207   */2208  async getTop10Owners(collectionId: number): Promise<ICrossAccountId[]> {2209    return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, 0])).toJSON().map(CrossAccountId.fromLowerCaseKeys).map((a: CrossAccountId) => a.toICrossAccountId());2210  }22112212  /**2213   * Get account balance2214   * @param collectionId ID of collection2215   * @param addressObj address of owner2216   * @example getBalance(10, {Substrate: "5GHoZe9c73RYbVzq..."})2217   * @returns amount of fungible tokens owned by address2218   */2219  async getBalance(collectionId: number, addressObj: ICrossAccountId): Promise<bigint> {2220    return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, 0])).toBigInt();2221  }22222223  /**2224   * Transfer tokens to address2225   * @param signer keyring of signer2226   * @param collectionId ID of collection2227   * @param toAddressObj address recipient2228   * @param amount amount of tokens to be sent2229   * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2230   * @returns ```true``` if extrinsic success, otherwise ```false```2231   */2232  async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount = 1n) {2233    return await super.transferToken(signer, collectionId, 0, toAddressObj, amount);2234  }22352236  /**2237   * Transfer some tokens on behalf of the owner.2238   * @param signer keyring of signer2239   * @param collectionId ID of collection2240   * @param fromAddressObj address on behalf of which tokens will be sent2241   * @param toAddressObj address where token to be sent2242   * @param amount number of tokens to be sent2243   * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n);2244   * @returns ```true``` if extrinsic success, otherwise ```false```2245   */2246  async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {2247    return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount);2248  }22492250  /**2251   * Destroy some amount of tokens2252   * @param signer keyring of signer2253   * @param collectionId ID of collection2254   * @param amount amount of tokens to be destroyed2255   * @example burnTokens(aliceKeyring, 10, 1000n);2256   * @returns ```true``` if extrinsic success, otherwise ```false```2257   */2258  async burnTokens(signer: IKeyringPair, collectionId: number, amount = 1n): Promise<boolean> {2259    return await super.burnToken(signer, collectionId, 0, amount);2260  }22612262  /**2263   * Burn some tokens on behalf of the owner.2264   * @param signer keyring of signer2265   * @param collectionId ID of collection2266   * @param fromAddressObj address on behalf of which tokens will be burnt2267   * @param amount amount of tokens to be burnt2268   * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2269   * @returns ```true``` if extrinsic success, otherwise ```false```2270   */2271  async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount = 1n): Promise<boolean> {2272    return await super.burnTokenFrom(signer, collectionId, 0, fromAddressObj, amount);2273  }22742275  /**2276   * Get total collection supply2277   * @param collectionId2278   * @returns2279   */2280  async getTotalPieces(collectionId: number): Promise<bigint> {2281    return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, 0])).unwrap().toBigInt();2282  }22832284  /**2285   * Set, change, or remove approved address to transfer tokens.2286   *2287   * @param signer keyring of signer2288   * @param collectionId ID of collection2289   * @param toAddressObj address to be approved2290   * @param amount amount of tokens to be approved2291   * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n)2292   * @returns ```true``` if extrinsic success, otherwise ```false```2293   */2294  approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount = 1n) {2295    return super.approveToken(signer, collectionId, 0, toAddressObj, amount);2296  }22972298  /**2299   * Get amount of fungible tokens approved to transfer2300   * @param collectionId ID of collection2301   * @param fromAddressObj owner of tokens2302   * @param toAddressObj the address approved for the transfer of tokens on behalf of the owner2303   * @returns number of tokens approved for the transfer2304   */2305  getApprovedTokens(collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {2306    return super.getTokenApprovedPieces(collectionId, 0, toAddressObj, fromAddressObj);2307  }2308}230923102311class ChainGroup extends HelperGroup<ChainHelperBase> {2312  /**2313   * Get system properties of a chain2314   * @example getChainProperties();2315   * @returns ss58Format, token decimals, and token symbol2316   */2317  getChainProperties(): IChainProperties {2318    const properties = (this.helper.getApi() as any).registry.getChainProperties().toJSON();2319    return {2320      ss58Format: properties.ss58Format.toJSON(),2321      tokenDecimals: properties.tokenDecimals.toJSON(),2322      tokenSymbol: properties.tokenSymbol.toJSON(),2323    };2324  }23252326  /**2327   * Get chain header2328   * @example getLatestBlockNumber();2329   * @returns the number of the last block2330   */2331  async getLatestBlockNumber(): Promise<number> {2332    return (await this.helper.callRpc('api.rpc.chain.getHeader')).number.toNumber();2333  }23342335  /**2336   * Get block hash by block number2337   * @param blockNumber number of block2338   * @example getBlockHashByNumber(12345);2339   * @returns hash of a block2340   */2341  async getBlockHashByNumber(blockNumber: number): Promise<string | null> {2342    const blockHash = (await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber])).toJSON();2343    if(blockHash === '0x0000000000000000000000000000000000000000000000000000000000000000') return null;2344    return blockHash;2345  }23462347  // TODO add docs2348  async getBlock(blockHashOrNumber: string | number): Promise<IBlock | null> {2349    const blockHash = typeof blockHashOrNumber === 'string' ? blockHashOrNumber : await this.getBlockHashByNumber(blockHashOrNumber);2350    if(!blockHash) return null;2351    return (await this.helper.callRpc('api.rpc.chain.getBlock', [blockHash])).toHuman().block;2352  }23532354  /**2355   * Get latest relay block2356   * @returns {number} relay block2357   */2358  async getRelayBlockNumber(): Promise<bigint> {2359    const blockNumber = (await this.helper.callRpc('api.query.parachainSystem.validationData')).toJSON().relayParentNumber;2360    return BigInt(blockNumber);2361  }23622363  /**2364   * Get account nonce2365   * @param address substrate address2366   * @example getNonce("5GrwvaEF5zXb26Fz...");2367   * @returns number, account's nonce2368   */2369  async getNonce(address: TSubstrateAccount): Promise<number> {2370    return (await this.helper.callRpc('api.query.system.account', [address])).nonce.toNumber();2371  }2372}23732374export class SubstrateBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2375  /**2376 * Get substrate address balance2377 * @param address substrate address2378 * @example getSubstrate("5GrwvaEF5zXb26Fz...")2379 * @returns amount of tokens on address2380 */2381  async getSubstrate(address: TSubstrateAccount): Promise<bigint> {2382    return (await this.helper.callRpc('api.query.system.account', [address])).data.free.toBigInt();2383  }23842385  /**2386   * Transfer tokens to substrate address2387   * @param signer keyring of signer2388   * @param address substrate address of a recipient2389   * @param amount amount of tokens to be transfered2390   * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2391   * @returns ```true``` if extrinsic success, otherwise ```false```2392   */2393  async transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2394    const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transferKeepAlive', [address, amount], true/*, `Unable to transfer balance from ${this.helper.getSignerAddress(signer)} to ${address}`*/);23952396    let transfer = {from: null, to: null, amount: 0n} as any;2397    result.result.events.forEach(({event: {data, method, section}}: any) => {2398      if((section === 'balances') && (method === 'Transfer')) {2399        transfer = {2400          from: this.helper.address.normalizeSubstrate(data[0]),2401          to: this.helper.address.normalizeSubstrate(data[1]),2402          amount: BigInt(data[2]),2403        };2404      }2405    });2406    const isSuccess = this.helper.address.normalizeSubstrate(typeof signer === 'string' ? signer : signer.address) === transfer.from2407      && this.helper.address.normalizeSubstrate(address) === transfer.to2408      && BigInt(amount) === transfer.amount;2409    return isSuccess;2410  }24112412  /**2413   * Get full substrate balance including free, frozen, and reserved2414   * @param address substrate address2415   * @returns2416   */2417  async getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2418    const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data;2419    return {free: accountInfo.free.toBigInt(), frozen: accountInfo.frozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};2420  }24212422  /**2423   * Get total issuance2424   * @returns2425   */2426  async getTotalIssuance(): Promise<bigint> {2427    const total = (await this.helper.callRpc('api.query.balances.totalIssuance', []));2428    return total.toBigInt();2429  }24302431  async getLocked(address: TSubstrateAccount): Promise<{ id: string, amount: bigint, reason: string }[]> {2432    const locks = (await this.helper.callRpc('api.query.balances.locks', [address])).toHuman();2433    return locks.map((lock: any) => ({id: lock.id, amount: BigInt(lock.amount.replace(/,/g, '')), reasons: lock.reasons}));2434  }2435  async getFrozen(address: TSubstrateAccount): Promise<{ id: string, amount: bigint }[]> {2436    const locks = (await this.helper.api!.query.balances.freezes(address)) as unknown as Array<any>;2437    return locks.map(lock => ({id: lock.id.toUtf8(), amount: lock.amount.toBigInt()}));2438  }2439}24402441export class EthereumBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2442  /**2443   * Get ethereum address balance2444   * @param address ethereum address2445   * @example getEthereum("0x9F0583DbB855d...")2446   * @returns amount of tokens on address2447   */2448  async getEthereum(address: TEthereumAccount): Promise<bigint> {2449    return (await this.helper.callRpc('api.rpc.eth.getBalance', [address])).toBigInt();2450  }24512452  /**2453   * Transfer tokens to address2454   * @param signer keyring of signer2455   * @param address Ethereum address of a recipient2456   * @param amount amount of tokens to be transfered2457   * @example transferToEthereum(alithKeyring, "0x9F0583DbB855d...", 100_000_000_000n);2458   * @returns ```true``` if extrinsic success, otherwise ```false```2459   */2460  async transferToEthereum(signer: TSigner, address: TEthereumAccount, amount: bigint | string): Promise<boolean> {2461    const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transferKeepAlive', [address, amount], true);24622463    let transfer = {from: null, to: null, amount: 0n} as any;2464    result.result.events.forEach(({event: {data, method, section}}: any) => {2465      if((section === 'balances') && (method === 'Transfer')) {2466        transfer = {2467          from: data[0].toString(),2468          to: data[1].toString(),2469          amount: BigInt(data[2]),2470        };2471      }2472    });2473    const isSuccess = (typeof signer === 'string' ? signer : signer.address) === transfer.from2474      && address === transfer.to2475      && BigInt(amount) === transfer.amount;2476    return isSuccess;2477  }2478}24792480class BalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2481  subBalanceGroup: SubstrateBalanceGroup<T>;2482  ethBalanceGroup: EthereumBalanceGroup<T>;24832484  constructor(helper: T) {2485    super(helper);2486    this.subBalanceGroup = new SubstrateBalanceGroup(helper);2487    this.ethBalanceGroup = new EthereumBalanceGroup(helper);2488  }24892490  getCollectionCreationPrice(): bigint {2491    return 2n * this.getOneTokenNominal();2492  }2493  /**2494   * Representation of the native token in the smallest unit - one OPAL (OPL), QUARTZ (QTZ), or UNIQUE (UNQ).2495   * @example getOneTokenNominal()2496   * @returns ```BigInt``` representation of the native token in the smallest unit, e.g. ```1_000_000_000_000_000_000n``` for QTZ.2497   */2498  getOneTokenNominal(): bigint {2499    const chainProperties = this.helper.chain.getChainProperties();2500    return 10n ** BigInt((chainProperties.tokenDecimals || [18])[0]);2501  }25022503  /**2504   * Get substrate address balance2505   * @param address substrate address2506   * @example getSubstrate("5GrwvaEF5zXb26Fz...")2507   * @returns amount of tokens on address2508   */2509  getSubstrate(address: TSubstrateAccount): Promise<bigint> {2510    return this.subBalanceGroup.getSubstrate(address);2511  }25122513  /**2514   * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2515   * @param address substrate address2516   * @returns2517   */2518  getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2519    return this.subBalanceGroup.getSubstrateFull(address);2520  }25212522  /**2523   * Get total issuance2524   * @returns2525   */2526  getTotalIssuance(): Promise<bigint> {2527    return this.subBalanceGroup.getTotalIssuance();2528  }25292530  /**2531   * Get locked balances2532   * @param address substrate address2533   * @returns locked balances with reason via api.query.balances.locks2534   * @deprecated all the methods should switch to getFrozen2535   */2536  getLocked(address: TSubstrateAccount) {2537    return this.subBalanceGroup.getLocked(address);2538  }25392540  /**2541   * Get frozen balances2542   * @param address substrate address2543   * @returns frozen balances with id via api.query.balances.freezes2544   */2545  getFrozen(address: TSubstrateAccount) {2546    return this.subBalanceGroup.getFrozen(address);2547  }25482549  /**2550   * Get ethereum address balance2551   * @param address ethereum address2552   * @example getEthereum("0x9F0583DbB855d...")2553   * @returns amount of tokens on address2554   */2555  getEthereum(address: TEthereumAccount): Promise<bigint> {2556    return this.ethBalanceGroup.getEthereum(address);2557  }25582559  async setBalanceSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint) {2560    await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceSetBalance', [address, amount], true);2561  }25622563  /**2564   * Transfer tokens to substrate address2565   * @param signer keyring of signer2566   * @param address substrate address of a recipient2567   * @param amount amount of tokens to be transfered2568   * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2569   * @returns ```true``` if extrinsic success, otherwise ```false```2570   */2571  transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2572    return this.subBalanceGroup.transferToSubstrate(signer, address, amount);2573  }25742575  async forceTransferToSubstrate(signer: TSigner, from: TSubstrateAccount, to: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2576    const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceTransfer', [from, to, amount], true);25772578    let transfer = {from: null, to: null, amount: 0n} as any;2579    result.result.events.forEach(({event: {data, method, section}}: any) => {2580      if((section === 'balances') && (method === 'Transfer')) {2581        transfer = {2582          from: this.helper.address.normalizeSubstrate(data[0]),2583          to: this.helper.address.normalizeSubstrate(data[1]),2584          amount: BigInt(data[2]),2585        };2586      }2587    });2588    let isSuccess = this.helper.address.normalizeSubstrate(from) === transfer.from;2589    isSuccess = isSuccess && this.helper.address.normalizeSubstrate(to) === transfer.to;2590    isSuccess = isSuccess && BigInt(amount) === transfer.amount;2591    return isSuccess;2592  }25932594  /**2595   * Transfer tokens with the unlock period2596   * @param signer signers Keyring2597   * @param address Substrate address of recipient2598   * @param schedule Schedule params2599   * @example vestedTransfer(signer, recepient.address, 20000, 100, 10, 50 * nominal); // total amount of vested tokens will be 100 * 50 = 50002600   */2601  async vestedTransfer(signer: TSigner, address: TSubstrateAccount, schedule: { start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint }): Promise<void> {2602    const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.vestedTransfer', [address, schedule]);2603    const event = result.result.events2604      .find((e: any) => e.event.section === 'vesting' &&2605        e.event.method === 'VestingScheduleAdded' &&2606        e.event.data[0].toHuman() === signer.address);2607    if(!event) throw Error('Cannot find transfer in events');2608  }26092610  /**2611   * Get schedule for recepient of vested transfer2612   * @param address Substrate address of recipient2613   * @returns2614   */2615  async getVestingSchedules(address: TSubstrateAccount): Promise<{ start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint }[]> {2616    const schedule = (await this.helper.callRpc('api.query.vesting.vestingSchedules', [address])).toJSON();2617    return schedule.map((schedule: any) => ({2618      start: BigInt(schedule.start),2619      period: BigInt(schedule.period),2620      periodCount: BigInt(schedule.periodCount),2621      perPeriod: BigInt(schedule.perPeriod),2622    }));2623  }26242625  /**2626   * Claim vested tokens2627   * @param signer signers Keyring2628   */2629  async claim(signer: TSigner) {2630    const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.claim', []);2631    const event = result.result.events2632      .find((e: any) => e.event.section === 'vesting' &&2633        e.event.method === 'Claimed' &&2634        e.event.data[0].toHuman() === signer.address);2635    if(!event) throw Error('Cannot find claim in events');2636  }2637}26382639class AddressGroup extends HelperGroup<ChainHelperBase> {2640  /**2641   * Normalizes the address to the specified ss58 format, by default ```42```.2642   * @param address substrate address2643   * @param ss58Format format for address conversion, by default ```42```2644   * @example normalizeSubstrate("unjKJQJrRd238pkUZZvzDQrfKuM39zBSnQ5zjAGAGcdRhaJTx") // returns 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY2645   * @returns substrate address converted to normalized (i.e., starting with 5) or specified explicitly representation2646   */2647  normalizeSubstrate(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {2648    return CrossAccountId.normalizeSubstrateAddress({Substrate: address}, ss58Format);2649  }26502651  /**2652   * Get address in the connected chain format2653   * @param address substrate address2654   * @example normalizeSubstrateToChainFormat("5GrwvaEF5zXb26Fz...") // returns unjKJQJrRd238pkUZZ... for Unique Network2655   * @returns address in chain format2656   */2657  normalizeSubstrateToChainFormat(address: TSubstrateAccount): TSubstrateAccount {2658    return this.normalizeSubstrate(address, this.helper.chain.getChainProperties().ss58Format);2659  }26602661  /**2662   * Get substrate mirror of an ethereum address2663   * @param ethAddress ethereum address2664   * @param toChainFormat false for normalized account2665   * @example ethToSubstrate('0x9F0583DbB855d...')2666   * @returns substrate mirror of a provided ethereum address2667   */2668  ethToSubstrate(ethAddress: TEthereumAccount, toChainFormat = false): TSubstrateAccount {2669    return CrossAccountId.translateEthToSub(ethAddress, toChainFormat ? this.helper.chain.getChainProperties().ss58Format : undefined);2670  }26712672  /**2673   * Get ethereum mirror of a substrate address2674   * @param subAddress substrate account2675   * @example substrateToEth("5DnSF6RRjwteE3BrC...")2676   * @returns ethereum mirror of a provided substrate address2677   */2678  substrateToEth(subAddress: TSubstrateAccount): TEthereumAccount {2679    return CrossAccountId.translateSubToEth(subAddress);2680  }26812682  /**2683   * Encode key to substrate address2684   * @param key key for encoding address2685   * @param ss58Format prefix for encoding to the address of the corresponding network2686   * @returns encoded substrate address2687   */2688  encodeSubstrateAddress(key: Uint8Array | string | bigint, ss58Format = 42): string {2689    const u8a: Uint8Array = typeof key === 'string'2690      ? hexToU8a(key)2691      : typeof key === 'bigint'2692        ? hexToU8a(key.toString(16))2693        : key;26942695    if(ss58Format < 0 || ss58Format > 16383 || [46, 47].includes(ss58Format)) {2696      throw new Error(`ss58Format is not valid, received ${typeof ss58Format} "${ss58Format}"`);2697    }26982699    const allowedDecodedLengths = [1, 2, 4, 8, 32, 33];2700    if(!allowedDecodedLengths.includes(u8a.length)) {2701      throw new Error(`key length is not valid, received ${u8a.length}, valid values are ${allowedDecodedLengths.join(', ')}`);2702    }27032704    const u8aPrefix = ss58Format < 642705      ? new Uint8Array([ss58Format])2706      : new Uint8Array([2707        ((ss58Format & 0xfc) >> 2) | 0x40,2708        (ss58Format >> 8) | ((ss58Format & 0x03) << 6),2709      ]);27102711    const input = u8aConcat(u8aPrefix, u8a);27122713    return base58Encode(u8aConcat(2714      input,2715      blake2AsU8a(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1),2716    ));2717  }27182719  /**2720   * Restore substrate address from bigint representation2721   * @param number decimal representation of substrate address2722   * @returns substrate address2723   */2724  restoreCrossAccountFromBigInt(number: bigint): TSubstrateAccount {2725    if(this.helper.api === null) {2726      throw 'Not connected';2727    }2728    const res = this.helper.api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();2729    if(res === undefined || res === null) {2730      throw 'Restore address error';2731    }2732    return res.toString();2733  }27342735  /**2736   * Convert etherium cross account id to substrate cross account id2737   * @param ethCrossAccount etherium cross account2738   * @returns substrate cross account id2739   */2740  convertCrossAccountFromEthCrossAccount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId {2741    if(ethCrossAccount.sub === '0') {2742      return {Ethereum: ethCrossAccount.eth.toLocaleLowerCase()};2743    }27442745    const ss58 = this.restoreCrossAccountFromBigInt(BigInt(ethCrossAccount.sub));2746    return {Substrate: ss58};2747  }27482749  paraSiblingSovereignAccount(paraid: number) {2750    // We are getting a *sibling* parachain sovereign account,2751    // so we need a sibling prefix: encoded(b"sibl") == 0x7369626c2752    const siblingPrefix = '0x7369626c';27532754    const encodedParaId = this.helper.getApi().createType('u32', paraid).toHex(true).substring(2);2755    const suffix = '000000000000000000000000000000000000000000000000';27562757    return siblingPrefix + encodedParaId + suffix;2758  }2759}276027612762class StakingGroup extends HelperGroup<UniqueHelper> {2763  /**2764   * Stake tokens for App Promotion2765   * @param signer keyring of signer2766   * @param amountToStake amount of tokens to stake2767   * @param label extra label for log2768   * @returns2769   */2770  async stake(signer: TSigner, amountToStake: bigint, label?: string): Promise<boolean> {2771    if(typeof label === 'undefined') label = `${signer.address} amount: ${amountToStake}`;2772    await this.helper.executeExtrinsic(2773      signer, 'api.tx.appPromotion.stake',2774      [amountToStake], true,2775    );2776    // TODO extract info from stakeResult2777    return true;2778  }27792780  /**2781   * Unstake all staked tokens2782   * @param signer keyring of signer2783   * @param amountToUnstake amount of tokens to unstake2784   * @param label extra label for log2785   * @returns block hash where unstake happened2786   */2787  async unstakeAll(signer: TSigner, label?: string): Promise<string> {2788    if(typeof label === 'undefined') label = `${signer.address}`;2789    const unstakeResult = await this.helper.executeExtrinsic(2790      signer, 'api.tx.appPromotion.unstakeAll',2791      [], true,2792    );2793    return unstakeResult.blockHash;2794  }27952796  /**2797   * Unstake the part of a staked tokens2798   * @param signer keyring of signer2799   * @param amount amount of tokens to unstake2800   * @param label extra label for log2801   * @returns block hash where unstake happened2802   */2803  async unstakePartial(signer: TSigner, amount: bigint, label?: string): Promise<string> {2804    if(typeof label === 'undefined') label = `${signer.address}`;2805    const unstakeResult = await this.helper.executeExtrinsic(2806      signer, 'api.tx.appPromotion.unstakePartial',2807      [amount], true,2808    );2809    return unstakeResult.blockHash;2810  }28112812  /**2813   * Get total number of active stakes2814   * @param address substrate address2815   * @returns {number}2816   */2817  async getStakesNumber(address: ICrossAccountId): Promise<number> {2818    if('Ethereum' in address) throw Error('only substrate address');2819    return (await this.helper.callRpc('api.query.appPromotion.stakesPerAccount', [address.Substrate])).toNumber();2820  }28212822  /**2823   * Get total staked amount for address2824   * @param address substrate or ethereum address2825   * @returns total staked amount2826   */2827  async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {2828    if(address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();2829    return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();2830  }28312832  /**2833   * Get total staked per block2834   * @param address substrate or ethereum address2835   * @returns array of stakes. `block` – the number of the block in which the stake was made. `amount` - the number of tokens staked in the block2836   */2837  async getTotalStakedPerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2838    const rawTotalStakerdPerBlock = await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address]);2839    return rawTotalStakerdPerBlock.map(([block, amount]: any[]) => ({2840      block: block.toBigInt(),2841      amount: amount.toBigInt(),2842    }));2843  }28442845  /**2846   * Get total pending unstake amount for address2847   * @param address substrate or ethereum address2848   * @returns total pending unstake amount2849   */2850  async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {2851    return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();2852  }28532854  /**2855   * Get pending unstake amount per block for address2856   * @param address substrate or ethereum address2857   * @returns array of pending stakes. `block` – the number of the block in which the unstake was made. `amount` - the number of tokens unstaked in the block2858   */2859  async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2860    const rawUnstakedPerBlock = await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address]);2861    const result = rawUnstakedPerBlock.map(([block, amount]: any[]) => ({2862      block: block.toBigInt(),2863      amount: amount.toBigInt(),2864    }));2865    return result;2866  }2867}286828692870class PreimageGroup extends HelperGroup<UniqueHelper> {2871  async getPreimageInfo(h256: string) {2872    return (await this.helper.callRpc('api.query.preimage.statusFor', [h256])).toJSON();2873  }28742875  /**2876   * Create a preimage from an API call.2877   * @param signer keyring of the signer.2878   * @param call an extrinsic call2879   * @example await notePreimageFromCall(preimageMaker,2880   *   helper.constructApiCall('api.tx.identity.forceInsertIdentities', [identitiesToAdd])2881   * );2882   * @returns promise of extrinsic execution.2883   */2884  notePreimageFromCall(signer: TSigner, call: any, returnPreimageHash = false) {2885    return this.notePreimage(signer, call.method.toHex(), returnPreimageHash);2886  }28872888  /**2889   * Create a preimage with a hex or a byte array.2890   * @param signer keyring of the signer.2891   * @param bytes preimage encoded in hex or a byte array, e.g. an extrinsic call.2892   * @example await notePreimage(preimageMaker,2893   *   helper.constructApiCall('api.tx.identity.forceInsertIdentities', [identitiesToAdd]).method.toHex()2894   * );2895   * @returns promise of extrinsic execution.2896   */2897  async notePreimage(signer: TSigner, bytes: string | Uint8Array, returnPreimageHash = false) {2898    const promise = this.helper.executeExtrinsic(signer, 'api.tx.preimage.notePreimage', [bytes]);2899    if(returnPreimageHash) {2900      const result = await promise;2901      const events = result.result.events.filter((x: any) => x.event.method === 'Noted' && x.event.section === 'preimage');2902      const preimageHash = events[0].event.data[0].toHuman();2903      return preimageHash;2904    }2905    return promise;2906  }29072908  /**2909   * Delete an existing preimage and return the deposit.2910   * @param signer keyring of the signer - either the owner or the preimage manager (sudo).2911   * @param h256 hash of the preimage.2912   * @returns promise of extrinsic execution.2913   */2914  unnotePreimage(signer: TSigner, h256: string) {2915    return this.helper.executeExtrinsic(signer, 'api.tx.preimage.unnotePreimage', [h256]);2916  }29172918  /**2919   * Request a preimage be uploaded to the chain without paying any fees or deposits.2920   * @param signer keyring of the signer - either the owner or the preimage manager (sudo).2921   * @param h256 hash of the preimage.2922   * @returns promise of extrinsic execution.2923   */2924  requestPreimage(signer: TSigner, h256: string) {2925    return this.helper.executeExtrinsic(signer, 'api.tx.preimage.requestPreimage', [h256]);2926  }29272928  /**2929   * Clear a previously made request for a preimage.2930   * @param signer keyring of the signer - either the owner or the preimage manager (sudo).2931   * @param h256 hash of the preimage.2932   * @returns promise of extrinsic execution.2933   */2934  unrequestPreimage(signer: TSigner, h256: string) {2935    return this.helper.executeExtrinsic(signer, 'api.tx.preimage.unrequestPreimage', [h256]);2936  }2937}29382939class UtilityGroup<T extends ChainHelperBase> extends HelperGroup<T> {2940  async batch(signer: TSigner, txs: any[]) {2941    return await this.helper.executeExtrinsic(signer, 'api.tx.utility.batch', [txs]);2942  }29432944  async batchAll(signer: TSigner, txs: any[]) {2945    return await this.helper.executeExtrinsic(signer, 'api.tx.utility.batchAll', [txs]);2946  }29472948  batchAllCall(txs: any[]) {2949    return this.helper.constructApiCall('api.tx.utility.batchAll', [txs]);2950  }2951}29522953export type ChainHelperBaseConstructor = new (...args: any[]) => ChainHelperBase;2954export type UniqueHelperConstructor = new (...args: any[]) => UniqueHelper;29552956export class UniqueHelper extends ChainHelperBase {2957  balance: BalanceGroup<UniqueHelper>;2958  collection: CollectionGroup;2959  nft: NFTGroup;2960  rft: RFTGroup;2961  ft: FTGroup;2962  staking: StakingGroup;2963  preimage: PreimageGroup;2964  utility: UtilityGroup<UniqueHelper>;29652966  constructor(logger?: ILogger, options: { [key: string]: any } = {}) {2967    super(logger, options.helperBase ?? UniqueHelper);29682969    this.balance = new BalanceGroup(this);2970    this.collection = new CollectionGroup(this);2971    this.nft = new NFTGroup(this);2972    this.rft = new RFTGroup(this);2973    this.ft = new FTGroup(this);2974    this.staking = new StakingGroup(this);2975    this.preimage = new PreimageGroup(this);2976    this.utility = new UtilityGroup(this);2977  }2978}29792980export class UniqueBaseCollection {2981  helper: UniqueHelper;2982  collectionId: number;29832984  constructor(collectionId: number, uniqueHelper: UniqueHelper) {2985    this.collectionId = collectionId;2986    this.helper = uniqueHelper;2987  }29882989  async getData() {2990    return await this.helper.collection.getData(this.collectionId);2991  }29922993  async getLastTokenId() {2994    return await this.helper.collection.getLastTokenId(this.collectionId);2995  }29962997  async doesTokenExist(tokenId: number) {2998    return await this.helper.collection.doesTokenExist(this.collectionId, tokenId);2999  }30003001  async getAdmins() {3002    return await this.helper.collection.getAdmins(this.collectionId);3003  }30043005  async getAllowList() {3006    return await this.helper.collection.getAllowList(this.collectionId);3007  }30083009  async getEffectiveLimits() {3010    return await this.helper.collection.getEffectiveLimits(this.collectionId);3011  }30123013  async getProperties(propertyKeys?: string[] | null) {3014    return await this.helper.collection.getProperties(this.collectionId, propertyKeys);3015  }30163017  async getPropertiesConsumedSpace() {3018    return await this.helper.collection.getPropertiesConsumedSpace(this.collectionId);3019  }30203021  async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) {3022    return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj);3023  }30243025  async getOptions() {3026    return await this.helper.collection.getCollectionOptions(this.collectionId);3027  }30283029  async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) {3030    return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress);3031  }30323033  async confirmSponsorship(signer: TSigner) {3034    return await this.helper.collection.confirmSponsorship(signer, this.collectionId);3035  }30363037  async removeSponsor(signer: TSigner) {3038    return await this.helper.collection.removeSponsor(signer, this.collectionId);3039  }30403041  async setLimits(signer: TSigner, limits: ICollectionLimits) {3042    return await this.helper.collection.setLimits(signer, this.collectionId, limits);3043  }30443045  async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount) {3046    return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress);3047  }30483049  async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3050    return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj);3051  }30523053  async addToAllowList(signer: TSigner, addressObj: ICrossAccountId) {3054    return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj);3055  }30563057  async removeFromAllowList(signer: TSigner, addressObj: ICrossAccountId) {3058    return await this.helper.collection.removeFromAllowList(signer, this.collectionId, addressObj);3059  }30603061  async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3062    return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj);3063  }30643065  async setProperties(signer: TSigner, properties: IProperty[]) {3066    return await this.helper.collection.setProperties(signer, this.collectionId, properties);3067  }30683069  async deleteProperties(signer: TSigner, propertyKeys: string[]) {3070    return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys);3071  }30723073  async setPermissions(signer: TSigner, permissions: ICollectionPermissions) {3074    return await this.helper.collection.setPermissions(signer, this.collectionId, permissions);3075  }30763077  async enableNesting(signer: TSigner, permissions: INestingPermissions) {3078    return await this.helper.collection.enableNesting(signer, this.collectionId, permissions);3079  }30803081  async disableNesting(signer: TSigner) {3082    return await this.helper.collection.disableNesting(signer, this.collectionId);3083  }30843085  async burn(signer: TSigner) {3086    return await this.helper.collection.burn(signer, this.collectionId);3087  }3088}30893090export class UniqueNFTCollection extends UniqueBaseCollection {3091  getTokenObject(tokenId: number) {3092    return new UniqueNFToken(tokenId, this);3093  }30943095  async getTokensByAddress(addressObj: ICrossAccountId) {3096    return await this.helper.nft.getTokensByAddress(this.collectionId, addressObj);3097  }30983099  async getToken(tokenId: number, blockHashAt?: string) {3100    return await this.helper.nft.getToken(this.collectionId, tokenId, [], blockHashAt);3101  }31023103  async getTokenOwner(tokenId: number, blockHashAt?: string) {3104    return await this.helper.nft.getTokenOwner(this.collectionId, tokenId, blockHashAt);3105  }31063107  async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {3108    return await this.helper.nft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);3109  }31103111  async getTokenChildren(tokenId: number, blockHashAt?: string) {3112    return await this.helper.nft.getTokenChildren(this.collectionId, tokenId, blockHashAt);3113  }31143115  async getPropertyPermissions(propertyKeys: string[] | null = null) {3116    return await this.helper.nft.getPropertyPermissions(this.collectionId, propertyKeys);3117  }31183119  async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3120    return await this.helper.nft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3121  }31223123  async getTokenPropertiesConsumedSpace(tokenId: number): Promise<number> {3124    const api = this.helper.getApi();3125    const props = (await api.query.nonfungible.tokenProperties(this.collectionId, tokenId)).toJSON() as any;31263127    return props?.consumedSpace ?? 0;3128  }31293130  async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId) {3131    return await this.helper.nft.transferToken(signer, this.collectionId, tokenId, addressObj);3132  }31333134  async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3135    return await this.helper.nft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj);3136  }31373138  async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId) {3139    return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj);3140  }31413142  async isTokenApproved(tokenId: number, toAddressObj: ICrossAccountId) {3143    return await this.helper.nft.isTokenApproved(this.collectionId, tokenId, toAddressObj);3144  }31453146  async mintToken(signer: TSigner, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3147    return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties});3148  }31493150  async mintMultipleTokens(signer: TSigner, tokens: { owner: ICrossAccountId, properties?: IProperty[] }[]) {3151    return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens);3152  }31533154  async burnToken(signer: TSigner, tokenId: number) {3155    return await this.helper.nft.burnToken(signer, this.collectionId, tokenId);3156  }31573158  async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId) {3159    return await this.helper.nft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj);3160  }31613162  async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3163    return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties);3164  }31653166  async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3167    return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3168  }31693170  async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3171    return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3172  }31733174  async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {3175    return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);3176  }31773178  async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3179    return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);3180  }3181}31823183export class UniqueRFTCollection extends UniqueBaseCollection {3184  getTokenObject(tokenId: number) {3185    return new UniqueRFToken(tokenId, this);3186  }31873188  async getToken(tokenId: number, blockHashAt?: string) {3189    return await this.helper.rft.getToken(this.collectionId, tokenId, [], blockHashAt);3190  }31913192  async getTokenOwner(tokenId: number, blockHashAt?: string) {3193    return await this.helper.rft.getTokenOwner(this.collectionId, tokenId, blockHashAt);3194  }31953196  async getTokensByAddress(addressObj: ICrossAccountId) {3197    return await this.helper.rft.getTokensByAddress(this.collectionId, addressObj);3198  }31993200  async getTop10TokenOwners(tokenId: number) {3201    return await this.helper.rft.getTokenTop10Owners(this.collectionId, tokenId);3202  }32033204  async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {3205    return await this.helper.rft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);3206  }32073208  async getTokenBalance(tokenId: number, addressObj: ICrossAccountId) {3209    return await this.helper.rft.getTokenBalance(this.collectionId, tokenId, addressObj);3210  }32113212  async getTokenTotalPieces(tokenId: number) {3213    return await this.helper.rft.getTokenTotalPieces(this.collectionId, tokenId);3214  }32153216  async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3217    return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj);3218  }32193220  async getPropertyPermissions(propertyKeys: string[] | null = null) {3221    return await this.helper.rft.getPropertyPermissions(this.collectionId, propertyKeys);3222  }32233224  async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3225    return await this.helper.rft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3226  }32273228  async getTokenPropertiesConsumedSpace(tokenId: number): Promise<number> {3229    const api = this.helper.getApi();3230    const props = (await api.query.refungible.tokenProperties(this.collectionId, tokenId)).toJSON() as any;32313232    return props?.consumedSpace ?? 0;3233  }32343235  async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount = 1n) {3236    return await this.helper.rft.transferToken(signer, this.collectionId, tokenId, addressObj, amount);3237  }32383239  async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {3240    return await this.helper.rft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj, amount);3241  }32423243  async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount = 1n) {3244    return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, amount);3245  }32463247  async repartitionToken(signer: TSigner, tokenId: number, amount: bigint) {3248    return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount);3249  }32503251  async mintToken(signer: TSigner, pieces = 1n, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3252    return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties});3253  }32543255  async mintMultipleTokens(signer: TSigner, tokens: { pieces: bigint, owner: ICrossAccountId, properties?: IProperty[] }[]) {3256    return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens);3257  }32583259  async burnToken(signer: TSigner, tokenId: number, amount = 1n) {3260    return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, amount);3261  }32623263  async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, amount = 1n) {3264    return await this.helper.rft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, amount);3265  }32663267  async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3268    return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties);3269  }32703271  async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3272    return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3273  }32743275  async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3276    return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3277  }32783279  async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {3280    return await this.helper.rft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);3281  }32823283  async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3284    return await this.helper.rft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);3285  }3286}32873288export class UniqueFTCollection extends UniqueBaseCollection {3289  async getBalance(addressObj: ICrossAccountId) {3290    return await this.helper.ft.getBalance(this.collectionId, addressObj);3291  }32923293  async getTotalPieces() {3294    return await this.helper.ft.getTotalPieces(this.collectionId);3295  }32963297  async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3298    return await this.helper.ft.getApprovedTokens(this.collectionId, fromAddressObj, toAddressObj);3299  }33003301  async getTop10Owners() {3302    return await this.helper.ft.getTop10Owners(this.collectionId);3303  }33043305  async mint(signer: TSigner, amount = 1n, owner: ICrossAccountId = {Substrate: signer.address}) {3306    return await this.helper.ft.mintTokens(signer, this.collectionId, amount, owner);3307  }33083309  async mintWithOneOwner(signer: TSigner, tokens: { value: bigint }[], owner: ICrossAccountId = {Substrate: signer.address}) {3310    return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, tokens, owner);3311  }33123313  async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount = 1n) {3314    return await this.helper.ft.transfer(signer, this.collectionId, toAddressObj, amount);3315  }33163317  async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {3318    return await this.helper.ft.transferFrom(signer, this.collectionId, fromAddressObj, toAddressObj, amount);3319  }33203321  async burnTokens(signer: TSigner, amount = 1n) {3322    return await this.helper.ft.burnTokens(signer, this.collectionId, amount);3323  }33243325  async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount = 1n) {3326    return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount);3327  }33283329  async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount = 1n) {3330    return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);3331  }3332}33333334export class UniqueBaseToken {3335  collection: UniqueNFTCollection | UniqueRFTCollection;3336  collectionId: number;3337  tokenId: number;33383339  constructor(tokenId: number, collection: UniqueNFTCollection | UniqueRFTCollection) {3340    this.collection = collection;3341    this.collectionId = collection.collectionId;3342    this.tokenId = tokenId;3343  }33443345  async getNextSponsored(addressObj: ICrossAccountId) {3346    return await this.collection.getTokenNextSponsored(this.tokenId, addressObj);3347  }33483349  async getProperties(propertyKeys?: string[] | null) {3350    return await this.collection.getTokenProperties(this.tokenId, propertyKeys);3351  }33523353  async getTokenPropertiesConsumedSpace() {3354    return await this.collection.getTokenPropertiesConsumedSpace(this.tokenId);3355  }33563357  async setProperties(signer: TSigner, properties: IProperty[]) {3358    return await this.collection.setTokenProperties(signer, this.tokenId, properties);3359  }33603361  async deleteProperties(signer: TSigner, propertyKeys: string[]) {3362    return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys);3363  }33643365  async doesExist() {3366    return await this.collection.doesTokenExist(this.tokenId);3367  }33683369  nestingAccount(): ICrossAccountId {3370    return this.collection.helper.util.getTokenAccount(this);3371  }3372}33733374export class UniqueNFToken extends UniqueBaseToken {3375  declare collection: UniqueNFTCollection;33763377  constructor(tokenId: number, collection: UniqueNFTCollection) {3378    super(tokenId, collection);3379    this.collection = collection;3380  }33813382  async getData(blockHashAt?: string) {3383    return await this.collection.getToken(this.tokenId, blockHashAt);3384  }33853386  async getOwner(blockHashAt?: string) {3387    return await this.collection.getTokenOwner(this.tokenId, blockHashAt);3388  }33893390  async getTopmostOwner(blockHashAt?: string) {3391    return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);3392  }33933394  async getChildren(blockHashAt?: string) {3395    return await this.collection.getTokenChildren(this.tokenId, blockHashAt);3396  }33973398  async nest(signer: TSigner, toTokenObj: IToken) {3399    return await this.collection.nestToken(signer, this.tokenId, toTokenObj);3400  }34013402  async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3403    return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);3404  }34053406  async transfer(signer: TSigner, addressObj: ICrossAccountId) {3407    return await this.collection.transferToken(signer, this.tokenId, addressObj);3408  }34093410  async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3411    return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj);3412  }34133414  async approve(signer: TSigner, toAddressObj: ICrossAccountId) {3415    return await this.collection.approveToken(signer, this.tokenId, toAddressObj);3416  }34173418  async isApproved(toAddressObj: ICrossAccountId) {3419    return await this.collection.isTokenApproved(this.tokenId, toAddressObj);3420  }34213422  async burn(signer: TSigner) {3423    return await this.collection.burnToken(signer, this.tokenId);3424  }34253426  async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId) {3427    return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj);3428  }3429}34303431export class UniqueRFToken extends UniqueBaseToken {3432  declare collection: UniqueRFTCollection;34333434  constructor(tokenId: number, collection: UniqueRFTCollection) {3435    super(tokenId, collection);3436    this.collection = collection;3437  }34383439  async getData(blockHashAt?: string) {3440    return await this.collection.getToken(this.tokenId, blockHashAt);3441  }34423443  async getOwner(blockHashAt?: string) {3444    return await this.collection.getTokenOwner(this.tokenId, blockHashAt);3445  }34463447  async getTop10Owners() {3448    return await this.collection.getTop10TokenOwners(this.tokenId);3449  }34503451  async getTopmostOwner(blockHashAt?: string) {3452    return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);3453  }34543455  async nest(signer: TSigner, toTokenObj: IToken) {3456    return await this.collection.nestToken(signer, this.tokenId, toTokenObj);3457  }34583459  async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3460    return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);3461  }34623463  async getBalance(addressObj: ICrossAccountId) {3464    return await this.collection.getTokenBalance(this.tokenId, addressObj);3465  }34663467  async getTotalPieces() {3468    return await this.collection.getTokenTotalPieces(this.tokenId);3469  }34703471  async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) {3472    return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj);3473  }34743475  async transfer(signer: TSigner, addressObj: ICrossAccountId, amount = 1n) {3476    return await this.collection.transferToken(signer, this.tokenId, addressObj, amount);3477  }34783479  async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount = 1n) {3480    return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj, amount);3481  }34823483  async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount = 1n) {3484    return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount);3485  }34863487  async repartition(signer: TSigner, amount: bigint) {3488    return await this.collection.repartitionToken(signer, this.tokenId, amount);3489  }34903491  async burn(signer: TSigner, amount = 1n) {3492    return await this.collection.burnToken(signer, this.tokenId, amount);3493  }34943495  async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount = 1n) {3496    return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj, amount);3497  }3498}
deletedjs-packages/tests/check-event/burnItemEvent.test.tsdiffbeforeafterboth
--- a/js-packages/tests/check-event/burnItemEvent.test.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/types.js';
-
-
-describe('Burn Item event ', () => {
-  let alice: IKeyringPair;
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice] = await helper.arrange.createAccounts([10n], donor);
-    });
-  });
-  itSub('Check event from burnItem(): ', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-    const token = await collection.mintToken(alice, {Substrate: alice.address});
-    await token.burn(alice);
-    await helper.wait.newBlocks(1);
-
-    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
-    const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
-    expect(eventStrings).to.contains('common.ItemDestroyed');
-    expect(eventStrings).to.contains('treasury.Deposit');
-    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
-  });
-});
deletedjs-packages/tests/check-event/createCollectionEvent.test.tsdiffbeforeafterboth
--- a/js-packages/tests/check-event/createCollectionEvent.test.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/types.js';
-
-describe('Create collection event ', () => {
-  let alice: IKeyringPair;
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice] = await helper.arrange.createAccounts([10n], donor);
-    });
-  });
-  itSub('Check event from createCollection(): ', async ({helper}) => {
-    await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-    await helper.wait.newBlocks(1);
-    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
-    const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
-    expect(eventStrings).to.contains('common.CollectionCreated');
-    expect(eventStrings).to.contains('treasury.Deposit');
-    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
-  });
-});
deletedjs-packages/tests/check-event/createItemEvent.test.tsdiffbeforeafterboth
--- a/js-packages/tests/check-event/createItemEvent.test.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/types.js';
-
-describe('Create Item event ', () => {
-  let alice: IKeyringPair;
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice] = await helper.arrange.createAccounts([10n], donor);
-    });
-  });
-  itSub('Check event from createItem(): ', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-    await collection.mintToken(alice, {Substrate: alice.address});
-    await helper.wait.newBlocks(1);
-    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
-    const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
-    expect(eventStrings).to.contains('common.ItemCreated');
-    expect(eventStrings).to.contains('treasury.Deposit');
-    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
-  });
-});
deletedjs-packages/tests/check-event/createMultipleItemsEvent.test.tsdiffbeforeafterboth
--- a/js-packages/tests/check-event/createMultipleItemsEvent.test.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/types.js';
-
-describe('Create Multiple Items Event event ', () => {
-  let alice: IKeyringPair;
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice] = await helper.arrange.createAccounts([10n], donor);
-    });
-  });
-  itSub('Check event from createMultipleItems(): ', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-
-    await collection.mintMultipleTokens(alice, [
-      {owner: {Substrate: alice.address}},
-      {owner: {Substrate: alice.address}},
-    ]);
-
-    await helper.wait.newBlocks(1);
-    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
-    const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
-    expect(eventStrings).to.contains('common.ItemCreated');
-    expect(eventStrings).to.contains('treasury.Deposit');
-    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
-  });
-});
deletedjs-packages/tests/check-event/destroyCollectionEvent.test.tsdiffbeforeafterboth
--- a/js-packages/tests/check-event/destroyCollectionEvent.test.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/types.js';
-
-describe('Destroy collection event ', () => {
-  let alice: IKeyringPair;
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice] = await helper.arrange.createAccounts([10n], donor);
-    });
-  });
-
-  itSub('Check event from destroyCollection(): ', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-    await collection.burn(alice);
-    await helper.wait.newBlocks(1);
-    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
-    const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
-    expect(eventStrings).to.contains('common.CollectionDestroyed');
-    expect(eventStrings).to.contains('treasury.Deposit');
-    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
-  });
-});
deletedjs-packages/tests/check-event/transferEvent.test.tsdiffbeforeafterboth
--- a/js-packages/tests/check-event/transferEvent.test.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/types.js';
-
-describe('Transfer event ', () => {
-  let alice: IKeyringPair;
-  let bob: IKeyringPair;
-
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
-    });
-  });
-
-  itSub('Check event from transfer(): ', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-    const token = await collection.mintToken(alice, {Substrate: alice.address});
-    await token.transfer(alice, {Substrate: bob.address});
-    await helper.wait.newBlocks(1);
-    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
-    const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
-    expect(eventStrings).to.contains('common.Transfer');
-    expect(eventStrings).to.contains('treasury.Deposit');
-    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
-  });
-});
deletedjs-packages/tests/check-event/transferFromEvent.test.tsdiffbeforeafterboth
--- a/js-packages/tests/check-event/transferFromEvent.test.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub} from '../util/index.js';
-import type {IEvent} from '@unique/playgrounds/types.js';
-
-describe('Transfer event ', () => {
-  let alice: IKeyringPair;
-  let bob: IKeyringPair;
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
-    });
-  });
-
-  itSub('Check event from transfer(): ', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
-    const token = await collection.mintToken(alice, {Substrate: alice.address});
-    await token.transferFrom(alice, {Substrate: alice.address}, {Substrate: bob.address});
-    await helper.wait.newBlocks(1);
-    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
-    const eventStrings = event.map(e => `${e.section}.${e.method}`);
-
-    expect(eventStrings).to.contains('common.Transfer');
-    expect(eventStrings).to.contains('treasury.Deposit');
-    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
-  });
-});
deletedjs-packages/tests/collator-selection/collatorSelection.seqtest.tsdiffbeforeafterboth
--- a/js-packages/tests/collator-selection/collatorSelection.seqtest.ts
+++ /dev/null
@@ -1,423 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from '../util/index.js';
-
-async function nodeAddress(name: string) {
-  // eslint-disable-next-line require-await
-  return await usingPlaygrounds(async (helper) => {
-    const envNodeStash = `RELAY_UNIQUE_NODE_${name.toUpperCase()}_STASH`;
-
-    const nodeStash = process.env[envNodeStash];
-    if(nodeStash) {
-      return helper.address.normalizeSubstrateToChainFormat(nodeStash);
-    } else {
-      throw Error(`"${envNodeStash}" env var is not set`);
-    }
-  });
-}
-
-async function getInitialInvulnerables() {
-  return await Promise.all([
-    nodeAddress('alpha'),
-    nodeAddress('beta'),
-    nodeAddress('gamma'),
-    nodeAddress('delta'),
-  ]);
-}
-
-async function resetInvulnerables() {
-  await usingPlaygrounds(async (helper, privateKey) => {
-    const superuser = await privateKey('//Alice');
-    const initialInvulnerables = await getInitialInvulnerables();
-
-    const invulnerables = await helper.collatorSelection.getInvulnerables();
-
-    // Remove all invulnerables but the first one
-    const firstInvulnerable = invulnerables[0];
-
-    let nonce = await helper.chain.getNonce(superuser.address);
-    await Promise.all(invulnerables.slice(1).map(invulnerable => helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++})));
-
-    // Add the initial invulnerables
-    await Promise.all(initialInvulnerables.map(invulnerable => helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [invulnerable], true, {nonce: nonce++})));
-
-    // Remove the first invulnerable if it's not an initial one
-    if(!initialInvulnerables.includes(firstInvulnerable)) {
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [firstInvulnerable]);
-    }
-  });
-}
-
-// todo:collator Most preferable to launch this test in parallel somehow -- or change the session period (1 hr).
-describe('Integration Test: Collator Selection', () => {
-  let superuser: IKeyringPair;
-  let previousLicenseBond = 0n;
-  let licenseBond = 0n;
-
-  before(async function() {
-    if(!process.env.RUN_COLLATOR_TESTS) this.skip();
-
-    await usingPlaygrounds(async (helper, privateKey) => {
-      requirePalletsOrSkip(this, helper, [Pallets.CollatorSelection]);
-      superuser = await privateKey('//Alice');
-
-      previousLicenseBond = await helper.collatorSelection.getLicenseBond();
-      licenseBond = 10n * helper.balance.getOneTokenNominal();
-      await helper.getSudo().collatorSelection.setLicenseBond(superuser, licenseBond);
-    });
-  });
-
-  describe('Dynamic shuffling of collators', () => {
-    // These two are the default invulnerables, and should return to be invulnerables after this suite.
-    let alphaNode: string;
-    let betaNode: string;
-
-    let gammaNode: string;
-    let deltaNode: string;
-
-    before(async function() {
-      await usingPlaygrounds(async (helper) => {
-        // todo:collator see again if blocks start to be finalized in dev mode
-        // Skip the collator block production in dev mode, since the blocks are sealed automatically.
-        if(await helper.arrange.isDevNode()) this.skip();
-
-        [alphaNode, betaNode, gammaNode, deltaNode] = await getInitialInvulnerables();
-
-        const invulnerables = await helper.collatorSelection.getInvulnerables();
-        expect(invulnerables.length, 'Invalid initial invulnerables number').to.be.equal(4);
-        expect(invulnerables, 'Invalid initial invulnerables').containSubset([alphaNode, betaNode, gammaNode, deltaNode]);
-      });
-    });
-
-    itSub('Change invulnerables and make sure they start producing blocks', async ({helper}) => {
-      let nonce = await helper.chain.getNonce(superuser.address);
-
-      nonce = await helper.chain.getNonce(superuser.address);
-      await expect(Promise.all([
-        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [alphaNode], true, {nonce: nonce++}),
-        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [betaNode], true, {nonce: nonce++}),
-      ])).to.be.fulfilled;
-
-      const newInvulnerables = await helper.collatorSelection.getInvulnerables();
-      expect(newInvulnerables).to.contain(gammaNode).and.contain(deltaNode).and.be.length(2);
-
-      await helper.wait.newSessions(2);
-
-      const newValidators = await helper.callRpc('api.query.session.validators');
-      expect(newValidators).to.contain(gammaNode).and.contain(deltaNode).and.be.length(2);
-
-      const lastBlockNumber = await helper.chain.getLatestBlockNumber();
-      await helper.wait.newBlocks(1);
-      const lastGammaBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [gammaNode])).toNumber();
-      const lastDeltaBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [deltaNode])).toNumber();
-      expect(lastGammaBlock >= lastBlockNumber || lastDeltaBlock >= lastBlockNumber).to.be.true;
-    });
-
-    after(async () => {
-      await resetInvulnerables();
-    });
-  });
-
-  describe('Getting and releasing licenses to collate', () => {
-    let crowd: IKeyringPair[];
-
-    before(async function() {
-      await usingPlaygrounds(async (helper) => {
-        crowd = await helper.arrange.createCrowd(20, 100n, superuser);
-
-        // set session keys for everyone
-        await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));
-      });
-    });
-
-    describe('Positive', () => {
-      itSub('Can lease and release a license', async ({helper}) => {
-        const account = crowd.pop()!;
-
-        // make sure it does not have any reserved funds
-        expect((await helper.balance.getSubstrateFull(account.address)).reserved).to.be.equal(0n);
-
-        // getting a license reserves a license bond cost
-        await helper.collatorSelection.obtainLicense(account);
-        expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(licenseBond);
-        expect((await helper.balance.getSubstrateFull(account.address)).reserved).to.be.equal(licenseBond);
-
-        // releasing a license un-reserves the license bond cost
-        await helper.collatorSelection.releaseLicense(account);
-        expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(0n);
-
-        const balance = await helper.balance.getSubstrateFull(account.address);
-        expect(balance.reserved).to.be.equal(0n);
-        expect(balance.free > 100n - licenseBond);
-      });
-
-      itSub('Can force revoke a license', async ({helper}) => {
-        const account = crowd.pop()!;
-
-        // getting a license reserves a license bond cost
-        const previousBalance = await helper.balance.getSubstrateFull(account.address);
-        await helper.collatorSelection.obtainLicense(account);
-        expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(licenseBond);
-
-        // force-releasing a license un-reserves the license bond cost as well
-        await helper.getSudo().collatorSelection.forceReleaseLicense(superuser, account.address);
-        expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(previousBalance.reserved);
-
-        const balance = await helper.balance.getSubstrateFull(account.address);
-        expect(balance.reserved).to.be.equal(previousBalance.reserved);
-        expect(balance.free > previousBalance.free - licenseBond);
-      });
-    });
-
-    describe('Negative', () => {
-      itSub('Cannot get a license without session keys set', async ({helper}) => {
-        const [account] = await helper.arrange.createAccounts([100n], superuser);
-        await expect(helper.collatorSelection.obtainLicense(account))
-          .to.be.rejectedWith(/collatorSelection.ValidatorNotRegistered/);
-      });
-
-      itSub('Cannot register a license twice', async ({helper}) => {
-        const account = crowd.pop()!;
-        await helper.collatorSelection.obtainLicense(account);
-        await expect(helper.collatorSelection.obtainLicense(account))
-          .to.be.rejectedWith(/collatorSelection.AlreadyHoldingLicense/);
-      });
-
-      itSub('Cannot release a license twice', async ({helper}) => {
-        const account = crowd.pop()!;
-        await helper.collatorSelection.obtainLicense(account);
-        await helper.collatorSelection.releaseLicense(account);
-        await expect(helper.collatorSelection.releaseLicense(account))
-          .to.be.rejectedWith(/collatorSelection.NoLicense/);
-      });
-
-      itSub('Cannot force revoke a license as non-sudo', async ({helper}) => {
-        const account = crowd.pop()!;
-        await helper.collatorSelection.obtainLicense(account);
-        await expect(helper.collatorSelection.forceReleaseLicense(superuser, account.address))
-          .to.be.rejectedWith(/BadOrigin/);
-      });
-    });
-  });
-
-  describe('Onboarding, collating, and offboarding as collator candidates', () => {
-    let crowd: IKeyringPair[];
-
-    before(async function() {
-      await usingPlaygrounds(async (helper) => {
-        crowd = await helper.arrange.createCrowd(20, 100n, superuser);
-
-        // set session keys for everyone
-        await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));
-      });
-    });
-
-    describe('Positive', () => {
-      itSub('Can onboard and offboard repeatedly', async ({helper}) => {
-        const account = crowd.pop()!;
-        await helper.collatorSelection.obtainLicense(account);
-        await helper.collatorSelection.onboard(account);
-        expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([account.address]);
-
-        await helper.collatorSelection.offboard(account);
-        expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([]);
-
-        await helper.collatorSelection.onboard(account);
-        expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([account.address]);
-
-        await helper.collatorSelection.offboard(account);
-        expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([]);
-      });
-
-      itSub('Penalizes and forfeits license from faulty collators', async ({helper}) => {
-        // This one shouldn't even be able to produce blocks.
-        const account = crowd.pop()!;
-        await helper.collatorSelection.obtainLicense(account);
-        await helper.collatorSelection.onboard(account);
-        expect(await helper.collatorSelection.getCandidates()).to.contain(account.address);
-
-        // Wait for 3 new sessions before checking that the collator will be kicked:
-        // one to get collator onboarded, and another two for the collator to fail
-        await helper.wait.newSessions(3);
-
-        expect(await helper.collatorSelection.getCandidates()).to.not.contain(account.address);
-        expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(0n);
-
-        // The account's reserved funds get slashed as a penalty
-        const balance = await helper.balance.getSubstrateFull(account.address);
-        expect(balance.reserved).to.be.equal(0n);
-        expect(balance.free < 100n - licenseBond);
-      });
-    });
-
-    describe('Negative', () => {
-      itSub('Cannot onboard without a license', async ({helper}) => {
-        const account = crowd.pop()!;
-        await expect(helper.collatorSelection.onboard(account))
-          .to.be.rejectedWith(/collatorSelection.NoLicense/);
-      });
-
-      itSub('Cannot offboard without a license', async ({helper}) => {
-        const account = crowd.pop()!;
-        await expect(helper.collatorSelection.offboard(account))
-          .to.be.rejectedWith(/collatorSelection.NotCandidate/);
-      });
-
-      itSub('Cannot offboard while not onboarded', async ({helper}) => {
-        const account = crowd.pop()!;
-        await helper.collatorSelection.obtainLicense(account);
-        await expect(helper.collatorSelection.offboard(account))
-          .to.be.rejectedWith(/collatorSelection.NotCandidate/);
-      });
-
-      itSub('Cannot onboard while already onboarded', async ({helper}) => {
-        const account = crowd.pop()!;
-        await helper.collatorSelection.obtainLicense(account);
-        await helper.collatorSelection.onboard(account);
-        await expect(helper.collatorSelection.onboard(account))
-          .to.be.rejectedWith(/collatorSelection.AlreadyCandidate/);
-      });
-    });
-  });
-
-  describe('Addition and removal of invulnerables', () => {
-    describe('Positive', () => {
-      itSub('Adds an invulnerable', async ({helper}) => {
-        const [account] = await helper.arrange.createAccounts([10n], superuser);
-        const invulnerables = await helper.collatorSelection.getInvulnerables();
-
-        await helper.session.setOwnKeysFromAddress(account);
-        await helper.getSudo().collatorSelection.addInvulnerable(superuser, account.address);
-
-        const newInvulnerables = await helper.collatorSelection.getInvulnerables();
-        expect(invulnerables.concat(account.address)).to.have.all.members(newInvulnerables);
-      });
-
-      itSub('Removes an invulnerable', async ({helper}) => {
-        const invulnerables = await helper.collatorSelection.getInvulnerables();
-        const lastInvulnerable = invulnerables.pop()!;
-
-        await helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable);
-        const newInvulnerables = await helper.collatorSelection.getInvulnerables();
-        // invulnerables had its last element removed, so they should be equal
-        expect(newInvulnerables).to.have.all.members(invulnerables);
-      });
-    });
-
-    describe('Negative', () => {
-      itSub('Does not duplicate an invulnerable', async ({helper}) => {
-        const invulnerables = await helper.collatorSelection.getInvulnerables();
-        // adding an already invulnerable should not fail, but should not duplicate it either
-        await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, invulnerables[0]))
-          .to.be.fulfilled;
-        const newInvulnerables = await helper.collatorSelection.getInvulnerables();
-        expect(newInvulnerables).to.have.all.members(invulnerables);
-      });
-
-      itSub('Cannot remove a non-existent invulnerable', async ({helper}) => {
-        const [account] = await helper.arrange.createAccounts([0n], superuser);
-        await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, account.address))
-          .to.be.rejectedWith(/collatorSelection.NotInvulnerable/);
-      });
-
-      itSub('Cannot allow invulnerables to be empty', async ({helper}) => {
-        const invulnerables = await helper.collatorSelection.getInvulnerables();
-        const lastInvulnerable = invulnerables.pop()!;
-
-        let nonce = await helper.chain.getNonce(superuser.address);
-        await Promise.all(invulnerables.map((i: any) =>
-          helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i], true, {nonce: nonce++})));
-
-        await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable))
-          .to.be.rejectedWith(/collatorSelection.TooFewInvulnerables/);
-
-        const newInvulnerables = await helper.collatorSelection.getInvulnerables();
-        expect(newInvulnerables).to.be.deep.equal([lastInvulnerable]);
-
-        // restore the invulnerables to the previous state
-        nonce = await helper.chain.getNonce(superuser.address);
-        await Promise.all(invulnerables.map((i: any) =>
-          helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i], true, {nonce: nonce++})));
-      });
-
-      itSub('Cannot have too many invulnerables', async ({helper}) => {
-        // todo:collator make sure that there is enough session time for a set of tests
-        // 28 non-functioning collators, teehee.
-
-        const invulnerablesLength = (await helper.collatorSelection.getInvulnerables()).length;
-        const invulnerablesUntilLimit = (await helper.collatorSelection.getDesiredCollators()) - invulnerablesLength;
-        const newInvulnerables = await helper.arrange.createAccounts(Array(invulnerablesUntilLimit).fill(10n), superuser);
-        const [lastInvulnerable] = await helper.arrange.createAccounts([10n], superuser);
-
-        await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
-          helper.session.setOwnKeysFromAddress(i)));
-        await helper.session.setOwnKeysFromAddress(lastInvulnerable);
-
-        let nonce = await helper.chain.getNonce(superuser.address);
-        await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
-          helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i.address], true, {nonce: nonce++})));
-
-        await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, lastInvulnerable.address))
-          .to.be.rejectedWith(/collatorSelection.TooManyInvulnerables/);
-
-        // restore the invulnerables to the previous state
-        nonce = await helper.chain.getNonce(superuser.address);
-        await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
-          helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i.address], true, {nonce: nonce++})));
-      });
-
-      itSub('Forbids a non-sudo to add an invulnerable', async ({helper}) => {
-        const [account] = await helper.arrange.createAccounts([10n], superuser);
-        const invulnerables = await helper.collatorSelection.getInvulnerables();
-
-        await helper.session.setOwnKeysFromAddress(account);
-        await expect(helper.collatorSelection.addInvulnerable(superuser, account.address))
-          .to.be.rejectedWith(/BadOrigin/);
-
-        const newInvulnerables = await helper.collatorSelection.getInvulnerables();
-        expect(newInvulnerables).to.be.members(invulnerables);
-      });
-
-      itSub('Forbids a non-sudo to remove an invulnerable', async ({helper}) => {
-        const invulnerables = await helper.collatorSelection.getInvulnerables();
-        await expect(helper.collatorSelection.removeInvulnerable(superuser, invulnerables[0]))
-          .to.be.rejectedWith(/BadOrigin/);
-        expect(await helper.collatorSelection.getInvulnerables()).to.have.all.members(invulnerables);
-      });
-
-      after(async function() {
-        await resetInvulnerables();
-      });
-    });
-  });
-
-  after(async function() {
-    if(!process.env.RUN_COLLATOR_TESTS) return;
-
-    await usingPlaygrounds(async (helper) => {
-      if(helper.fetchMissingPalletNames([Pallets.CollatorSelection]).length != 0) return;
-
-      await helper.getSudo().collatorSelection.setLicenseBond(superuser, previousLicenseBond);
-
-      const candidates = await helper.collatorSelection.getCandidates();
-      let nonce = await helper.chain.getNonce(superuser.address);
-      await Promise.all(candidates.map(candidate =>
-        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.forceReleaseLicense', [candidate], true, {nonce: nonce++})));
-    });
-  });
-});
deletedjs-packages/tests/collator-selection/identity.seqtest.tsdiffbeforeafterboth
--- a/js-packages/tests/collator-selection/identity.seqtest.ts
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from '../util/index.js';
-import {UniqueHelper} from '@unique/playgrounds/unique.js';
-
-async function getIdentities(helper: UniqueHelper) {
-  const identities: [string, any][] = [];
-  for(const [key, value] of await helper.getApi().query.identity.identityOf.entries())
-    identities.push([(key as any).toHuman(), (value as any).unwrap()]);
-  return identities;
-}
-
-async function getIdentityAccounts(helper: UniqueHelper) {
-  return (await getIdentities(helper)).flatMap(([key, _value]) => key);
-}
-
-async function getSubIdentityAccounts(helper: UniqueHelper, address: string) {
-  return ((await helper.getApi().query.identity.subsOf(address)).toHuman() as any)[1];
-}
-
-async function getSubIdentityName(helper: UniqueHelper, address: string) {
-  return ((await helper.getApi().query.identity.superOf(address)).toHuman() as any);
-}
-
-describe('Integration Test: Identities Manipulation', () => {
-  let superuser: IKeyringPair;
-
-  before(async function() {
-    if(!process.env.RUN_COLLATOR_TESTS) this.skip();
-
-    await usingPlaygrounds(async (helper, privateKey) => {
-      requirePalletsOrSkip(this, helper, [Pallets.Identity]);
-      superuser = await privateKey('//Alice');
-    });
-  });
-
-  itSub('Normal calls do not work', async ({helper}) => {
-    // console.error = () => {};
-    await expect(helper.executeExtrinsic(superuser, 'api.tx.identity.setIdentity', [{info: {display: {Raw: 'Meowser'}}}] as any))
-      .to.be.rejectedWith(/Transaction call is not expected/);
-  });
-
-  describe('Identities', () => {
-    itSub('Sets identities', async ({helper}) => {
-      const oldIdentitiesCount = (await getIdentityAccounts(helper)).length;
-
-      const crowdSize = 10;
-      const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
-      const identities = crowd.map((acc, i) => [acc.address, {info: {display: {Raw: `accounter #${i}`}}}]);
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
-
-      expect((await getIdentityAccounts(helper)).length).to.be.equal(oldIdentitiesCount + crowdSize);
-    });
-
-    itSub('Setting identities does not delete existing but does overwrite', async ({helper}) => {
-      const crowd = await helper.arrange.createCrowd(10, 0n, superuser);
-      const identities = crowd.map((acc, i) => [acc.address, {info: {display: {Raw: `accounter #${i}`}}}]);
-
-      // insert a single identity
-      let singleIdentity = identities.pop()!;
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [[singleIdentity]] as any);
-
-      const oldIdentitiesCount = (await getIdentityAccounts(helper)).length;
-
-      // change an identity and push it with a few new others
-      singleIdentity = [singleIdentity[0], {info: {display: {Raw: 'something special'}}}];
-      identities.push(singleIdentity);
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
-
-      // oldIdentitiesCount + 9 because one identity is overwritten, not inserted on top
-      expect((await getIdentityAccounts(helper)).length).to.be.equal(oldIdentitiesCount + 9);
-      expect((await helper.callRpc('api.query.identity.identityOf', [singleIdentity[0]])).toHuman().info.display)
-        .to.be.deep.equal({Raw: 'something special'});
-    });
-
-    itSub('Removes identities', async ({helper}) => {
-      const crowd = await helper.arrange.createCrowd(10, 0n, superuser);
-      const identities = crowd.map((acc, i) => [acc.address, {info: {display: {Raw: `accounter #${i}`}}}]);
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
-      const oldIdentities = await getIdentityAccounts(helper);
-
-      // delete a couple, check that they are no longer there
-      const scapegoats = [crowd.pop()!.address, crowd.pop()!.address];
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceRemoveIdentities', [scapegoats]);
-      const newIdentities = await getIdentityAccounts(helper);
-      expect(newIdentities.concat(scapegoats)).to.be.have.members(oldIdentities);
-    });
-  });
-
-  describe('Sub-identities', () => {
-    itSub('Sets subs', async ({helper}) => {
-      const crowdSize = 18;
-      const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
-      const supers = [crowd.pop()!, crowd.pop()!, crowd.pop()!];
-
-      const subsPerSup = crowd.length / supers.length;
-      let subCount = 0;
-      const subs = [
-        crowd.slice(subCount, subCount += subsPerSup + 1),
-        crowd.slice(subCount, subCount += subsPerSup),
-        crowd.slice(subCount, subCount += subsPerSup - 1),
-      ];
-
-      const subsInfo = supers.map((acc, i) => [
-        acc.address, [
-          1000000n + BigInt(i + 1),
-          subs[i].map((sub, j) => [
-            sub.address, {Raw: `accounter #${j}`},
-          ]),
-        ],
-      ]);
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo] as any);
-
-      for(let i = 0; i < supers.length; i++) {
-        // check deposit
-        expect(((await helper.getApi().query.identity.subsOf(supers[i].address)).toJSON() as any)[0]).to.be.equal(1000001 + i);
-
-        const subsAccounts = await getSubIdentityAccounts(helper, supers[i].address);
-        // check sub-identities as account ids
-        expect(subsAccounts).to.include.members(subs[i].map(x => x.address));
-
-        for(let j = 0; j < subsAccounts.length; j++) {
-          // check sub-identities' names
-          expect((await getSubIdentityName(helper, subsAccounts[j]))[1]).to.be.deep.equal({Raw: `accounter #${j}`});
-        }
-      }
-    });
-
-    itSub('Setting sub-identities does not delete other existing but does overwrite own', async ({helper}) => {
-      const crowdSize = 18;
-      const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
-      const supers = [crowd.pop()!, crowd.pop()!, crowd.pop()!];
-
-      const subsPerSup = crowd.length / supers.length;
-      let subCount = 0;
-      const subs = [
-        crowd.slice(subCount, subCount += subsPerSup + 1),
-        crowd.slice(subCount, subCount += subsPerSup),
-        crowd.slice(subCount, subCount += subsPerSup - 1),
-      ];
-
-      const subsInfo1 = supers.map((acc, i) => [
-        acc.address, [
-          1000000n + BigInt(i + 1),
-          subs[i].map((sub, j) => [
-            sub.address, {Raw: `accounter #${j}`},
-          ]),
-        ],
-      ]);
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo1] as any);
-
-      // change some sub-identities...
-      subs[2].pop(); subs[2].pop(); subs[2].push(...await helper.arrange.createAccounts([0n], superuser));
-
-      // ...and set them
-      const subsInfo2 = [[
-        supers[2].address, [
-          999999n,
-          subs[2].map((sub, j) => [
-            sub.address, {Raw: `discounter #${j}`},
-          ]),
-        ],
-      ]];
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo2] as any);
-
-      // make sure everything else is the same
-      for(let i = 0; i < supers.length - 1; i++) {
-        // check deposit
-        expect(((await helper.getApi().query.identity.subsOf(supers[i].address)).toJSON() as any)[0]).to.be.equal(1000001 + i);
-
-        const subsAccounts = await getSubIdentityAccounts(helper, supers[i].address);
-        // check sub-identities as account ids
-        expect(subsAccounts).to.include.members(subs[i].map(x => x.address));
-
-        for(let j = 0; j < subsAccounts; j++) {
-          // check sub-identities' names
-          expect((await getSubIdentityName(helper, subsAccounts[j]))[1]).to.be.deep.equal({Raw: `accounter #${j}`});
-        }
-      }
-
-      // check deposit
-      expect(((await helper.getApi().query.identity.subsOf(supers[2].address)).toJSON() as any)[0]).to.be.equal(999999);
-
-      const subsAccounts = await getSubIdentityAccounts(helper, supers[2].address);
-      // check sub-identities as account ids
-      expect(subsAccounts).to.include.members(subs[2].map(x => x.address));
-
-      for(let j = 0; j < subsAccounts.length; j++) {
-        // check sub-identities' names
-        expect((await getSubIdentityName(helper, subsAccounts[j]))[1]).to.be.deep.equal({Raw: `discounter #${j}`});
-      }
-    });
-
-    itSub('Removes sub-identities', async ({helper}) => {
-      const crowdSize = 3;
-      const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
-      const sup = crowd.pop()!;
-
-      const subsInfo1 = [[
-        sup.address, [
-          1000000n,
-          crowd.map((sub, j) => [
-            sub.address, {Raw: `accounter #${j}`},
-          ]),
-        ],
-      ]];
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo1] as any);
-
-      // empty sub-identities should delete the records
-      const subsInfo2 = [[
-        sup.address, [
-          1000000n,
-          [],
-        ],
-      ]];
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo2] as any);
-
-      // check deposit
-      expect((await helper.getApi().query.identity.subsOf(sup.address)).toHuman()).to.be.deep.equal(['0', []]);
-
-      for(let j = 0; j < crowd.length; j++) {
-        // check sub-identities' names
-        expect((await getSubIdentityName(helper, crowd[j].address))).to.be.null;
-      }
-    });
-
-    itSub('Removing identities deletes associated sub-identities', async ({helper}) => {
-      const crowd = await helper.arrange.createCrowd(3, 0n, superuser);
-      const sup = crowd.pop()!;
-
-      // insert identity
-      const identities = [[sup.address, {info: {display: {Raw: 'mental'}}}]];
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
-
-      // and its sub-identities
-      const subsInfo = [[
-        sup.address, [
-          1000000n,
-          crowd.map((sub, j) => [
-            sub.address, {Raw: `accounter #${j}`},
-          ]),
-        ],
-      ]];
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo] as any);
-
-      // delete top identity
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceRemoveIdentities', [[sup.address]]);
-
-      // check that sub-identities are deleted
-      expect((await helper.getApi().query.identity.subsOf(sup.address)).toHuman()).to.be.deep.equal(['0', []]);
-
-      for(let j = 0; j < crowd.length; j++) {
-        // check sub-identities' names
-        expect((await getSubIdentityName(helper, crowd[j].address))).to.be.null;
-      }
-    });
-  });
-
-  after(async function() {
-    if(!process.env.RUN_COLLATOR_TESTS) return;
-
-    await usingPlaygrounds(async helper => {
-      if(helper.fetchMissingPalletNames([Pallets.Identity]).length != 0) return;
-
-      const identitiesToRemove: string[] = await getIdentityAccounts(helper);
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceRemoveIdentities', [identitiesToRemove]);
-    });
-  });
-});
modifiedjs-packages/tests/eth/marketplace-v2/marketplace.test.tsdiffbeforeafterboth
--- a/js-packages/tests/eth/marketplace-v2/marketplace.test.ts
+++ b/js-packages/tests/eth/marketplace-v2/marketplace.test.ts
@@ -40,6 +40,8 @@
   });
 
   async function deployMarket(helper: EthUniqueHelper, marketOwner: string) {
+    const nodeModulesDir = `${dirname}/../../../node_modules`;
+    const solApiDir = `${dirname}/../api`;
     return await helper.ethContract.deployByCode(
       marketOwner,
       'Market',
@@ -47,39 +49,39 @@
       [
         {
           solPath: '@unique-nft/solidity-interfaces/contracts/UniqueNFT.sol',
-          fsPath: `${dirname}/../api/UniqueNFT.sol`,
+          fsPath: `${solApiDir}/UniqueNFT.sol`,
         },
         {
           solPath: '@unique-nft/solidity-interfaces/contracts/UniqueFungible.sol',
-          fsPath: `${dirname}/../api/UniqueFungible.sol`,
+          fsPath: `${solApiDir}/UniqueFungible.sol`,
         },
         {
           solPath: '@openzeppelin/contracts/utils/introspection/IERC165.sol',
-          fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol`,
+          fsPath: `${nodeModulesDir}/@openzeppelin/contracts/utils/introspection/IERC165.sol`,
         },
         {
           solPath: '@openzeppelin/contracts/access/Ownable.sol',
-          fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/access/Ownable.sol`,
+          fsPath: `${nodeModulesDir}/@openzeppelin/contracts/access/Ownable.sol`,
         },
         {
           solPath: '@openzeppelin/contracts/utils/Context.sol',
-          fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/Context.sol`,
+          fsPath: `${nodeModulesDir}/@openzeppelin/contracts/utils/Context.sol`,
         },
         {
           solPath: '@openzeppelin/contracts/security/ReentrancyGuard.sol',
-          fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/security/ReentrancyGuard.sol`,
+          fsPath: `${nodeModulesDir}/@openzeppelin/contracts/security/ReentrancyGuard.sol`,
         },
         {
           solPath: '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol',
-          fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/utils/introspection/ERC165Checker.sol`,
+          fsPath: `${nodeModulesDir}/@openzeppelin/contracts/utils/introspection/ERC165Checker.sol`,
         },
         {
           solPath: '@openzeppelin/contracts/token/ERC721/IERC721.sol',
-          fsPath: `${dirname}/../../../../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol`,
+          fsPath: `${nodeModulesDir}/@openzeppelin/contracts/token/ERC721/IERC721.sol`,
         },
         {
           solPath: '@unique-nft/solidity-interfaces/contracts/CollectionHelpers.sol',
-          fsPath: `${dirname}/../api/CollectionHelpers.sol`,
+          fsPath: `${solApiDir}/CollectionHelpers.sol`,
         },
         {
           solPath: 'royalty/UniqueRoyaltyHelper.sol',
deletedjs-packages/tests/governance/council.test.tsdiffbeforeafterboth
--- a/js-packages/tests/governance/council.test.ts
+++ /dev/null
@@ -1,457 +0,0 @@
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
-import {Event} from '@unique/playgrounds/unique.dev.js';
-import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, councilMotionDuration, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, initTechComm, clearFellowship, dummyProposal, dummyProposalCall, initFellowship, defaultEnactmentMoment, fellowshipPropositionOrigin} from './util.js';
-import type {ICounselors} from './util.js';
-
-describeGov('Governance: Council tests', () => {
-  let donor: IKeyringPair;
-  let counselors: ICounselors;
-  let sudoer: IKeyringPair;
-
-  const moreThanHalfCouncilThreshold = 3;
-
-  before(async function() {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      requirePalletsOrSkip(this, helper, [Pallets.Council]);
-
-      donor = await privateKey({url: import.meta.url});
-      sudoer = await privateKey('//Alice');
-    });
-  });
-
-  beforeEach(async () => {
-    counselors = await initCouncil(donor, sudoer);
-  });
-
-  afterEach(async () => {
-    await clearCouncil(sudoer);
-    await clearTechComm(sudoer);
-  });
-
-  async function proposalFromMoreThanHalfCouncil(proposal: any) {
-    return await usingPlaygrounds(async (helper) => {
-      expect((await helper.callRpc('api.query.councilMembership.members')).toJSON().length).to.be.equal(5);
-      const proposeResult = await helper.council.collective.propose(
-        counselors.filip,
-        proposal,
-        moreThanHalfCouncilThreshold,
-      );
-
-      const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
-      const proposalIndex = councilProposedEvent.proposalIndex;
-      const proposalHash = councilProposedEvent.proposalHash;
-
-
-      await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
-      await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);
-      await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);
-
-      return await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
-    });
-  }
-
-  async function proposalFromAllCouncil(proposal: any) {
-    return await usingPlaygrounds(async (helper) => {
-      expect((await helper.callRpc('api.query.councilMembership.members')).toJSON().length).to.be.equal(5);
-      const proposeResult = await helper.council.collective.propose(
-        counselors.filip,
-        proposal,
-        moreThanHalfCouncilThreshold,
-      );
-
-      const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
-      const proposalIndex = councilProposedEvent.proposalIndex;
-      const proposalHash = councilProposedEvent.proposalHash;
-
-
-      await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
-      await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);
-      await helper.council.collective.vote(counselors.ildar, proposalHash, proposalIndex, true);
-      await helper.council.collective.vote(counselors.irina, proposalHash, proposalIndex, true);
-      await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);
-
-      return await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
-    });
-  }
-
-  itSub('>50% of Council can externally propose SuperMajorityAgainst', async ({helper}) => {
-    const forceSetBalanceReceiver = helper.arrange.createEmptyAccount();
-    const forceSetBalanceTestValue = 20n * 10n ** 25n;
-
-    const democracyProposal = await helper.constructApiCall('api.tx.balances.forceSetBalance', [
-      forceSetBalanceReceiver.address, forceSetBalanceTestValue,
-    ]);
-
-    const councilProposal = await helper.democracy.externalProposeDefaultCall(democracyProposal);
-
-    const proposeResult = await helper.council.collective.propose(
-      counselors.filip,
-      councilProposal,
-      moreThanHalfCouncilThreshold,
-    );
-
-    const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
-    const proposalIndex = councilProposedEvent.proposalIndex;
-    const proposalHash = councilProposedEvent.proposalHash;
-
-    await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
-    await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);
-    await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);
-
-    await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
-
-    const democracyStartedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
-    const democracyReferendumIndex = democracyStartedEvent.referendumIndex;
-    const democracyThreshold = democracyStartedEvent.threshold;
-
-    expect(democracyThreshold).to.be.equal('SuperMajorityAgainst');
-
-    await helper.democracy.vote(counselors.filip, democracyReferendumIndex, {
-      Standard: {
-        vote: {
-          aye: true,
-          conviction: 1,
-        },
-        balance: 10_000n,
-      },
-    });
-
-    await helper.democracy.vote(counselors.charu, democracyReferendumIndex, {
-      Standard: {
-        vote: {
-          aye: false,
-          conviction: 1,
-        },
-        balance: 50_000n,
-      },
-    });
-
-    const passedReferendumEvent = await helper.wait.expectEvent(democracyVotingPeriod, Event.Democracy.Passed);
-    expect(passedReferendumEvent.referendumIndex).to.be.equal(democracyReferendumIndex);
-
-    await helper.wait.expectEvent(democracyEnactmentPeriod, Event.Scheduler.Dispatched);
-    const receiverBalance = await helper.balance.getSubstrate(forceSetBalanceReceiver.address);
-    expect(receiverBalance).to.be.equal(forceSetBalanceTestValue);
-  });
-
-  itSub('Council prime member vote is the default', async ({helper}) => {
-    const newTechCommMember = helper.arrange.createEmptyAccount();
-    const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address);
-    const proposeResult = await helper.council.collective.propose(
-      counselors.filip,
-      addMemberProposal,
-      moreThanHalfCouncilThreshold,
-    );
-
-    const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
-    const proposalIndex = councilProposedEvent.proposalIndex;
-    const proposalHash = councilProposedEvent.proposalHash;
-
-    await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
-
-    await helper.wait.newBlocks(councilMotionDuration);
-    const closeResult = await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
-    const closeEvent = Event.Council.Closed.expect(closeResult);
-    const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON() as string[];
-    expect(closeEvent.yes).to.be.equal(members.length);
-  });
-
-  itSub('Superuser can add a member', async ({helper}) => {
-    const newMember = helper.arrange.createEmptyAccount();
-    await expect(helper.getSudo().council.membership.addMember(sudoer, newMember.address)).to.be.fulfilled;
-
-    const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
-    expect(members).to.contains(newMember.address);
-  });
-
-  itSub('Superuser can remove a member', async ({helper}) => {
-    await expect(helper.getSudo().council.membership.removeMember(sudoer, counselors.alex.address)).to.be.fulfilled;
-
-    const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
-    expect(members).to.not.contains(counselors.alex.address);
-  });
-
-  itSub('>50% Council can add TechComm member', async ({helper}) => {
-    const newTechCommMember = helper.arrange.createEmptyAccount();
-    const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address);
-
-    await proposalFromMoreThanHalfCouncil(addMemberProposal);
-
-    const techCommMembers = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
-    expect(techCommMembers).to.contains(newTechCommMember.address);
-  });
-
-  itSub('Council can remove TechComm member', async ({helper}) => {
-    const techComm = await initTechComm(donor, sudoer);
-    const removeMemberPrpoposal = helper.technicalCommittee.membership.removeMemberCall(techComm.andy.address);
-    await proposalFromMoreThanHalfCouncil(removeMemberPrpoposal);
-
-    const techCommMembers = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
-    expect(techCommMembers).to.not.contains(techComm.andy.address);
-  });
-
-  itSub.skip('Council member can add Fellowship member', async ({helper}) => {
-    const newFellowshipMember = helper.arrange.createEmptyAccount();
-    await expect(helper.council.collective.execute(
-      counselors.alex,
-      helper.fellowship.collective.addMemberCall(newFellowshipMember.address),
-    )).to.be.fulfilled;
-    const fellowshipMembers = (await helper.callRpc('api.query.fellowshipCollective.members')).toJSON();
-    expect(fellowshipMembers).to.contains(newFellowshipMember.address);
-  });
-
-  itSub('>50% Council can promote Fellowship member', async ({helper}) => {
-    const fellowship = await initFellowship(donor, sudoer);
-    const memberWithZeroRank = fellowship[0][0];
-
-    const proposal = helper.fellowship.collective.promoteCall(memberWithZeroRank.address);
-    await proposalFromMoreThanHalfCouncil(proposal);
-    const record = (await helper.callRpc('api.query.fellowshipCollective.members', [memberWithZeroRank.address])).toJSON();
-    expect(record).to.be.deep.equal({rank: 1});
-
-    await clearFellowship(sudoer);
-  });
-
-  itSub('>50% Council can demote Fellowship member', async ({helper}) => {
-    const fellowship = await initFellowship(donor, sudoer);
-    const memberWithRankOne = fellowship[1][0];
-
-    const proposal = helper.fellowship.collective.demoteCall(memberWithRankOne.address);
-    await proposalFromMoreThanHalfCouncil(proposal);
-
-    const record = (await helper.callRpc('api.query.fellowshipCollective.members', [memberWithRankOne.address])).toJSON();
-    expect(record).to.be.deep.equal({rank: 0});
-
-    await clearFellowship(sudoer);
-  });
-
-  itSub('>50% Council can add\remove Fellowship member', async ({helper}) => {
-    try {
-      const newMember = helper.arrange.createEmptyAccount();
-
-      const proposalAdd = helper.fellowship.collective.addMemberCall(newMember.address);
-      const proposalRemove = helper.fellowship.collective.removeMemberCall(newMember.address, fellowshipRankLimit);
-      await expect(proposalFromMoreThanHalfCouncil(proposalAdd)).to.be.fulfilled;
-      expect(await helper.fellowship.collective.getMembers()).to.be.deep.contain(newMember.address);
-      await expect(proposalFromMoreThanHalfCouncil(proposalRemove)).to.be.fulfilled;
-      expect(await helper.fellowship.collective.getMembers()).to.be.not.deep.contain(newMember.address);
-    }
-    finally {
-      await clearFellowship(sudoer);
-    }
-  });
-
-  itSub('Council can blacklist Democracy proposals', async ({helper}) => {
-    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-    await expect(proposalFromAllCouncil(helper.democracy.blacklistCall(preimageHash, null))).to.be.fulfilled;
-  });
-
-  itSub('Sudo can blacklist Democracy proposals', async ({helper}) => {
-    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-    await expect(helper.getSudo().democracy.blacklist(sudoer, preimageHash)).to.be.fulfilled;
-  });
-
-  itSub('[Negative] Council cannot add Council member', async ({helper}) => {
-    const newCouncilMember = helper.arrange.createEmptyAccount();
-    const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
-
-    await expect(proposalFromAllCouncil(addMemberProposal)).to.be.rejected;
-  });
-
-  itSub('[Negative] Council cannot remove Council member', async ({helper}) => {
-    const removeMemberProposal = helper.council.membership.removeMemberCall(counselors.alex.address);
-
-    await expect(proposalFromAllCouncil(removeMemberProposal)).to.be.rejected;
-  });
-
-  itSub('[Negative] Council cannot submit regular democracy proposal', async ({helper}) => {
-    const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
-
-    await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);
-  });
-
-  itSub('[Negative] Council cannot externally propose SimpleMajority', async ({helper}) => {
-    const councilProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
-
-    await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);
-  });
-
-  itSub('[Negative] Council cannot externally propose SuperMajorityApprove', async ({helper}) => {
-    const councilProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
-
-    await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);
-  });
-
-  itSub('[Negative] Council member cannot add/remove a Council member', async ({helper}) => {
-    const newCouncilMember = helper.arrange.createEmptyAccount();
-    await expect(helper.council.collective.execute(
-      counselors.alex,
-      helper.council.membership.addMemberCall(newCouncilMember.address),
-    )).to.be.rejectedWith('BadOrigin');
-    await expect(helper.council.collective.execute(
-      counselors.alex,
-      helper.council.membership.removeMemberCall(counselors.charu.address),
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] Council cannot set/clear Council prime member', async ({helper}) => {
-    const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
-    const proposalForClear = await helper.council.membership.clearPrimeCall();
-
-    await expect(proposalFromAllCouncil(proposalForSet)).to.be.rejectedWith(/BadOrigin/);
-    await expect(proposalFromAllCouncil(proposalForClear)).to.be.rejectedWith(/BadOrigin/);
-
-  });
-
-  itSub('[Negative] Council member cannot set/clear Council prime member', async ({helper}) => {
-    await expect(helper.council.collective.execute(
-      counselors.alex,
-      helper.council.membership.setPrimeCall(counselors.charu.address),
-    )).to.be.rejectedWith('BadOrigin');
-    await expect(helper.council.collective.execute(
-      counselors.alex,
-      helper.council.membership.clearPrimeCall(),
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] Council member cannot add/remove a TechComm member', async ({helper}) => {
-    const newTechCommMember = helper.arrange.createEmptyAccount();
-    await expect(helper.council.collective.execute(
-      counselors.alex,
-      helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address),
-    )).to.be.rejectedWith('BadOrigin');
-    await expect(helper.council.collective.execute(
-      counselors.alex,
-      helper.technicalCommittee.membership.removeMemberCall(newTechCommMember.address),
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] Council member cannot promote/demote a Fellowship member', async ({helper}) => {
-    const fellowship = await initFellowship(donor, sudoer);
-    const memberWithRankOne = fellowship[1][0];
-
-    await expect(helper.council.collective.execute(
-      counselors.alex,
-      helper.fellowship.collective.promoteCall(memberWithRankOne.address),
-    )).to.be.rejectedWith('BadOrigin');
-    await expect(helper.council.collective.execute(
-      counselors.alex,
-      helper.fellowship.collective.demoteCall(memberWithRankOne.address),
-    )).to.be.rejectedWith('BadOrigin');
-    await clearFellowship(sudoer);
-  });
-
-  itSub('[Negative] Council cannot fast-track Democracy proposals', async ({helper}) => {
-    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
-    await expect(proposalFromAllCouncil(helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0)))
-      .to.be.rejectedWith(/BadOrigin/);
-  });
-
-  itSub('[Negative] Council member cannot fast-track Democracy proposals', async ({helper}) => {
-    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
-    await expect(helper.council.collective.execute(
-      counselors.alex,
-      helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0),
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] Council cannot cancel Democracy proposals', async ({helper}) => {
-    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
-    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
-
-    await expect(proposalFromAllCouncil(helper.democracy.cancelProposalCall(proposalIndex)))
-      .to.be.rejectedWith(/BadOrigin/);
-  });
-
-  itSub('[Negative] Council member cannot cancel Democracy proposals', async ({helper}) => {
-
-    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
-    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
-
-    await expect(helper.council.collective.execute(
-      counselors.alex,
-      helper.democracy.cancelProposalCall(proposalIndex),
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] Council cannot cancel ongoing Democracy referendums', async ({helper}) => {
-    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
-    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
-    const referendumIndex = startedEvent.referendumIndex;
-
-    await expect(proposalFromAllCouncil(helper.democracy.emergencyCancelCall(referendumIndex)))
-      .to.be.rejectedWith(/BadOrigin/);
-  });
-
-  itSub('[Negative] Council member cannot cancel ongoing Democracy referendums', async ({helper}) => {
-    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
-    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
-    const referendumIndex = startedEvent.referendumIndex;
-
-    await expect(helper.council.collective.execute(
-      counselors.alex,
-      helper.democracy.emergencyCancelCall(referendumIndex),
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] Council cannot cancel Fellowship referendums', async ({helper}) => {
-    const fellowship = await initFellowship(donor, sudoer);
-    const fellowshipProposer = fellowship[5][0];
-    const proposal = dummyProposal(helper);
-
-    const submitResult = await helper.fellowship.referenda.submit(
-      fellowshipProposer,
-      fellowshipPropositionOrigin,
-      proposal,
-      defaultEnactmentMoment,
-    );
-
-    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-
-    await expect(proposalFromAllCouncil(helper.fellowship.referenda.cancelCall(referendumIndex)))
-      .to.be.rejectedWith(/BadOrigin/);
-  });
-
-  itSub('[Negative] Council member cannot cancel Fellowship referendums', async ({helper}) => {
-    const fellowship = await initFellowship(donor, sudoer);
-    const fellowshipProposer = fellowship[5][0];
-    const proposal = dummyProposal(helper);
-
-    const submitResult = await helper.fellowship.referenda.submit(
-      fellowshipProposer,
-      fellowshipPropositionOrigin,
-      proposal,
-      defaultEnactmentMoment,
-    );
-    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-    await expect(helper.council.collective.execute(
-      counselors.alex,
-      helper.fellowship.referenda.cancelCall(referendumIndex),
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] Council referendum cannot be closed until the voting threshold is met', async ({helper}) => {
-    const councilSize = (await helper.callRpc('api.query.councilMembership.members')).toJSON().length as any as number;
-    expect(councilSize).is.greaterThan(1);
-    const proposeResult = await helper.council.collective.propose(
-      counselors.filip,
-      dummyProposalCall(helper),
-      councilSize,
-    );
-
-    const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
-    const proposalIndex = councilProposedEvent.proposalIndex;
-    const proposalHash = councilProposedEvent.proposalHash;
-
-
-    await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
-    await expect(helper.council.collective.close(counselors.filip, proposalHash, proposalIndex)).to.be.rejectedWith('TooEarly');
-  });
-
-});
deletedjs-packages/tests/governance/democracy.test.tsdiffbeforeafterboth
--- a/js-packages/tests/governance/democracy.test.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
-import {clearFellowship, democracyLaunchPeriod, democracyTrackMinRank, dummyProposalCall, fellowshipConfirmPeriod, fellowshipMinEnactPeriod, fellowshipPreparePeriod, fellowshipPropositionOrigin, initFellowship, voteUnanimouslyInFellowship} from './util.js';
-import {Event} from '@unique/playgrounds/unique.dev.js';
-
-describeGov('Governance: Democracy tests', () => {
-  let regularUser: IKeyringPair;
-  let donor: IKeyringPair;
-  let sudoer: IKeyringPair;
-
-  before(async function() {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      requirePalletsOrSkip(this, helper, [Pallets.Democracy]);
-
-      donor = await privateKey({url: import.meta.url});
-      sudoer = await privateKey('//Alice');
-
-      [regularUser] = await helper.arrange.createAccounts([1000n], donor);
-    });
-  });
-
-  itSub('Regular user can vote', async ({helper}) => {
-    const fellows = await initFellowship(donor, sudoer);
-    const rank1Proposer = fellows[1][0];
-
-    const democracyProposalCall = dummyProposalCall(helper);
-    const fellowshipProposal = {
-      Inline: helper.democracy.proposeCall(democracyProposalCall, 0n).method.toHex(),
-    };
-
-    const submitResult = await helper.fellowship.referenda.submit(
-      rank1Proposer,
-      fellowshipPropositionOrigin,
-      fellowshipProposal,
-      {After: 0},
-    );
-
-    const fellowshipReferendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-    await voteUnanimouslyInFellowship(helper, fellows, democracyTrackMinRank, fellowshipReferendumIndex);
-    await helper.fellowship.referenda.placeDecisionDeposit(donor, fellowshipReferendumIndex);
-
-    await helper.wait.expectEvent(
-      fellowshipPreparePeriod + fellowshipConfirmPeriod + fellowshipMinEnactPeriod,
-      Event.Democracy.Proposed,
-    );
-
-    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
-    const referendumIndex = startedEvent.referendumIndex;
-
-    const ayeBalance = 10_000n;
-
-    await helper.democracy.vote(regularUser, referendumIndex, {
-      Standard: {
-        vote: {
-          aye: true,
-          conviction: 1,
-        },
-        balance: ayeBalance,
-      },
-    });
-
-    const referendumInfo = await helper.democracy.referendumInfo(referendumIndex);
-    const tally = referendumInfo.ongoing.tally;
-
-    expect(BigInt(tally.ayes)).to.be.equal(ayeBalance);
-
-    await clearFellowship(sudoer);
-  });
-
-  itSub('[Negative] Regular user cannot submit a regular proposal', async ({helper}) => {
-    const submitResult = helper.democracy.propose(regularUser, dummyProposalCall(helper), 0n);
-    await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
-  });
-
-  itSub('[Negative] Regular user cannot externally propose SuperMajorityAgainst', async ({helper}) => {
-    const submitResult = helper.democracy.externalProposeDefault(regularUser, dummyProposalCall(helper));
-    await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
-  });
-
-  itSub('[Negative] Regular user cannot externally propose SimpleMajority', async ({helper}) => {
-    const submitResult = helper.democracy.externalProposeMajority(regularUser, dummyProposalCall(helper));
-    await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
-  });
-
-  itSub('[Negative] Regular user cannot externally propose SuperMajorityApprove', async ({helper}) => {
-    const submitResult = helper.democracy.externalPropose(regularUser, dummyProposalCall(helper));
-    await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
-  });
-});
deletedjs-packages/tests/governance/fellowship.test.tsdiffbeforeafterboth
--- a/js-packages/tests/governance/fellowship.test.ts
+++ /dev/null
@@ -1,335 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
-import {DevUniqueHelper, Event} from '@unique/playgrounds/unique.dev.js';
-import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, clearFellowship, defaultEnactmentMoment, dummyProposal, dummyProposalCall, fellowshipPropositionOrigin, initFellowship, initTechComm, voteUnanimouslyInFellowship, democracyTrackMinRank, fellowshipPreparePeriod, fellowshipConfirmPeriod, fellowshipMinEnactPeriod, democracyTrackId, hardResetFellowshipReferenda, hardResetDemocracy, hardResetGovScheduler} from './util.js';
-import type {ICounselors, ITechComms} from './util.js';
-
-describeGov('Governance: Fellowship tests', () => {
-  let members: IKeyringPair[][];
-
-  let rank1Proposer: IKeyringPair;
-
-  let sudoer: any;
-  let donor: any;
-  let counselors: ICounselors;
-  let techcomms: ITechComms;
-
-  const submissionDeposit = 1000n;
-
-  async function testBadFellowshipProposal(
-    helper: DevUniqueHelper,
-    proposalCall: any,
-  ) {
-    const badProposal = {
-      Inline: proposalCall.method.toHex(),
-    };
-    const submitResult = await helper.fellowship.referenda.submit(
-      rank1Proposer,
-      fellowshipPropositionOrigin,
-      badProposal,
-      defaultEnactmentMoment,
-    );
-
-    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-    await voteUnanimouslyInFellowship(helper, members, democracyTrackMinRank, referendumIndex);
-    await helper.fellowship.referenda.placeDecisionDeposit(donor, referendumIndex);
-
-    const enactmentId = await helper.fellowship.referenda.enactmentEventId(referendumIndex);
-    const dispatchedEvent = await helper.wait.expectEvent(
-      fellowshipPreparePeriod + fellowshipConfirmPeriod + defaultEnactmentMoment.After,
-      Event.Scheduler.Dispatched,
-      (event: any) => event.id == enactmentId,
-    );
-
-    expect(dispatchedEvent.result.isErr, 'Bad Fellowship must fail')
-      .to.be.true;
-
-    expect(dispatchedEvent.result.asErr.isBadOrigin, 'Bad Fellowship must fail with BadOrigin')
-      .to.be.true;
-  }
-
-  before(async function() {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      requirePalletsOrSkip(this, helper, [Pallets.Democracy, Pallets.Fellowship, Pallets.TechnicalCommittee, Pallets.Council]);
-
-      sudoer = await privateKey('//Alice');
-      donor = await privateKey({url: import.meta.url});
-    });
-
-    counselors = await initCouncil(donor, sudoer);
-    techcomms = await initTechComm(donor, sudoer);
-    members = await initFellowship(donor, sudoer);
-
-    rank1Proposer = members[1][0];
-  });
-
-  after(async () => {
-    await clearFellowship(sudoer);
-    await clearTechComm(sudoer);
-    await clearCouncil(sudoer);
-    await hardResetFellowshipReferenda(sudoer);
-    await hardResetDemocracy(sudoer);
-    await hardResetGovScheduler(sudoer);
-  });
-
-  itSub('FellowshipProposition can submit regular Democracy proposals', async ({helper}) => {
-    const democracyProposalCall = dummyProposalCall(helper);
-    const fellowshipProposal = {
-      Inline: helper.democracy.proposeCall(democracyProposalCall, 0n).method.toHex(),
-    };
-
-    const submitResult = await helper.fellowship.referenda.submit(
-      rank1Proposer,
-      fellowshipPropositionOrigin,
-      fellowshipProposal,
-      defaultEnactmentMoment,
-    );
-
-    const fellowshipReferendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-    await voteUnanimouslyInFellowship(helper, members, democracyTrackMinRank, fellowshipReferendumIndex);
-    await helper.fellowship.referenda.placeDecisionDeposit(donor, fellowshipReferendumIndex);
-
-    const democracyProposed = await helper.wait.expectEvent(
-      fellowshipPreparePeriod + fellowshipConfirmPeriod + fellowshipMinEnactPeriod,
-      Event.Democracy.Proposed,
-    );
-
-    const democracyEnqueuedProposal = await helper.democracy.expectPublicProposal(democracyProposed.proposalIndex);
-    expect(democracyEnqueuedProposal.inline, 'Fellowship proposal expected to be in the Democracy')
-      .to.be.equal(democracyProposalCall.method.toHex());
-
-    await helper.wait.newBlocks(democracyVotingPeriod);
-  });
-
-  itSub('Fellowship (rank-1 or greater) member can submit Fellowship proposals on the Democracy track', async ({helper}) => {
-    for(let rank = 1; rank < fellowshipRankLimit; rank++) {
-      const rankMembers = members[rank];
-
-      for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {
-        const member = rankMembers[memberIdx];
-        const newDummyProposal = dummyProposal(helper);
-
-        const submitResult = await helper.fellowship.referenda.submit(
-          member,
-          fellowshipPropositionOrigin,
-          newDummyProposal,
-          defaultEnactmentMoment,
-        );
-
-        const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-        const referendumInfo = await helper.fellowship.referenda.referendumInfo(referendumIndex);
-        expect(referendumInfo.ongoing.track, `${memberIdx}-th member of rank #${rank}: proposal #${referendumIndex} is on invalid track`)
-          .to.be.equal(democracyTrackId);
-      }
-    }
-  });
-
-  itSub(`Fellowship (rank-${democracyTrackMinRank} or greater) members can vote on the Democracy track`, async ({helper}) => {
-    const proposal = dummyProposal(helper);
-
-    const submitResult = await helper.fellowship.referenda.submit(
-      rank1Proposer,
-      fellowshipPropositionOrigin,
-      proposal,
-      defaultEnactmentMoment,
-    );
-
-    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-
-    let expectedAyes = 0;
-    for(let rank = democracyTrackMinRank; rank < fellowshipRankLimit; rank++) {
-      const rankMembers = members[rank];
-
-      for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {
-        const member = rankMembers[memberIdx];
-        await helper.fellowship.collective.vote(member, referendumIndex, true);
-        expectedAyes += 1;
-
-        const referendumInfo = await helper.fellowship.referenda.referendumInfo(referendumIndex);
-        expect(referendumInfo.ongoing.tally.bareAyes, `Vote from ${memberIdx}-th member of rank #${rank} isn't accounted`)
-          .to.be.equal(expectedAyes);
-      }
-    }
-  });
-
-  itSub('Fellowship rank vote strength is correct', async ({helper}) => {
-    const excessRankWeightTable = [
-      1,
-      3,
-      6,
-      10,
-      15,
-      21,
-    ];
-
-    const proposal = dummyProposal(helper);
-
-    const submitResult = await helper.fellowship.referenda.submit(
-      rank1Proposer,
-      fellowshipPropositionOrigin,
-      proposal,
-      defaultEnactmentMoment,
-    );
-
-    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-
-    for(let rank = democracyTrackMinRank; rank < fellowshipRankLimit; rank++) {
-      const rankMembers = members[rank];
-
-      for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {
-        const member = rankMembers[memberIdx];
-
-        const referendumInfoBefore = await helper.fellowship.referenda.referendumInfo(referendumIndex);
-        const ayesBefore = referendumInfoBefore.ongoing.tally.ayes;
-
-        await helper.fellowship.collective.vote(member, referendumIndex, true);
-
-        const referendumInfoAfter = await helper.fellowship.referenda.referendumInfo(referendumIndex);
-        const ayesAfter = referendumInfoAfter.ongoing.tally.ayes;
-
-        const expectedVoteWeight = excessRankWeightTable[rank - democracyTrackMinRank];
-        const voteWeight = ayesAfter - ayesBefore;
-
-        expect(voteWeight, `Vote weight of ${memberIdx}-th member of rank #${rank} is invalid`)
-          .to.be.equal(expectedVoteWeight);
-      }
-    }
-  });
-
-  itSub('[Negative] FellowshipProposition cannot externally propose SuperMajorityAgainst', async ({helper}) => {
-    await testBadFellowshipProposal(helper, helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper)));
-  });
-
-  itSub('[Negative] FellowshipProposition cannot externally propose SimpleMajority', async ({helper}) => {
-    await testBadFellowshipProposal(helper, helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper)));
-  });
-
-  itSub('[Negative] FellowshipProposition cannot externally propose SuperMajorityApprove', async ({helper}) => {
-    await testBadFellowshipProposal(helper, helper.democracy.externalProposeCall(dummyProposalCall(helper)));
-  });
-
-  itSub('[Negative] Fellowship (rank-0) member cannot submit Fellowship proposals on the Democracy track', async ({helper}) => {
-    const rank0Proposer = members[0][0];
-
-    const proposal = dummyProposal(helper);
-
-    const submitResult = helper.fellowship.referenda.submit(
-      rank0Proposer,
-      fellowshipPropositionOrigin,
-      proposal,
-      defaultEnactmentMoment,
-    );
-
-    await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
-  });
-
-  itSub('[Negative] Fellowship (rank-1 or greater) member cannot submit if no deposit can be provided', async ({helper}) => {
-    const poorMember = rank1Proposer;
-
-    const balanceBefore = await helper.balance.getSubstrate(poorMember.address);
-    await helper.getSudo().balance.setBalanceSubstrate(sudoer, poorMember.address, submissionDeposit - 1n);
-
-    const proposal = dummyProposal(helper);
-
-    const submitResult = helper.fellowship.referenda.submit(
-      poorMember,
-      fellowshipPropositionOrigin,
-      proposal,
-      defaultEnactmentMoment,
-    );
-
-    await expect(submitResult).to.be.rejectedWith(/account balance too low/);
-
-    await helper.getSudo().balance.setBalanceSubstrate(sudoer, poorMember.address, balanceBefore);
-  });
-
-  itSub(`[Negative] Fellowship (rank-${democracyTrackMinRank - 1} or less) members cannot vote on the Democracy track`, async ({helper}) => {
-    const proposal = dummyProposal(helper);
-
-    const submitResult = await helper.fellowship.referenda.submit(
-      rank1Proposer,
-      fellowshipPropositionOrigin,
-      proposal,
-      defaultEnactmentMoment,
-    );
-
-    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-
-    for(let rank = 0; rank < democracyTrackMinRank; rank++) {
-      for(const member of members[rank]) {
-        const voteResult = helper.fellowship.collective.vote(member, referendumIndex, true);
-        await expect(voteResult).to.be.rejectedWith(/RankTooLow/);
-      }
-    }
-  });
-
-  itSub('[Negative] FellowshipProposition cannot add/remove a Council member', async ({helper}) => {
-    const [councilNonMember] = await helper.arrange.createAccounts([10n], donor);
-
-    await testBadFellowshipProposal(helper, helper.council.membership.addMemberCall(councilNonMember.address));
-    await testBadFellowshipProposal(helper, helper.council.membership.removeMemberCall(counselors.ildar.address));
-  });
-
-  itSub('[Negative] FellowshipProposition cannot set/clear Council prime member', async ({helper}) => {
-    await testBadFellowshipProposal(helper, helper.council.membership.setPrimeCall(counselors.ildar.address));
-    await testBadFellowshipProposal(helper, helper.council.membership.clearPrimeCall());
-  });
-
-  itSub('[Negative] FellowshipProposition cannot add/remove a TechComm member', async ({helper}) => {
-    const [techCommNonMember] = await helper.arrange.createAccounts([10n], donor);
-
-    await testBadFellowshipProposal(helper, helper.technicalCommittee.membership.addMemberCall(techCommNonMember.address));
-    await testBadFellowshipProposal(helper, helper.technicalCommittee.membership.removeMemberCall(techcomms.constantine.address));
-  });
-
-  itSub('[Negative] FellowshipProposition cannot add/remove a Fellowship member', async ({helper}) => {
-    const [fellowshipNonMember] = await helper.arrange.createAccounts([10n], donor);
-
-    await testBadFellowshipProposal(helper, helper.fellowship.collective.addMemberCall(fellowshipNonMember.address));
-    await testBadFellowshipProposal(helper, helper.fellowship.collective.removeMemberCall(rank1Proposer.address, 1));
-  });
-
-  itSub('[Negative] FellowshipProposition cannot promote/demote a Fellowship member', async ({helper}) => {
-    await testBadFellowshipProposal(helper, helper.fellowship.collective.promoteCall(rank1Proposer.address));
-    await testBadFellowshipProposal(helper, helper.fellowship.collective.demoteCall(rank1Proposer.address));
-  });
-
-  itSub('[Negative] FellowshipProposition cannot fast-track Democracy proposals', async ({helper}) => {
-    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-
-    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
-    await testBadFellowshipProposal(helper, helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0));
-  });
-
-  itSub('[Negative] FellowshipProposition cannot cancel Democracy proposals', async ({helper}) => {
-    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
-    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
-
-    await testBadFellowshipProposal(helper, helper.democracy.cancelProposalCall(proposalIndex));
-  });
-
-  itSub('[Negative] FellowshipProposition cannot cancel ongoing Democracy referendums', async ({helper}) => {
-    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
-    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
-    const referendumIndex = startedEvent.referendumIndex;
-
-    await testBadFellowshipProposal(helper, helper.democracy.emergencyCancelCall(referendumIndex));
-  });
-
-  itSub('[Negative] FellowshipProposition cannot blacklist Democracy proposals', async ({helper}) => {
-    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-
-    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
-    await testBadFellowshipProposal(helper, helper.democracy.blacklistCall(preimageHash, null));
-  });
-
-  itSub('[Negative] FellowshipProposition cannot veto external proposals', async ({helper}) => {
-    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-
-    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
-    await testBadFellowshipProposal(helper, helper.democracy.vetoExternalCall(preimageHash));
-  });
-});
deletedjs-packages/tests/governance/init.test.tsdiffbeforeafterboth
--- a/js-packages/tests/governance/init.test.ts
+++ /dev/null
@@ -1,193 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
-import {Event} from '@unique/playgrounds/unique.dev.js';
-import {democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, clearCouncil, clearTechComm, clearFellowship} from './util.js';
-import type {ICounselors, ITechComms} from './util.js';
-
-describeGov('Governance: Initialization', () => {
-  let donor: IKeyringPair;
-  let sudoer: IKeyringPair;
-  let counselors: ICounselors;
-  let techcomms: ITechComms;
-  let coreDevs: any;
-
-  const expectedAlexFellowRank = 7;
-  const expectedFellowRank = 6;
-
-  before(async function() {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      requirePalletsOrSkip(this, helper, [Pallets.Democracy, Pallets.Council, Pallets.TechnicalCommittee]);
-
-      const councilMembers = await helper.council.membership.getMembers();
-      const techcommMembers = await helper.technicalCommittee.membership.getMembers();
-      expect(councilMembers.length == 0, 'The Council must be empty before the Gov Init');
-      expect(techcommMembers.length == 0, 'The Technical Commettee must be empty before the Gov Init');
-
-      donor = await privateKey({url: import.meta.url});
-      sudoer = await privateKey('//Alice');
-
-      const counselorsNum = 5;
-      const techCommsNum = 3;
-      const coreDevsNum = 2;
-      const [
-        alex,
-        ildar,
-        charu,
-        filip,
-        irina,
-
-        greg,
-        andy,
-        constantine,
-
-        yaroslav,
-        daniel,
-      ] = await helper.arrange.createAccounts(new Array(counselorsNum + techCommsNum + coreDevsNum).fill(10_000n), donor);
-
-      counselors = {
-        alex,
-        ildar,
-        charu,
-        filip,
-        irina,
-      };
-
-      techcomms = {
-        greg,
-        andy,
-        constantine,
-      };
-
-      coreDevs = {
-        yaroslav: yaroslav,
-        daniel: daniel,
-      };
-    });
-  });
-
-  itSub('Initialize Governance', async ({helper}) => {
-    const promoteFellow = (fellow: string, promotionsNum: number) => new Array(promotionsNum).fill(helper.fellowship.collective.promoteCall(fellow));
-
-    const expectFellowRank = async (fellow: string, expectedRank: number) => {
-      expect(await helper.fellowship.collective.getMemberRank(fellow)).to.be.equal(expectedRank);
-    };
-
-    console.log('\t- Setup the Prime of the Council via sudo');
-    await helper.getSudo().utility.batchAll(sudoer, [
-      helper.council.membership.addMemberCall(counselors.alex.address),
-      helper.council.membership.setPrimeCall(counselors.alex.address),
-
-      helper.fellowship.collective.addMemberCall(counselors.alex.address),
-      ...promoteFellow(counselors.alex.address, expectedAlexFellowRank),
-    ]);
-
-    let councilMembers = await helper.council.membership.getMembers();
-    const councilPrime = await helper.council.collective.getPrimeMember();
-    const alexFellowRank = await helper.fellowship.collective.getMemberRank(counselors.alex.address);
-    expect(councilMembers).to.be.deep.equal([counselors.alex.address]);
-    expect(councilPrime).to.be.equal(counselors.alex.address);
-    expect(alexFellowRank).to.be.equal(expectedAlexFellowRank);
-
-    console.log('\t- The Council Prime initializes the Technical Commettee');
-    const councilProposalThreshold = 1;
-
-    await helper.council.collective.propose(
-      counselors.alex,
-      helper.utility.batchAllCall([
-        helper.technicalCommittee.membership.addMemberCall(techcomms.greg.address),
-        helper.technicalCommittee.membership.addMemberCall(techcomms.andy.address),
-        helper.technicalCommittee.membership.addMemberCall(techcomms.constantine.address),
-
-        helper.technicalCommittee.membership.setPrimeCall(techcomms.greg.address),
-      ]),
-      councilProposalThreshold,
-    );
-
-    const techCommMembers = await helper.technicalCommittee.membership.getMembers();
-    const techCommPrime = await helper.technicalCommittee.membership.getPrimeMember();
-    const expectedTechComms = [techcomms.greg.address, techcomms.andy.address, techcomms.constantine.address];
-    expect(techCommMembers.length).to.be.equal(expectedTechComms.length);
-    expect(techCommMembers).to.containSubset(expectedTechComms);
-    expect(techCommPrime).to.be.equal(techcomms.greg.address);
-
-    console.log('\t- The Council Prime initiates a referendum to add counselors');
-    const returnPreimageHash = true;
-    const preimageHash = await helper.preimage.notePreimageFromCall(counselors.alex, helper.utility.batchAllCall([
-      helper.council.membership.addMemberCall(counselors.ildar.address),
-      helper.council.membership.addMemberCall(counselors.charu.address),
-      helper.council.membership.addMemberCall(counselors.filip.address),
-      helper.council.membership.addMemberCall(counselors.irina.address),
-
-      helper.fellowship.collective.addMemberCall(counselors.charu.address),
-      helper.fellowship.collective.addMemberCall(counselors.ildar.address),
-      helper.fellowship.collective.addMemberCall(counselors.irina.address),
-      helper.fellowship.collective.addMemberCall(counselors.filip.address),
-      helper.fellowship.collective.addMemberCall(techcomms.greg.address),
-      helper.fellowship.collective.addMemberCall(techcomms.andy.address),
-      helper.fellowship.collective.addMemberCall(techcomms.constantine.address),
-      helper.fellowship.collective.addMemberCall(coreDevs.yaroslav.address),
-      helper.fellowship.collective.addMemberCall(coreDevs.daniel.address),
-
-      ...promoteFellow(counselors.charu.address, expectedFellowRank),
-      ...promoteFellow(counselors.ildar.address, expectedFellowRank),
-      ...promoteFellow(counselors.irina.address, expectedFellowRank),
-      ...promoteFellow(counselors.filip.address, expectedFellowRank),
-      ...promoteFellow(techcomms.greg.address, expectedFellowRank),
-      ...promoteFellow(techcomms.andy.address, expectedFellowRank),
-      ...promoteFellow(techcomms.constantine.address, expectedFellowRank),
-      ...promoteFellow(coreDevs.yaroslav.address, expectedFellowRank),
-      ...promoteFellow(coreDevs.daniel.address, expectedFellowRank),
-    ]), returnPreimageHash);
-
-    await helper.council.collective.propose(
-      counselors.alex,
-      helper.democracy.externalProposeDefaultWithPreimageCall(preimageHash),
-      councilProposalThreshold,
-    );
-
-    console.log('\t- The referendum is being decided');
-    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
-
-    await helper.democracy.vote(counselors.filip, startedEvent.referendumIndex, {
-      Standard: {
-        vote: {
-          aye: true,
-          conviction: 1,
-        },
-        balance: 10_000n,
-      },
-    });
-
-    const passedReferendumEvent = await helper.wait.expectEvent(democracyVotingPeriod, Event.Democracy.Passed);
-    expect(passedReferendumEvent.referendumIndex).to.be.equal(startedEvent.referendumIndex);
-
-    await helper.wait.expectEvent(democracyEnactmentPeriod, Event.Scheduler.Dispatched);
-
-    councilMembers = await helper.council.membership.getMembers();
-    const expectedCounselors = [
-      counselors.alex.address,
-      counselors.ildar.address,
-      counselors.charu.address,
-      counselors.filip.address,
-      counselors.irina.address,
-    ];
-    expect(councilMembers.length).to.be.equal(expectedCounselors.length);
-    expect(councilMembers).to.containSubset(expectedCounselors);
-
-    await expectFellowRank(counselors.ildar.address, expectedFellowRank);
-    await expectFellowRank(counselors.charu.address, expectedFellowRank);
-    await expectFellowRank(counselors.filip.address, expectedFellowRank);
-    await expectFellowRank(counselors.irina.address, expectedFellowRank);
-    await expectFellowRank(techcomms.greg.address, expectedFellowRank);
-    await expectFellowRank(techcomms.andy.address, expectedFellowRank);
-    await expectFellowRank(techcomms.constantine.address, expectedFellowRank);
-    await expectFellowRank(coreDevs.yaroslav.address, expectedFellowRank);
-    await expectFellowRank(coreDevs.daniel.address, expectedFellowRank);
-  });
-
-  after(async function() {
-    await clearFellowship(sudoer);
-    await clearTechComm(sudoer);
-    await clearCouncil(sudoer);
-  });
-});
deletedjs-packages/tests/governance/technicalCommittee.test.tsdiffbeforeafterboth
--- a/js-packages/tests/governance/technicalCommittee.test.ts
+++ /dev/null
@@ -1,383 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../util/index.js';
-import {Event} from '@unique/playgrounds/unique.dev.js';
-import {initCouncil, democracyLaunchPeriod, democracyFastTrackVotingPeriod, clearCouncil, clearTechComm, clearFellowship, defaultEnactmentMoment, dummyProposal, dummyProposalCall, fellowshipPropositionOrigin, initFellowship, initTechComm, hardResetFellowshipReferenda, hardResetDemocracy, hardResetGovScheduler} from './util.js';
-import type {ITechComms} from './util.js';
-
-describeGov('Governance: Technical Committee tests', () => {
-  let sudoer: IKeyringPair;
-  let techcomms: ITechComms;
-  let donor: IKeyringPair;
-  let preImageHash: string;
-
-
-  const allTechCommitteeThreshold = 3;
-
-  before(async function() {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      requirePalletsOrSkip(this, helper, [Pallets.TechnicalCommittee]);
-      sudoer = await privateKey('//Alice');
-      donor = await privateKey({url: import.meta.url});
-
-      techcomms = await initTechComm(donor, sudoer);
-
-      const proposalCall = await helper.constructApiCall('api.tx.balances.forceSetBalance', [donor.address, 20n * 10n ** 25n]);
-      preImageHash = await helper.preimage.notePreimageFromCall(sudoer, proposalCall, true);
-    });
-  });
-
-  after(async () => {
-    await usingPlaygrounds(async (helper) => {
-      await clearTechComm(sudoer);
-
-      await helper.preimage.unnotePreimage(sudoer, preImageHash);
-      await hardResetFellowshipReferenda(sudoer);
-      await hardResetDemocracy(sudoer);
-      await hardResetGovScheduler(sudoer);
-    });
-  });
-
-  function proposalFromAllCommittee(proposal: any) {
-    return usingPlaygrounds(async (helper) => {
-      expect((await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON().length).to.be.equal(allTechCommitteeThreshold);
-      const proposeResult = await helper.technicalCommittee.collective.propose(
-        techcomms.andy,
-        proposal,
-        allTechCommitteeThreshold,
-      );
-
-      const commiteeProposedEvent = Event.TechnicalCommittee.Proposed.expect(proposeResult);
-      const proposalIndex = commiteeProposedEvent.proposalIndex;
-      const proposalHash = commiteeProposedEvent.proposalHash;
-
-
-      await helper.technicalCommittee.collective.vote(techcomms.andy, proposalHash, proposalIndex, true);
-      await helper.technicalCommittee.collective.vote(techcomms.constantine, proposalHash, proposalIndex, true);
-      await helper.technicalCommittee.collective.vote(techcomms.greg, proposalHash, proposalIndex, true);
-
-      const closeResult = await helper.technicalCommittee.collective.close(techcomms.andy, proposalHash, proposalIndex);
-      Event.TechnicalCommittee.Closed.expect(closeResult);
-      Event.TechnicalCommittee.Approved.expect(closeResult);
-      const {result} = Event.TechnicalCommittee.Executed.expect(closeResult);
-      expect(result).to.eq('Ok');
-
-      return closeResult;
-    });
-  }
-
-  itSub('TechComm can fast-track Democracy proposals', async ({helper}) => {
-    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-    await helper.wait.parachainBlockMultiplesOf(35n);
-
-    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
-    const fastTrackProposal = await proposalFromAllCommittee(helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0));
-    Event.Democracy.Started.expect(fastTrackProposal);
-  });
-
-  itSub('TechComm can cancel Democracy proposals', async ({helper}) => {
-    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
-    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
-
-    const cancelProposal = await proposalFromAllCommittee(helper.democracy.cancelProposalCall(proposalIndex));
-    Event.Democracy.ProposalCanceled.expect(cancelProposal);
-  });
-
-  itSub('TechComm can cancel ongoing Democracy referendums', async ({helper}) => {
-    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
-    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
-    const referendumIndex = startedEvent.referendumIndex;
-
-    const emergencyCancelProposal = await proposalFromAllCommittee(helper.democracy.emergencyCancelCall(referendumIndex));
-    Event.Democracy.Cancelled.expect(emergencyCancelProposal);
-  });
-
-  itSub('TechComm member can veto Democracy proposals', async ({helper}) => {
-    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
-    const vetoExternalCall = await helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      helper.democracy.vetoExternalCall(preimageHash),
-    );
-    Event.Democracy.Vetoed.expect(vetoExternalCall);
-  });
-
-  itSub('TechComm can cancel Fellowship referendums', async ({helper}) => {
-    const fellowship = await initFellowship(donor, sudoer);
-    const fellowshipProposer = fellowship[5][0];
-    const proposal = dummyProposal(helper);
-
-    const submitResult = await helper.fellowship.referenda.submit(
-      fellowshipProposer,
-      fellowshipPropositionOrigin,
-      proposal,
-      defaultEnactmentMoment,
-    );
-    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-    const cancelProposal = await proposalFromAllCommittee(helper.fellowship.referenda.cancelCall(referendumIndex));
-    Event.FellowshipReferenda.Cancelled.expect(cancelProposal);
-  });
-
-  itSub.skip('TechComm member can add a Fellowship member', async ({helper}) => {
-    const newFellowshipMember = helper.arrange.createEmptyAccount();
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      helper.fellowship.collective.addMemberCall(newFellowshipMember.address),
-    )).to.be.fulfilled;
-    const fellowshipMembers = (await helper.callRpc('api.query.fellowshipCollective.members')).toJSON();
-    expect(fellowshipMembers).to.contains(newFellowshipMember.address);
-    await clearFellowship(sudoer);
-  });
-
-  itSub('[Negative] TechComm cannot submit regular democracy proposal', async ({helper}) => {
-    const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
-
-    await expect(proposalFromAllCommittee(councilProposal)).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm cannot externally propose SuperMajorityAgainst', async ({helper}) => {
-    const commiteeProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));
-
-    await expect(proposalFromAllCommittee(commiteeProposal)).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm cannot externally propose SimpleMajority', async ({helper}) => {
-    const commiteeProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
-
-    await expect(proposalFromAllCommittee(commiteeProposal)).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm cannot externally propose SuperMajorityApprove', async ({helper}) => {
-    const commiteeProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
-
-    await expect(proposalFromAllCommittee(commiteeProposal)).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm member cannot submit regular democracy proposal', async ({helper}) => {
-    const memberProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
-
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      memberProposal,
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm member cannot externally propose SuperMajorityAgainst', async ({helper}) => {
-    const memberProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));
-
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      memberProposal,
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm member cannot externally propose SimpleMajority', async ({helper}) => {
-    const memberProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
-
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      memberProposal,
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm member cannot externally propose SuperMajorityApprove', async ({helper}) => {
-    const memberProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
-
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      memberProposal,
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-
-  itSub.skip('[Negative] TechComm cannot promote/demote Fellowship member', async () => {
-
-  });
-
-  itSub.skip('[Negative] TechComm member cannot promote/demote Fellowship member', async () => {
-
-  });
-
-  itSub('[Negative] TechComm cannot add/remove a Council member', async ({helper}) => {
-    const newCouncilMember = helper.arrange.createEmptyAccount();
-    const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
-    const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);
-
-    await expect(proposalFromAllCommittee(addMemberProposal)).to.be.rejectedWith('BadOrigin');
-    await expect(proposalFromAllCommittee(removeMemberProposal)).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm member cannot add/remove a Council member', async ({helper}) => {
-    const newCouncilMember = helper.arrange.createEmptyAccount();
-    const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
-    const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);
-
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      addMemberProposal,
-    )).to.be.rejectedWith('BadOrigin');
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      removeMemberProposal,
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm cannot set/clear Council prime member', async ({helper}) => {
-    const counselors = await initCouncil(donor, sudoer);
-    const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
-    const proposalForClear = await helper.council.membership.clearPrimeCall();
-
-    await expect(proposalFromAllCommittee(proposalForSet)).to.be.rejectedWith('BadOrigin');
-    await expect(proposalFromAllCommittee(proposalForClear)).to.be.rejectedWith('BadOrigin');
-    await clearCouncil(sudoer);
-  });
-
-  itSub('[Negative] TechComm member cannot set/clear Council prime member', async ({helper}) => {
-    const counselors = await initCouncil(donor, sudoer);
-    const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
-    const proposalForClear = await helper.council.membership.clearPrimeCall();
-
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      proposalForSet,
-    )).to.be.rejectedWith('BadOrigin');
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      proposalForClear,
-    )).to.be.rejectedWith('BadOrigin');
-    await clearCouncil(sudoer);
-  });
-
-  itSub('[Negative] TechComm cannot add/remove a TechComm member', async ({helper}) => {
-    const newCommMember = helper.arrange.createEmptyAccount();
-    const addMemberProposal = helper.council.membership.addMemberCall(newCommMember.address);
-    const removeMemberProposal = helper.council.membership.removeMemberCall(newCommMember.address);
-
-    await expect(proposalFromAllCommittee(addMemberProposal)).to.be.rejectedWith('BadOrigin');
-    await expect(proposalFromAllCommittee(removeMemberProposal)).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm member cannot add/remove a TechComm member', async ({helper}) => {
-    const newCommMember = helper.arrange.createEmptyAccount();
-    const addMemberProposal = helper.council.membership.addMemberCall(newCommMember.address);
-    const removeMemberProposal = helper.council.membership.removeMemberCall(newCommMember.address);
-
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      addMemberProposal,
-    )).to.be.rejectedWith('BadOrigin');
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      removeMemberProposal,
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm cannot remove a Fellowship member', async ({helper}) => {
-    const fellowship = await initFellowship(donor, sudoer);
-
-    await expect(proposalFromAllCommittee(helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5))).to.be.rejectedWith('BadOrigin');
-    await clearFellowship(sudoer);
-  });
-
-  itSub('[Negative] TechComm member cannot remove a Fellowship member', async ({helper}) => {
-    const fellowship = await initFellowship(donor, sudoer);
-
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5),
-    )).to.be.rejectedWith('BadOrigin');
-    await clearFellowship(sudoer);
-  });
-
-  itSub('[Negative] TechComm member cannot fast-track Democracy proposals', async ({helper}) => {
-    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0),
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm member cannot cancel Democracy proposals', async ({helper}) => {
-    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
-    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
-
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      helper.democracy.cancelProposalCall(proposalIndex),
-    ))
-      .to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm member cannot cancel ongoing Democracy referendums', async ({helper}) => {
-    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
-    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
-    const referendumIndex = startedEvent.referendumIndex;
-
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      helper.democracy.emergencyCancelCall(referendumIndex),
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm cannot blacklist Democracy proposals', async ({helper}) => {
-    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
-    await expect(proposalFromAllCommittee(helper.democracy.blacklistCall(preimageHash))).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm member cannot blacklist Democracy proposals', async ({helper}) => {
-    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
-    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
-
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      helper.democracy.blacklistCall(preimageHash),
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub.skip('[Negative] TechComm member cannot veto external Democracy proposals until the cool-off period pass', async () => {
-
-  });
-
-  itSub('[Negative] TechComm member cannot cancel Fellowship referendums', async ({helper}) => {
-    const fellowship = await initFellowship(donor, sudoer);
-    const fellowshipProposer = fellowship[5][0];
-    const proposal = dummyProposal(helper);
-
-    const submitResult = await helper.fellowship.referenda.submit(
-      fellowshipProposer,
-      fellowshipPropositionOrigin,
-      proposal,
-      defaultEnactmentMoment,
-    );
-
-    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
-
-    await expect(helper.technicalCommittee.collective.execute(
-      techcomms.andy,
-      helper.fellowship.referenda.cancelCall(referendumIndex),
-    )).to.be.rejectedWith('BadOrigin');
-  });
-
-  itSub('[Negative] TechComm referendum cannot be closed until the voting threshold is met', async ({helper}) => {
-    const committeeSize = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON().length as any as number;
-    expect(committeeSize).is.greaterThan(1);
-    const proposeResult = await helper.technicalCommittee.collective.propose(
-      techcomms.andy,
-      dummyProposalCall(helper),
-      committeeSize,
-    );
-
-    const committeeProposedEvent = Event.TechnicalCommittee.Proposed.expect(proposeResult);
-    const proposalIndex = committeeProposedEvent.proposalIndex;
-    const proposalHash = committeeProposedEvent.proposalHash;
-
-    await helper.technicalCommittee.collective.vote(techcomms.constantine, proposalHash, proposalIndex, true);
-
-    await expect(helper.technicalCommittee.collective.close(techcomms.andy, proposalHash, proposalIndex)).to.be.rejectedWith('TooEarly');
-  });
-});
deletedjs-packages/tests/governance/util.tsdiffbeforeafterboth
--- a/js-packages/tests/governance/util.ts
+++ /dev/null
@@ -1,224 +0,0 @@
-import type {IKeyringPair} from '@polkadot/types/types';
-import {xxhashAsHex} from '@polkadot/util-crypto';
-import type {u32} from '@polkadot/types-codec';
-import {usingPlaygrounds, expect} from '../util/index.js';
-import {UniqueHelper} from '@unique/playgrounds/unique.js';
-import {DevUniqueHelper} from '@unique/playgrounds/unique.dev.js';
-
-export const democracyLaunchPeriod = 35;
-export const democracyVotingPeriod = 35;
-export const councilMotionDuration = 35;
-export const democracyEnactmentPeriod = 40;
-export const democracyFastTrackVotingPeriod = 5;
-
-export const fellowshipRankLimit = 7;
-export const fellowshipPropositionOrigin = 'FellowshipProposition';
-export const fellowshipPreparePeriod = 3;
-export const fellowshipConfirmPeriod = 3;
-export const fellowshipMinEnactPeriod = 1;
-
-export const defaultEnactmentMoment = {After: 0};
-
-export const democracyTrackId = 10;
-export const democracyTrackMinRank = 3;
-const twox128 = (data: any) => xxhashAsHex(data, 128);
-export interface ICounselors {
-  alex: IKeyringPair;
-  ildar: IKeyringPair;
-  charu: IKeyringPair;
-  filip: IKeyringPair;
-  irina: IKeyringPair;
-}
-export interface ITechComms {
-    greg: IKeyringPair;
-    andy: IKeyringPair;
-    constantine: IKeyringPair;
-}
-
-export async function initCouncil(donor: IKeyringPair, superuser: IKeyringPair) {
-  let counselors: IKeyringPair[] = [];
-
-  await usingPlaygrounds(async (helper) => {
-    const [alex, ildar, charu, filip, irina] = await helper.arrange.createAccounts([10_000n, 10_000n, 10_000n, 10_000n, 10_000n], donor);
-    const sudo = helper.getSudo();
-    {
-      const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON() as [];
-      if(members.length != 0) {
-        await clearCouncil(superuser);
-      }
-    }
-    const expectedMembers = [alex, ildar, charu, filip, irina];
-    for(const member of expectedMembers) {
-      await sudo.executeExtrinsic(superuser, 'api.tx.councilMembership.addMember', [member.address]);
-    }
-    await sudo.executeExtrinsic(superuser, 'api.tx.councilMembership.setPrime', [alex.address]);
-    {
-      const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
-      expect(members).to.containSubset(expectedMembers.map((x: IKeyringPair) => x.address));
-      expect(members.length).to.be.equal(expectedMembers.length);
-    }
-
-    counselors = [alex, ildar, charu, filip, irina];
-  });
-  return {
-    alex: counselors[0],
-    ildar: counselors[1],
-    charu: counselors[2],
-    filip: counselors[3],
-    irina: counselors[4],
-  };
-}
-
-export async function clearCouncil(superuser: IKeyringPair) {
-  await usingPlaygrounds(async (helper) => {
-    let members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
-    if(members.length) {
-      const sudo = helper.getSudo();
-      for(const address of members) {
-        await sudo.executeExtrinsic(superuser, 'api.tx.councilMembership.removeMember', [address]);
-      }
-      members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
-    }
-    expect(members).to.be.deep.equal([]);
-  });
-}
-
-
-export async function initTechComm(donor: IKeyringPair, superuser: IKeyringPair) {
-  let techcomms: IKeyringPair[] = [];
-
-  await usingPlaygrounds(async (helper) => {
-    const [greg, andy, constantine] = await helper.arrange.createAccounts([10_000n, 10_000n, 10_000n], donor);
-    const sudo = helper.getSudo();
-    {
-      const members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON() as [];
-      if(members.length != 0) {
-        await clearTechComm(superuser);
-      }
-    }
-    await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.addMember', [greg.address]);
-    await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.addMember', [andy.address]);
-    await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.addMember', [constantine.address]);
-    await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.setPrime', [greg.address]);
-    {
-      const members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
-      expect(members).to.containSubset([greg.address, andy.address, constantine.address]);
-      expect(members.length).to.be.equal(3);
-    }
-
-    techcomms = [greg, andy, constantine];
-  });
-
-  return {
-    greg: techcomms[0],
-    andy: techcomms[1],
-    constantine: techcomms[2],
-  };
-}
-
-export async function clearTechComm(superuser: IKeyringPair) {
-  await usingPlaygrounds(async (helper) => {
-    let members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
-    if(members.length) {
-      const sudo = helper.getSudo();
-      for(const address of members) {
-        await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.removeMember', [address]);
-      }
-      members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
-    }
-    expect(members).to.be.deep.equal([]);
-  });
-}
-
-export async function initFellowship(donor: IKeyringPair, sudoer: IKeyringPair) {
-  const numMembersInRank = 3;
-  const memberBalance = 5000n;
-  const members: IKeyringPair[][] = [];
-
-  await usingPlaygrounds(async (helper) => {
-    const currentFellows = await helper.getApi().query.fellowshipCollective.members.keys();
-
-    if(currentFellows.length != 0) {
-      await clearFellowship(sudoer);
-    }
-    for(let i = 0; i < fellowshipRankLimit; i++) {
-      const rankMembers = await helper.arrange.createAccounts(
-        Array(numMembersInRank).fill(memberBalance),
-        donor,
-      );
-
-      for(const member of rankMembers) {
-        await helper.getSudo().fellowship.collective.addMember(sudoer, member.address);
-
-        for(let rank = 0; rank < i; rank++) {
-          await helper.getSudo().fellowship.collective.promote(sudoer, member.address);
-        }
-      }
-
-      members.push(rankMembers);
-    }
-  });
-
-  return members;
-}
-
-export async function clearFellowship(sudoer: IKeyringPair) {
-  await usingPlaygrounds(async (helper) => {
-    const fellowship = (await helper.getApi().query.fellowshipCollective.members.keys())
-      .map((key) => key.args[0].toString());
-    for(const  member of fellowship) {
-      await helper.getSudo().fellowship.collective.removeMember(sudoer, member, fellowshipRankLimit);
-    }
-  });
-}
-
-export async function clearFellowshipReferenda(sudoer: IKeyringPair) {
-  await usingPlaygrounds(async (helper) => {
-    const proposalsCount = (await helper.getApi().query.fellowshipReferenda.referendumCount()) as u32;
-    for(let i = 0; i < proposalsCount.toNumber(); i++) {
-      await helper.getSudo().fellowship.referenda.cancel(sudoer, i);
-    }
-  });
-}
-
-export async function hardResetFellowshipReferenda(sudoer: IKeyringPair) {
-  await usingPlaygrounds(async (helper) => {
-    const api = helper.getApi();
-    const prefix = twox128('FellowshipReferenda');
-    await helper.signTransaction(sudoer, api.tx.sudo.sudo(api.tx.system.killPrefix(prefix, 100)));
-  });
-}
-
-export async function hardResetDemocracy(sudoer: IKeyringPair) {
-  await usingPlaygrounds(async (helper) => {
-    const api = helper.getApi();
-    const prefix = twox128('Democracy');
-    await helper.signTransaction(sudoer, api.tx.sudo.sudo(api.tx.system.killPrefix(prefix, 100)));
-  });
-}
-
-export async function hardResetGovScheduler(sudoer: IKeyringPair) {
-  await usingPlaygrounds(async (helper) => {
-    const api = helper.getApi();
-    const prefix = twox128('GovScheduler');
-    await helper.signTransaction(sudoer, api.tx.sudo.sudo(api.tx.system.killPrefix(prefix, 500)));
-  });
-}
-
-export async function voteUnanimouslyInFellowship(helper: DevUniqueHelper, fellows: IKeyringPair[][], minRank: number, referendumIndex: number) {
-  for(let rank = minRank; rank < fellowshipRankLimit; rank++) {
-    for(const member of fellows[rank]) {
-      await helper.fellowship.collective.vote(member, referendumIndex, true);
-    }
-  }
-}
-
-export function dummyProposalCall(helper: UniqueHelper) {
-  return helper.constructApiCall('api.tx.system.remark', ['dummy proposal' + (new Date()).getTime()]);
-}
-
-export function dummyProposal(helper: UniqueHelper) {
-  return {
-    Inline: dummyProposalCall(helper).method.toHex(),
-  };
-}
deletedjs-packages/tests/nesting/collectionProperties.seqtest.tsdiffbeforeafterboth
--- a/js-packages/tests/nesting/collectionProperties.seqtest.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip, sizeOfProperty} from '../util/index.js';
-
-describe('Integration Test: Collection Properties with sudo', () => {
-  let superuser: IKeyringPair;
-  let alice: IKeyringPair;
-
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      superuser = await privateKey('//Alice');
-      const donor = await privateKey({url: import.meta.url});
-      [alice] = await helper.arrange.createAccounts([100n], donor);
-    });
-  });
-
-  [
-    {mode: 'nft' as const, requiredPallets: []},
-    {mode: 'ft' as const, requiredPallets: []},
-    {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
-  ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
-    before(async function() {
-      // eslint-disable-next-line require-await
-      await usingPlaygrounds(async helper => {
-        requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
-      });
-    });
-
-    itSub('Repairing an unbroken collection\'s properties preserves the consumed space', async({helper}) => {
-      const properties = [
-        {key: 'sea-creatures', value: 'mermaids'},
-        {key: 'goldenratio', value: '1.6180339887498948482045868343656381177203091798057628621354486227052604628189'},
-      ];
-      const collection = await helper[testSuite.mode].mintCollection(alice, {properties});
-
-      const newProperty = {key: 'space', value: ' '.repeat(4096)};
-      await collection.setProperties(alice, [newProperty]);
-      const originalSpace = await collection.getPropertiesConsumedSpace();
-      expect(originalSpace).to.be.equal(sizeOfProperty(properties[0]) + sizeOfProperty(properties[1]) + sizeOfProperty(newProperty));
-
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.unique.forceRepairCollection', [collection.collectionId], true);
-      const recomputedSpace = await collection.getPropertiesConsumedSpace();
-      expect(recomputedSpace).to.be.equal(originalSpace);
-    });
-  }));
-});
deletedjs-packages/tests/nesting/collectionProperties.test.tsdiffbeforeafterboth
--- a/js-packages/tests/nesting/collectionProperties.test.ts
+++ /dev/null
@@ -1,326 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip, sizeOfProperty} from '../util/index.js';
-
-describe('Integration Test: Collection Properties', () => {
-  let alice: IKeyringPair;
-  let bob: IKeyringPair;
-
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice, bob] = await helper.arrange.createAccounts([200n, 10n], donor);
-    });
-  });
-
-  itSub('Properties are initially empty', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice);
-    expect(await collection.getProperties()).to.be.empty;
-  });
-
-  [
-    {mode: 'nft' as const, requiredPallets: []},
-    {mode: 'ft' as const, requiredPallets: []},
-    {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
-  ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
-    before(async function() {
-      // eslint-disable-next-line require-await
-      await usingPlaygrounds(async helper => {
-        requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
-      });
-    });
-
-    itSub('Sets properties for a collection', async ({helper}) =>  {
-      const collection = await helper[testSuite.mode].mintCollection(alice);
-
-      // As owner
-      await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}])).to.be.fulfilled;
-
-      await collection.addAdmin(alice, {Substrate: bob.address});
-
-      // As administrator
-      await expect(collection.setProperties(bob, [{key: 'black_hole'}])).to.be.fulfilled;
-
-      const properties = await collection.getProperties();
-      expect(properties).to.include.deep.members([
-        {key: 'electron', value: 'come bond'},
-        {key: 'black_hole', value: ''},
-      ]);
-    });
-
-    itSub('Check valid names for collection properties keys', async ({helper}) =>  {
-      const collection = await helper[testSuite.mode].mintCollection(alice);
-
-      // alpha symbols
-      await expect(collection.setProperties(alice, [{key: 'answer'}])).to.be.fulfilled;
-
-      // numeric symbols
-      await expect(collection.setProperties(alice, [{key: '451'}])).to.be.fulfilled;
-
-      // underscore symbol
-      await expect(collection.setProperties(alice, [{key: 'black_hole'}])).to.be.fulfilled;
-
-      // dash symbol
-      await expect(collection.setProperties(alice, [{key: '-'}])).to.be.fulfilled;
-
-      // dot symbol
-      await expect(collection.setProperties(alice, [{key: 'once.in.a.long.long.while...', value: 'you get a little lost'}])).to.be.fulfilled;
-
-      const properties = await collection.getProperties();
-      expect(properties).to.include.deep.members([
-        {key: 'answer', value: ''},
-        {key: '451', value: ''},
-        {key: 'black_hole', value: ''},
-        {key: '-', value: ''},
-        {key: 'once.in.a.long.long.while...', value: 'you get a little lost'},
-      ]);
-    });
-
-    itSub('Changes properties of a collection', async ({helper}) =>  {
-      const collection = await helper[testSuite.mode].mintCollection(alice);
-
-      await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: ''}])).to.be.fulfilled;
-
-      // Mutate the properties
-      await expect(collection.setProperties(alice, [{key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled;
-
-      const properties = await collection.getProperties();
-      expect(properties).to.include.deep.members([
-        {key: 'electron', value: 'come bond'},
-        {key: 'black_hole', value: 'LIGO'},
-      ]);
-    });
-
-    itSub('Deletes properties of a collection', async ({helper}) =>  {
-      const collection = await helper[testSuite.mode].mintCollection(alice);
-
-      await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled;
-
-      await expect(collection.deleteProperties(alice, ['electron'])).to.be.fulfilled;
-
-      const properties = await collection.getProperties(['black_hole', 'electron']);
-      expect(properties).to.be.deep.equal([
-        {key: 'black_hole', value: 'LIGO'},
-      ]);
-    });
-
-    itSub('Allows modifying a collection property multiple times with the same size', async({helper}) => {
-      const propKey = 'tok-prop';
-
-      const collection = await helper[testSuite.mode].mintCollection(alice);
-
-      const maxCollectionPropertiesSize = 40960;
-
-      const propDataSize = 4096;
-
-      let propDataChar = 'a';
-      const makeNewPropData = () => {
-        propDataChar = String.fromCharCode(propDataChar.charCodeAt(0) + 1);
-        return `${propDataChar}`.repeat(propDataSize);
-      };
-
-      const property = {key: propKey, value: makeNewPropData()};
-      await collection.setProperties(alice, [property]);
-      const originalSpace = await collection.getPropertiesConsumedSpace();
-      expect(originalSpace).to.be.equal(sizeOfProperty(property));
-
-      const sameSizePropertiesPossibleNum = maxCollectionPropertiesSize / propDataSize;
-
-      // It is possible to modify a property as many times as needed.
-      // It will not consume any additional space.
-      for(let i = 0; i < sameSizePropertiesPossibleNum + 1; i++) {
-        await collection.setProperties(alice, [{key: propKey, value: makeNewPropData()}]);
-        const consumedSpace = await collection.getPropertiesConsumedSpace();
-        expect(consumedSpace).to.be.equal(originalSpace);
-      }
-    });
-
-    itSub('Adding then removing a collection property doesn\'t change the consumed space', async({helper}) => {
-      const propKey = 'tok-prop';
-
-      const collection = await helper[testSuite.mode].mintCollection(alice);
-      const originalSpace = await collection.getPropertiesConsumedSpace();
-
-      const propDataSize = 4096;
-      const propData = 'a'.repeat(propDataSize);
-
-      const property = {key: propKey, value: propData};
-      await collection.setProperties(alice, [property]);
-      let consumedSpace = await collection.getPropertiesConsumedSpace();
-      expect(consumedSpace).to.be.equal(sizeOfProperty(property));
-
-      await collection.deleteProperties(alice, [propKey]);
-      consumedSpace = await collection.getPropertiesConsumedSpace();
-      expect(consumedSpace).to.be.equal(originalSpace);
-    });
-
-    itSub('Modifying a collection property with different sizes correctly changes the consumed space', async({helper}) => {
-      const propKey = 'tok-prop';
-
-      const collection = await helper[testSuite.mode].mintCollection(alice);
-      const originalSpace = await collection.getPropertiesConsumedSpace();
-
-      const initProp = {key: propKey, value: 'a'.repeat(4096)};
-      const biggerProp = {key: propKey, value: 'b'.repeat(5000)};
-      const smallerProp = {key: propKey, value: 'c'.repeat(4000)};
-
-      let consumedSpace;
-      let expectedConsumedSpaceDiff;
-
-      await collection.setProperties(alice, [initProp]);
-      consumedSpace = await collection.getPropertiesConsumedSpace();
-      expectedConsumedSpaceDiff = sizeOfProperty(initProp) - originalSpace;
-      expect(consumedSpace).to.be.equal(originalSpace + expectedConsumedSpaceDiff);
-
-      await collection.setProperties(alice, [biggerProp]);
-      consumedSpace = await collection.getPropertiesConsumedSpace();
-      expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(initProp);
-      expect(consumedSpace).to.be.equal(sizeOfProperty(initProp) + expectedConsumedSpaceDiff);
-
-      await collection.setProperties(alice, [smallerProp]);
-      consumedSpace = await collection.getPropertiesConsumedSpace();
-      expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(smallerProp);
-      expect(consumedSpace).to.be.equal(sizeOfProperty(biggerProp) - expectedConsumedSpaceDiff);
-    });
-  }));
-});
-
-describe('Negative Integration Test: Collection Properties', () => {
-  let alice: IKeyringPair;
-  let bob: IKeyringPair;
-
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice, bob] = await helper.arrange.createAccounts([1000n, 100n], donor);
-    });
-  });
-
-  [
-    {mode: 'nft' as const, requiredPallets: []},
-    {mode: 'ft' as const, requiredPallets: []},
-    {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
-  ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
-    before(async function() {
-      // eslint-disable-next-line require-await
-      await usingPlaygrounds(async helper => {
-        requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
-      });
-    });
-
-    itSub('Fails to set properties in a collection if not its onwer/administrator', async ({helper}) =>  {
-      const collection = await helper[testSuite.mode].mintCollection(alice);
-
-      await expect(collection.setProperties(bob, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]))
-        .to.be.rejectedWith(/common\.NoPermission/);
-
-      expect(await collection.getProperties()).to.be.empty;
-    });
-
-    itSub('Fails to set properties that exceed the limits', async ({helper}) =>  {
-      const collection = await helper[testSuite.mode].mintCollection(alice);
-
-      const spaceLimit = (helper.getApi().consts.unique.maxCollectionPropertiesSize as any).toNumber();
-
-      // Mute the general tx parsing error, too many bytes to process
-      {
-        console.error = () => {};
-        await expect(collection.setProperties(alice, [
-          {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))},
-        ])).to.be.rejected;
-      }
-
-      expect(await collection.getProperties(['electron'])).to.be.empty;
-
-      await expect(collection.setProperties(alice, [
-        {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 18))},
-        {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))},
-      ])).to.be.rejectedWith(/common\.NoSpaceForProperty/);
-
-      expect(await collection.getProperties(['electron', 'black_hole'])).to.be.empty;
-    });
-
-    itSub('Fails to set more properties than it is allowed', async ({helper}) =>  {
-      const collection = await helper[testSuite.mode].mintCollection(alice);
-
-      const propertiesToBeSet = [];
-      for(let i = 0; i < 65; i++) {
-        propertiesToBeSet.push({
-          key: 'electron_' + i,
-          value: Math.random() > 0.5 ? 'high' : 'low',
-        });
-      }
-
-      await expect(collection.setProperties(alice, propertiesToBeSet)).
-        to.be.rejectedWith(/common\.PropertyLimitReached/);
-
-      expect(await collection.getProperties()).to.be.empty;
-    });
-
-    itSub('Fails to set properties with invalid names', async ({helper}) => {
-      const collection = await helper[testSuite.mode].mintCollection(alice);
-
-      const invalidProperties = [
-        [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],
-        [{key: 'Mr/Sandman', value: 'Bring me a gene'}],
-        [{key: 'déjà vu', value: 'hmm...'}],
-      ];
-
-      for(let i = 0; i < invalidProperties.length; i++) {
-        await expect(
-          collection.setProperties(alice, invalidProperties[i]),
-          `on rejecting the new badly-named property #${i}`,
-        ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
-      }
-
-      await expect(
-        collection.setProperties(alice, [{key: '', value: 'nothing must not exist'}]),
-        'on rejecting an unnamed property',
-      ).to.be.rejectedWith(/common\.EmptyPropertyKey/);
-
-      await expect(
-        collection.setProperties(alice, [{key: 'CRISPR-Cas9', value: 'rewriting nature!'}]),
-        'on setting the correctly-but-still-badly-named property',
-      ).to.be.fulfilled;
-
-      const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');
-
-      const properties = await collection.getProperties(keys);
-      expect(properties).to.be.deep.equal([
-        {key: 'CRISPR-Cas9', value: 'rewriting nature!'},
-      ]);
-
-      for(let i = 0; i < invalidProperties.length; i++) {
-        await expect(
-          collection.deleteProperties(alice, invalidProperties[i].map(propertySet => propertySet.key)),
-          `on trying to delete the non-existent badly-named property #${i}`,
-        ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
-      }
-    });
-
-    itSub('Forbids to repair a collection if called with non-sudo', async({helper}) => {
-      const collection = await helper[testSuite.mode].mintCollection(alice, {properties: [
-        {key: 'sea-creatures', value: 'mermaids'},
-        {key: 'goldenratio', value: '1.6180339887498948482045868343656381177203091798057628621354486227052604628189'},
-      ]});
-
-      await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairCollection', [collection.collectionId], true))
-        .to.be.rejectedWith(/BadOrigin/);
-    });
-  }));
-});
deletedjs-packages/tests/nesting/graphs.test.tsdiffbeforeafterboth
--- a/js-packages/tests/nesting/graphs.test.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, usingPlaygrounds} from '../util/index.js';
-import {UniqueHelper, UniqueNFTCollection, UniqueNFToken} from '@unique/playgrounds/unique.js';
-
-/**
- * ```dot
- * 4 -> 3 -> 2 -> 1
- * 7 -> 6 -> 5 -> 2
- * 8 -> 5
- * ```
- */
-async function buildComplexObjectGraph(helper: UniqueHelper, sender: IKeyringPair): Promise<[UniqueNFTCollection,UniqueNFToken[]]> {
-  const collection = await helper.nft.mintCollection(sender, {permissions: {nesting: {tokenOwner: true}}});
-  const tokens = await collection.mintMultipleTokens(sender, Array(8).fill({owner: {Substrate: sender.address}}));
-
-  await tokens[7].nest(sender, tokens[4]);
-  await tokens[6].nest(sender, tokens[5]);
-  await tokens[5].nest(sender, tokens[4]);
-  await tokens[4].nest(sender, tokens[1]);
-  await tokens[3].nest(sender, tokens[2]);
-  await tokens[2].nest(sender, tokens[1]);
-  await tokens[1].nest(sender, tokens[0]);
-
-  return [collection, tokens];
-}
-
-describe('Graphs', () => {
-  let alice: IKeyringPair;
-
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice] = await helper.arrange.createAccounts([10n], donor);
-    });
-  });
-
-  itSub('Ouroboros can\'t be created in a complex graph', async ({helper}) => {
-    const [collection, tokens] = await buildComplexObjectGraph(helper, alice);
-
-    await collection.setPermissions(alice, {nesting: {collectionAdmin: false, tokenOwner: true}});
-
-    // [token owner] to self
-    await expect(
-      tokens[0].nest(alice, tokens[0]),
-      '[token owner] self-nesting is forbidden',
-    ).to.be.rejectedWith(/structure\.OuroborosDetected/);
-    // [token owner] to nested part of graph
-    await expect(
-      tokens[0].nest(alice, tokens[4]),
-      '[token owner] cannot nest the root node into an internal node',
-    ).to.be.rejectedWith(/structure\.OuroborosDetected/);
-    await expect(
-      tokens[1].transferFrom(alice, tokens[0].nestingAccount(), tokens[7].nestingAccount()),
-      '[token owner] cannot nest higher internal node into lower internal node',
-    ).to.be.rejectedWith(/structure\.OuroborosDetected/);
-
-    await collection.setPermissions(alice, {nesting: {collectionAdmin: true, tokenOwner: false}});
-
-    // [collection owner] to self
-    await expect(
-      tokens[0].nest(alice, tokens[0]),
-      '[collection owner] self-nesting is forbidden',
-    ).to.be.rejectedWith(/structure\.OuroborosDetected/);
-    // [collection owner] to nested part of graph
-    await expect(
-      tokens[0].nest(alice, tokens[4]),
-      '[collection owner] cannot nest the root node into an internal node',
-    ).to.be.rejectedWith(/structure\.OuroborosDetected/);
-  });
-});
deletedjs-packages/tests/nesting/propertyPermissions.test.tsdiffbeforeafterboth
--- a/js-packages/tests/nesting/propertyPermissions.test.ts
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, usingPlaygrounds, expect} from '../util/index.js';
-import {UniqueNFTCollection, UniqueRFTCollection} from '@unique/playgrounds/unique.js';
-
-describe('Integration Test: Access Rights to Token Properties', () => {
-  let alice: IKeyringPair;
-  let bob: IKeyringPair;
-
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor);
-    });
-  });
-
-  itSub('Reads access rights to properties of a collection', async ({helper}) =>  {
-    const collection = await helper.nft.mintCollection(alice);
-    const propertyRights = (await helper.callRpc('api.query.common.collectionPropertyPermissions', [collection.collectionId])).toJSON();
-    expect(propertyRights).to.be.empty;
-  });
-
-  async function testSetsAccessRightsToProperties(collection: UniqueNFTCollection | UniqueRFTCollection) {
-    await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true}}]))
-      .to.be.fulfilled;
-
-    await collection.addAdmin(alice, {Substrate: bob.address});
-
-    await expect(collection.setTokenPropertyPermissions(bob, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]))
-      .to.be.fulfilled;
-
-    const propertyRights = await collection.getPropertyPermissions(['skullduggery', 'mindgame']);
-    expect(propertyRights).to.include.deep.members([
-      {key: 'skullduggery', permission: {mutable: true, collectionAdmin: false, tokenOwner: false}},
-      {key: 'mindgame', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},
-    ]);
-  }
-
-  itSub('Sets access rights to properties of a collection (NFT)', async ({helper}) =>  {
-    await testSetsAccessRightsToProperties(await helper.nft.mintCollection(alice));
-  });
-
-  itSub.ifWithPallets('Sets access rights to properties of a collection (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
-    await testSetsAccessRightsToProperties(await helper.rft.mintCollection(alice));
-  });
-
-  async function testChangesAccessRightsToProperty(collection: UniqueNFTCollection | UniqueRFTCollection) {
-    await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]))
-      .to.be.fulfilled;
-
-    await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]))
-      .to.be.fulfilled;
-
-    const propertyRights = await collection.getPropertyPermissions();
-    expect(propertyRights).to.be.deep.equal([
-      {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
-    ]);
-  }
-
-  itSub('Changes access rights to properties of a NFT collection', async ({helper}) =>  {
-    await testChangesAccessRightsToProperty(await helper.nft.mintCollection(alice));
-  });
-
-  itSub.ifWithPallets('Changes access rights to properties of a ReFungible collection', [Pallets.ReFungible], async ({helper}) => {
-    await testChangesAccessRightsToProperty(await helper.rft.mintCollection(alice));
-  });
-});
-
-describe('Negative Integration Test: Access Rights to Token Properties', () => {
-  let alice: IKeyringPair;
-  let bob: IKeyringPair;
-
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
-    });
-  });
-
-  async function testPreventsFromSettingAccessRightsNotAdminOrOwner(collection: UniqueNFTCollection | UniqueRFTCollection) {
-    await expect(collection.setTokenPropertyPermissions(bob, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]))
-      .to.be.rejectedWith(/common\.NoPermission/);
-
-    const propertyRights = await collection.getPropertyPermissions(['skullduggery']);
-    expect(propertyRights).to.be.empty;
-  }
-
-  itSub('Prevents from setting access rights to properties of a NFT collection if not an onwer/admin', async ({helper}) =>  {
-    await testPreventsFromSettingAccessRightsNotAdminOrOwner(await helper.nft.mintCollection(alice));
-  });
-
-  itSub.ifWithPallets('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', [Pallets.ReFungible], async ({helper}) => {
-    await testPreventsFromSettingAccessRightsNotAdminOrOwner(await helper.rft.mintCollection(alice));
-  });
-
-  async function testPreventFromAddingTooManyPossibleProperties(collection: UniqueNFTCollection | UniqueRFTCollection) {
-    const constitution = [];
-    for(let i = 0; i < 65; i++) {
-      constitution.push({
-        key: 'property_' + i,
-        permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},
-      });
-    }
-
-    await expect(collection.setTokenPropertyPermissions(alice, constitution))
-      .to.be.rejectedWith(/common\.PropertyLimitReached/);
-
-    const propertyRights = await collection.getPropertyPermissions();
-    expect(propertyRights).to.be.empty;
-  }
-
-  itSub('Prevents from adding too many possible properties (NFT)', async ({helper}) =>  {
-    await testPreventFromAddingTooManyPossibleProperties(await helper.nft.mintCollection(alice));
-  });
-
-  itSub.ifWithPallets('Prevents from adding too many possible properties (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
-    await testPreventFromAddingTooManyPossibleProperties(await helper.rft.mintCollection(alice));
-  });
-
-  async function testPreventAccessRightsModifiedIfConstant(collection: UniqueNFTCollection | UniqueRFTCollection) {
-    await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]))
-      .to.be.fulfilled;
-
-    await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {collectionAdmin: true}}]))
-      .to.be.rejectedWith(/common\.NoPermission/);
-
-    const propertyRights = await collection.getPropertyPermissions(['skullduggery']);
-    expect(propertyRights).to.deep.equal([
-      {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
-    ]);
-  }
-
-  itSub('Prevents access rights to be modified if constant (NFT)', async ({helper}) =>  {
-    await testPreventAccessRightsModifiedIfConstant(await helper.nft.mintCollection(alice));
-  });
-
-  itSub.ifWithPallets('Prevents access rights to be modified if constant (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
-    await testPreventAccessRightsModifiedIfConstant(await helper.rft.mintCollection(alice));
-  });
-
-  async function testPreventsAddingPropertiesWithInvalidNames(collection: UniqueNFTCollection | UniqueRFTCollection) {
-    const invalidProperties = [
-      [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],
-      [{key: 'G#4', permission: {tokenOwner: true}}],
-      [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],
-    ];
-
-    for(let i = 0; i < invalidProperties.length; i++) {
-      await expect(
-        collection.setTokenPropertyPermissions(alice, invalidProperties[i]),
-        `on setting the new badly-named property #${i}`,
-      ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
-    }
-
-    await expect(
-      collection.setTokenPropertyPermissions(alice, [{key: '', permission: {}}]),
-      'on rejecting an unnamed property',
-    ).to.be.rejectedWith(/common\.EmptyPropertyKey/);
-
-    const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string
-    await expect(
-      collection.setTokenPropertyPermissions(alice, [
-        {key: correctKey, permission: {collectionAdmin: true}},
-      ]),
-      'on setting the correctly-but-still-badly-named property',
-    ).to.be.fulfilled;
-
-    const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');
-
-    const propertyRights = await collection.getPropertyPermissions(keys);
-    expect(propertyRights).to.be.deep.equal([
-      {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},
-    ]);
-  }
-
-  itSub('Prevents adding properties with invalid names (NFT)', async ({helper}) =>  {
-    await testPreventsAddingPropertiesWithInvalidNames(await helper.nft.mintCollection(alice));
-  });
-
-  itSub.ifWithPallets('Prevents adding properties with invalid names (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
-    await testPreventsAddingPropertiesWithInvalidNames(await helper.rft.mintCollection(alice));
-  });
-});
deletedjs-packages/tests/nesting/tokenProperties.seqtest.tsdiffbeforeafterboth
--- a/js-packages/tests/nesting/tokenProperties.seqtest.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip, sizeOfProperty} from '../util/index.js';
-
-describe('Integration Test: Token Properties with sudo', () => {
-  let superuser: IKeyringPair;
-  let alice: IKeyringPair; // collection owner
-
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      superuser = await privateKey('//Alice');
-      const donor = await privateKey({url: import.meta.url});
-      [alice] = await helper.arrange.createAccounts([100n], donor);
-    });
-  });
-
-  [
-    {mode: 'nft' as const, pieces: undefined, requiredPallets: []} as const,
-    {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]} as const,
-  ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
-    before(async function() {
-      // eslint-disable-next-line require-await
-      await usingPlaygrounds(async helper => {
-        requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
-      });
-    });
-
-    itSub('force_repair_item preserves valid consumed space', async({helper}) => {
-      const propKey = 'tok-prop';
-
-      const collection = await helper[testSuite.mode].mintCollection(alice, {
-        tokenPropertyPermissions: [
-          {
-            key: propKey,
-            permission: {mutable: true, tokenOwner: true},
-          },
-        ],
-      });
-      const token = await (
-        testSuite.pieces
-          ? collection.mintToken(alice, testSuite.pieces as any)
-          : collection.mintToken(alice)
-      );
-
-      const prop = {key: propKey, value: 'a'.repeat(4096)};
-
-      await token.setProperties(alice, [prop]);
-      const originalSpace = await token.getTokenPropertiesConsumedSpace();
-      expect(originalSpace).to.be.equal(sizeOfProperty(prop));
-
-      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.unique.forceRepairItem', [token.collectionId, token.tokenId], true);
-      const recomputedSpace = await token.getTokenPropertiesConsumedSpace();
-      expect(recomputedSpace).to.be.equal(originalSpace);
-    });
-  }));
-});
deletedjs-packages/tests/nesting/tokenProperties.test.tsdiffbeforeafterboth
--- a/js-packages/tests/nesting/tokenProperties.test.ts
+++ /dev/null
@@ -1,816 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect, sizeOfProperty} from '../util/index.js';
-import {UniqueHelper, UniqueNFToken, UniqueRFToken} from '@unique/playgrounds/unique.js';
-
-describe('Integration Test: Token Properties', () => {
-  let alice: IKeyringPair; // collection owner
-  let bob: IKeyringPair; // collection admin
-  let charlie: IKeyringPair; // token owner
-
-  let permissions: {permission: any, signers: IKeyringPair[]}[];
-
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 100n, 100n], donor);
-    });
-
-    permissions = [
-      {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},
-      {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob]},
-      {permission: {mutable: true, tokenOwner: true}, signers: [charlie]},
-      {permission: {mutable: false, tokenOwner: true}, signers: [charlie]},
-      {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},
-      {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},
-    ];
-  });
-
-  async function mintCollectionWithAllPermissionsAndToken(helper: UniqueHelper, mode: 'NFT' | 'RFT'): Promise<[UniqueNFToken | UniqueRFToken, bigint]> {
-    const collection = await (mode == 'NFT' ? helper.nft : helper.rft).mintCollection(alice, {
-      tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
-        signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
-    });
-    return mode == 'NFT' ? [await collection.mintToken(alice), 1n] : [await collection.mintToken(alice, 100n as any), 100n];
-  }
-
-  async function testReadsYetEmptyProperties(token: UniqueNFToken | UniqueRFToken) {
-    const properties = await token.getProperties();
-    expect(properties).to.be.empty;
-
-    const tokenData = await token.getData();
-    expect(tokenData!.properties).to.be.empty;
-  }
-
-  itSub('Reads yet empty properties of a token (NFT)', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice);
-    const token = await collection.mintToken(alice);
-    await testReadsYetEmptyProperties(token);
-  });
-
-  itSub.ifWithPallets('Reads yet empty properties of a token (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
-    const collection = await helper.rft.mintCollection(alice);
-    const token = await collection.mintToken(alice);
-    await testReadsYetEmptyProperties(token);
-  });
-
-  async function testAssignPropertiesAccordingToPermissions(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
-    await token.collection.addAdmin(alice, {Substrate: bob.address});
-    await token.transfer(alice, {Substrate: charlie.address}, pieces);
-
-    const propertyKeys: string[] = [];
-    let i = 0;
-    for(const permission of permissions) {
-      i++;
-      let j = 0;
-      for(const signer of permission.signers) {
-        j++;
-        const key = i + '_' + signer.address;
-        propertyKeys.push(key);
-
-        await expect(
-          token.setProperties(signer, [{key: key, value: 'Serotonin increase'}]),
-          `on adding property #${i} by signer #${j}`,
-        ).to.be.fulfilled;
-      }
-    }
-
-    const properties = await token.getProperties(propertyKeys);
-    const tokenData = await token.getData();
-    for(let i = 0; i < properties.length; i++) {
-      expect(properties[i].value).to.be.equal('Serotonin increase');
-      expect(tokenData!.properties[i].value).to.be.equal('Serotonin increase');
-    }
-  }
-
-  itSub('Assigns properties to a token according to permissions (NFT)', async ({helper}) =>  {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
-    await testAssignPropertiesAccordingToPermissions(token, amount);
-  });
-
-  itSub.ifWithPallets('Assigns properties to a token according to permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
-    await testAssignPropertiesAccordingToPermissions(token, amount);
-  });
-
-  async function testChangesPropertiesAccordingPermission(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
-    await token.collection.addAdmin(alice, {Substrate: bob.address});
-    await token.transfer(alice, {Substrate: charlie.address}, pieces);
-
-    const propertyKeys: string[] = [];
-    let i = 0;
-    for(const permission of permissions) {
-      i++;
-      if(!permission.permission.mutable) continue;
-
-      let j = 0;
-      for(const signer of permission.signers) {
-        j++;
-        const key = i + '_' + signer.address;
-        propertyKeys.push(key);
-
-        await expect(
-          token.setProperties(signer, [{key, value: 'Serotonin increase'}]),
-          `on adding property #${i} by signer #${j}`,
-        ).to.be.fulfilled;
-
-        await expect(
-          token.setProperties(signer, [{key, value: 'Serotonin stable'}]),
-          `on changing property #${i} by signer #${j}`,
-        ).to.be.fulfilled;
-      }
-    }
-
-    const properties = await token.getProperties(propertyKeys);
-    const tokenData = await token.getData();
-    for(let i = 0; i < properties.length; i++) {
-      expect(properties[i].value).to.be.equal('Serotonin stable');
-      expect(tokenData!.properties[i].value).to.be.equal('Serotonin stable');
-    }
-  }
-
-  itSub('Changes properties of a token according to permissions (NFT)', async ({helper}) =>  {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
-    await testChangesPropertiesAccordingPermission(token, amount);
-  });
-
-  itSub.ifWithPallets('Changes properties of a token according to permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
-    await testChangesPropertiesAccordingPermission(token, amount);
-  });
-
-  async function testDeletePropertiesAccordingPermission(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
-    await token.collection.addAdmin(alice, {Substrate: bob.address});
-    await token.transfer(alice, {Substrate: charlie.address}, pieces);
-
-    const propertyKeys: string[] = [];
-    let i = 0;
-
-    for(const permission of permissions) {
-      i++;
-      if(!permission.permission.mutable) continue;
-
-      let j = 0;
-      for(const signer of permission.signers) {
-        j++;
-        const key = i + '_' + signer.address;
-        propertyKeys.push(key);
-
-        await expect(
-          token.setProperties(signer, [{key, value: 'Serotonin increase'}]),
-          `on adding property #${i} by signer #${j}`,
-        ).to.be.fulfilled;
-
-        await expect(
-          token.deleteProperties(signer, [key]),
-          `on deleting property #${i} by signer #${j}`,
-        ).to.be.fulfilled;
-      }
-    }
-
-    expect(await token.getProperties(propertyKeys)).to.be.empty;
-    expect((await token.getData())!.properties).to.be.empty;
-  }
-
-  itSub('Deletes properties of a token according to permissions (NFT)', async ({helper}) =>  {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
-    await testDeletePropertiesAccordingPermission(token, amount);
-  });
-
-  itSub.ifWithPallets('Deletes properties of a token according to permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
-    await testDeletePropertiesAccordingPermission(token, amount);
-  });
-
-  itSub('Assigns properties to a nested token according to permissions', async ({helper}) =>  {
-    const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
-    const collectionB = await helper.nft.mintCollection(alice, {
-      tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
-        signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
-    });
-    const targetToken = await collectionA.mintToken(alice);
-    const nestedToken = await collectionB.mintToken(alice, targetToken.nestingAccount());
-
-    await collectionB.addAdmin(alice, {Substrate: bob.address});
-    await targetToken.transfer(alice, {Substrate: charlie.address});
-
-    const propertyKeys: string[] = [];
-    let i = 0;
-    for(const permission of permissions) {
-      i++;
-      let j = 0;
-      for(const signer of permission.signers) {
-        j++;
-        const key = i + '_' + signer.address;
-        propertyKeys.push(key);
-
-        await expect(
-          nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]),
-          `on adding property #${i} by signer #${j}`,
-        ).to.be.fulfilled;
-      }
-    }
-
-    const properties = await nestedToken.getProperties(propertyKeys);
-    const tokenData = await nestedToken.getData();
-    for(let i = 0; i < properties.length; i++) {
-      expect(properties[i].value).to.be.equal('Serotonin increase');
-      expect(tokenData!.properties[i].value).to.be.equal('Serotonin increase');
-    }
-    expect(await targetToken.getProperties()).to.be.empty;
-  });
-
-  itSub('Changes properties of a nested token according to permissions', async ({helper}) =>  {
-    const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
-    const collectionB = await helper.nft.mintCollection(alice, {
-      tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
-        signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
-    });
-    const targetToken = await collectionA.mintToken(alice);
-    const nestedToken = await collectionB.mintToken(alice, targetToken.nestingAccount());
-
-    await collectionB.addAdmin(alice, {Substrate: bob.address});
-    await targetToken.transfer(alice, {Substrate: charlie.address});
-
-    const propertyKeys: string[] = [];
-    let i = 0;
-    for(const permission of permissions) {
-      i++;
-      if(!permission.permission.mutable) continue;
-
-      let j = 0;
-      for(const signer of permission.signers) {
-        j++;
-        const key = i + '_' + signer.address;
-        propertyKeys.push(key);
-
-        await expect(
-          nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]),
-          `on adding property #${i} by signer #${j}`,
-        ).to.be.fulfilled;
-
-        await expect(
-          nestedToken.setProperties(signer, [{key, value: 'Serotonin stable'}]),
-          `on changing property #${i} by signer #${j}`,
-        ).to.be.fulfilled;
-      }
-    }
-
-    const properties = await nestedToken.getProperties(propertyKeys);
-    const tokenData = await nestedToken.getData();
-    for(let i = 0; i < properties.length; i++) {
-      expect(properties[i].value).to.be.equal('Serotonin stable');
-      expect(tokenData!.properties[i].value).to.be.equal('Serotonin stable');
-    }
-    expect(await targetToken.getProperties()).to.be.empty;
-  });
-
-  itSub('Deletes properties of a nested token according to permissions', async ({helper}) =>  {
-    const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
-    const collectionB = await helper.nft.mintCollection(alice, {
-      tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
-        signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
-    });
-    const targetToken = await collectionA.mintToken(alice);
-    const nestedToken = await collectionB.mintToken(alice, targetToken.nestingAccount());
-
-    await collectionB.addAdmin(alice, {Substrate: bob.address});
-    await targetToken.transfer(alice, {Substrate: charlie.address});
-
-    const propertyKeys: string[] = [];
-    let i = 0;
-    for(const permission of permissions) {
-      i++;
-      if(!permission.permission.mutable) continue;
-
-      let j = 0;
-      for(const signer of permission.signers) {
-        j++;
-        const key = i + '_' + signer.address;
-        propertyKeys.push(key);
-
-        await expect(
-          nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]),
-          `on adding property #${i} by signer #${j}`,
-        ).to.be.fulfilled;
-
-        await expect(
-          nestedToken.deleteProperties(signer, [key]),
-          `on deleting property #${i} by signer #${j}`,
-        ).to.be.fulfilled;
-      }
-    }
-
-    expect(await nestedToken.getProperties(propertyKeys)).to.be.empty;
-    expect((await nestedToken.getData())!.properties).to.be.empty;
-    expect(await targetToken.getProperties()).to.be.empty;
-  });
-
-  [
-    {mode: 'nft' as const, storage: 'nonfungible' as const, pieces: undefined, requiredPallets: []} as const,
-    {mode: 'rft' as const, storage: 'refungible' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]} as const,
-  ].map(testCase =>
-    itSub.ifWithPallets(`Allows modifying a token property multiple times with the same size (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
-      const propKey = 'tok-prop';
-
-      const collection = await helper[testCase.mode].mintCollection(alice, {
-        tokenPropertyPermissions: [
-          {
-            key: propKey,
-            permission: {mutable: true, tokenOwner: true},
-          },
-        ],
-      });
-
-      const maxTokenPropertiesSize = 32768;
-
-      const propDataSize = 4096;
-
-      let propDataChar = 'a';
-      const makeNewPropData = () => {
-        propDataChar = String.fromCharCode(propDataChar.charCodeAt(0) + 1);
-        return `${propDataChar}`.repeat(propDataSize);
-      };
-
-      const token = await (
-        testCase.pieces
-          ? collection.mintToken(alice, testCase.pieces as any)
-          : collection.mintToken(alice)
-      );
-
-      const property = {key: propKey, value: makeNewPropData()};
-      await token.setProperties(alice, [property]);
-      const originalSpace = await token.getTokenPropertiesConsumedSpace();
-      expect(originalSpace).to.be.equal(sizeOfProperty(property));
-
-      const sameSizePropertiesPossibleNum = maxTokenPropertiesSize / propDataSize;
-
-      // It is possible to modify a property as many times as needed.
-      // It will not consume any additional space.
-      for(let i = 0; i < sameSizePropertiesPossibleNum + 1; i++) {
-        await token.setProperties(alice, [{key: propKey, value: makeNewPropData()}]);
-        const consumedSpace = await token.getTokenPropertiesConsumedSpace();
-        expect(consumedSpace).to.be.equal(originalSpace);
-      }
-    }));
-
-  [
-    {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
-    {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
-  ].map(testCase =>
-    itSub.ifWithPallets(`Adding then removing a token property doesn't change the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
-      const propKey = 'tok-prop';
-
-      const collection = await helper[testCase.mode].mintCollection(alice, {
-        tokenPropertyPermissions: [
-          {
-            key: propKey,
-            permission: {mutable: true, tokenOwner: true},
-          },
-        ],
-      });
-      const token = await (
-        testCase.pieces
-          ? collection.mintToken(alice, testCase.pieces as any)
-          : collection.mintToken(alice)
-      );
-      const originalSpace = await token.getTokenPropertiesConsumedSpace();
-
-      const propDataSize = 4096;
-      const propData = 'a'.repeat(propDataSize);
-
-      const property = {key: propKey, value: propData};
-      await token.setProperties(alice, [property]);
-      let consumedSpace = await token.getTokenPropertiesConsumedSpace();
-      expect(consumedSpace).to.be.equal(sizeOfProperty(property));
-
-      await token.deleteProperties(alice, [propKey]);
-      consumedSpace = await token.getTokenPropertiesConsumedSpace();
-      expect(consumedSpace).to.be.equal(originalSpace);
-    }));
-
-  [
-    {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
-    {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
-  ].map(testCase =>
-    itSub.ifWithPallets(`Modifying a token property with different sizes correctly changes the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
-      const propKey = 'tok-prop';
-
-      const collection = await helper[testCase.mode].mintCollection(alice, {
-        tokenPropertyPermissions: [
-          {
-            key: propKey,
-            permission: {mutable: true, tokenOwner: true},
-          },
-        ],
-      });
-      const token = await (
-        testCase.pieces
-          ? collection.mintToken(alice, testCase.pieces as any)
-          : collection.mintToken(alice)
-      );
-      const originalSpace = await token.getTokenPropertiesConsumedSpace();
-
-      const initProp = {key: propKey, value: 'a'.repeat(4096)};
-      const biggerProp = {key: propKey, value: 'b'.repeat(5000)};
-      const smallerProp = {key: propKey, value: 'c'.repeat(4000)};
-
-      let consumedSpace;
-      let expectedConsumedSpaceDiff;
-
-      await token.setProperties(alice, [initProp]);
-      consumedSpace = await token.getTokenPropertiesConsumedSpace();
-      expectedConsumedSpaceDiff = sizeOfProperty(initProp) - originalSpace;
-      expect(consumedSpace).to.be.equal(originalSpace + expectedConsumedSpaceDiff);
-
-      await token.setProperties(alice, [biggerProp]);
-      consumedSpace = await token.getTokenPropertiesConsumedSpace();
-      expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(initProp);
-      expect(consumedSpace).to.be.equal(sizeOfProperty(initProp) + expectedConsumedSpaceDiff);
-
-      await token.setProperties(alice, [smallerProp]);
-      consumedSpace = await token.getTokenPropertiesConsumedSpace();
-      expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(smallerProp);
-      expect(consumedSpace).to.be.equal(sizeOfProperty(biggerProp) - expectedConsumedSpaceDiff);
-    }));
-
-  itSub('Set sponsored properties', async({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {tokenPropertyPermissions: [{key: 'k', permission: {tokenOwner: true}}]});
-
-    await collection.setSponsor(alice, alice.address);
-    await collection.confirmSponsorship(alice);
-    await collection.setPermissions(alice, {access: 'AllowList', mintMode: true});
-    await collection.addToAllowList(alice, {Substrate: bob.address});
-    await collection.setLimits(alice, {sponsoredDataRateLimit: {blocks: 30}});
-
-    const token = await collection.mintToken(alice, {Substrate: bob.address});
-
-    const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
-    const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
-
-    await token.setProperties(bob, [{key: 'k', value: 'val'}]);
-
-    const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
-    const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
-
-    expect(bobBalanceAfter).to.be.equal(bobBalanceBefore);
-    expect(aliceBalanceBefore > aliceBalanceAfter).to.be.true;
-  });
-});
-
-describe('Negative Integration Test: Token Properties', () => {
-  let alice: IKeyringPair; // collection owner
-  let bob: IKeyringPair; // collection admin
-  let charlie: IKeyringPair; // token owner
-
-  let constitution: {permission: any, signers: IKeyringPair[], sinner: IKeyringPair}[];
-
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      let dave: IKeyringPair;
-      [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);
-
-      // todo:playgrounds probably separate these tests later
-      constitution = [
-        {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},
-        {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},
-        {permission: {mutable: true, tokenOwner: true}, signers: [charlie], sinner: alice},
-        {permission: {mutable: false, tokenOwner: true}, signers: [charlie], sinner: alice},
-        {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},
-        {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},
-      ];
-    });
-  });
-
-  [
-    {mode: 'nft' as const, requiredPallets: [Pallets.NFT]},
-    {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
-  ].map(testCase =>
-    itSub.ifWithPallets(`Forbids adding/deleting properties of a token if token doesn't exist (${testCase.mode.toLocaleUpperCase})`, testCase.requiredPallets, async({helper}) => {
-      const collection = await helper[testCase.mode].mintCollection(alice, {
-        tokenPropertyPermissions: constitution.slice(0, 1).map(({permission}) => ({key: '1', permission})),
-      });
-      const nonExistentToken = collection.getTokenObject(1);
-
-      await expect(
-        nonExistentToken.setProperties(alice, [{key: '1', value: 'Serotonin increase'}]),
-        'on expecting failure whilst adding a property by alice',
-      ).to.be.rejectedWith(/common\.TokenNotFound/);
-
-      await expect(
-        nonExistentToken.deleteProperties(alice, ['1']),
-        'on expecting failure whilst deleting a property by alice',
-      ).to.be.rejectedWith(/common\.TokenNotFound/);
-    }));
-
-  async function mintCollectionWithAllPermissionsAndToken(helper: UniqueHelper, mode: 'NFT' | 'RFT'): Promise<[UniqueNFToken | UniqueRFToken, bigint]> {
-    const collection = await (mode == 'NFT' ? helper.nft : helper.rft).mintCollection(alice, {
-      tokenPropertyPermissions: constitution.map(({permission}, i) => ({key: `${i+1}`, permission})),
-    });
-    return mode == 'NFT' ? [await collection.mintToken(alice), 1n] : [await collection.mintToken(alice, 100n as any), 100n];
-  }
-
-  async function getConsumedSpace(api: any, collectionId: number, tokenId: number, mode: 'NFT' | 'RFT'): Promise<number> {
-    return (await (mode == 'NFT' ? api.query.nonfungible : api.query.refungible).tokenProperties(collectionId, tokenId)).toJSON().consumedSpace;
-  }
-
-  async function prepare(token: UniqueNFToken | UniqueRFToken, pieces: bigint): Promise<number> {
-    await token.collection.addAdmin(alice, {Substrate: bob.address});
-    await token.transfer(alice, {Substrate: charlie.address}, pieces);
-
-    let i = 0;
-    for(const passage of constitution) {
-      i++;
-      const signer = passage.signers[0];
-      await expect(
-        token.setProperties(signer, [{key: `${i}`, value: 'Serotonin increase'}]),
-        `on adding property ${i} by ${signer.address}`,
-      ).to.be.fulfilled;
-    }
-
-    const originalSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
-    return originalSpace;
-  }
-
-  async function testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
-    const originalSpace = await prepare(token, pieces);
-
-    let i = 0;
-    for(const forbiddance of constitution) {
-      i++;
-      if(!forbiddance.permission.mutable) continue;
-
-      await expect(
-        token.setProperties(forbiddance.sinner, [{key: `${i}`, value: 'Serotonin down'}]),
-        `on failing to change property ${i} by the malefactor`,
-      ).to.be.rejectedWith(/common\.NoPermission/);
-
-      await expect(
-        token.deleteProperties(forbiddance.sinner, [`${i}`]),
-        `on failing to delete property ${i} by the malefactor`,
-      ).to.be.rejectedWith(/common\.NoPermission/);
-    }
-
-    const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
-    expect(consumedSpace).to.be.equal(originalSpace);
-  }
-
-  itSub('Forbids changing/deleting properties of a token if the user is outside of permissions (NFT)', async ({helper}) =>  {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
-    await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token, amount);
-  });
-
-  itSub.ifWithPallets('Forbids changing/deleting properties of a token if the user is outside of permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
-    await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token, amount);
-  });
-
-  async function testForbidsChangingDeletingPropertiesIfPropertyImmutable(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
-    const originalSpace = await prepare(token, pieces);
-
-    let i = 0;
-    for(const permission of constitution) {
-      i++;
-      if(permission.permission.mutable) continue;
-
-      await expect(
-        token.setProperties(permission.signers[0], [{key: `${i}`, value: 'Serotonin down'}]),
-        `on failing to change property ${i} by signer #0`,
-      ).to.be.rejectedWith(/common\.NoPermission/);
-
-      await expect(
-        token.deleteProperties(permission.signers[0], [i.toString()]),
-        `on failing to delete property ${i} by signer #0`,
-      ).to.be.rejectedWith(/common\.NoPermission/);
-    }
-
-    const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
-    expect(consumedSpace).to.be.equal(originalSpace);
-  }
-
-  itSub('Forbids changing/deleting properties of a token if the property is permanent (immutable) (NFT)', async ({helper}) =>  {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
-    await testForbidsChangingDeletingPropertiesIfPropertyImmutable(token, amount);
-  });
-
-  itSub.ifWithPallets('Forbids changing/deleting properties of a token if the property is permanent (immutable) (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
-    await testForbidsChangingDeletingPropertiesIfPropertyImmutable(token, amount);
-  });
-
-  async function testForbidsAddingPropertiesIfPropertyNotDeclared(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
-    const originalSpace = await prepare(token, pieces);
-
-    await expect(
-      token.setProperties(alice, [{key: 'non-existent', value: 'I exist!'}]),
-      'on failing to add a previously non-existent property',
-    ).to.be.rejectedWith(/common\.NoPermission/);
-
-    await expect(
-      token.collection.setTokenPropertyPermissions(alice, [{key: 'now-existent', permission: {}}]),
-      'on setting a new non-permitted property',
-    ).to.be.fulfilled;
-
-    await expect(
-      token.setProperties(alice, [{key: 'now-existent', value: 'I exist!'}]),
-      'on failing to add a property forbidden by the \'None\' permission',
-    ).to.be.rejectedWith(/common\.NoPermission/);
-
-    expect(await token.getProperties(['non-existent', 'now-existent'])).to.be.empty;
-
-    const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
-    expect(consumedSpace).to.be.equal(originalSpace);
-  }
-
-  itSub('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (NFT)', async ({helper}) =>  {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
-    await testForbidsAddingPropertiesIfPropertyNotDeclared(token, amount);
-  });
-
-  itSub.ifWithPallets('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
-    await testForbidsAddingPropertiesIfPropertyNotDeclared(token, amount);
-  });
-
-  async function testForbidsAddingTooLargeProperties(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
-    const originalSpace = await prepare(token, pieces);
-
-    await expect(
-      token.collection.setTokenPropertyPermissions(alice, [
-        {key: 'a_holy_book', permission: {collectionAdmin: true, tokenOwner: true}},
-        {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},
-      ]),
-      'on setting new permissions for properties',
-    ).to.be.fulfilled;
-
-    // Mute the general tx parsing error
-    {
-      console.error = () => {};
-      await expect(token.setProperties(alice, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]))
-        .to.be.rejected;
-    }
-
-    await expect(token.setProperties(alice, [
-      {key: 'a_holy_book', value: 'word '.repeat(3277)},
-      {key: 'young_years', value: 'neverending'.repeat(1490)},
-    ])).to.be.rejectedWith(/common\.NoSpaceForProperty/);
-
-    expect(await token.getProperties(['a_holy_book', 'young_years'])).to.be.empty;
-    const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
-    expect(consumedSpace).to.be.equal(originalSpace);
-  }
-
-  itSub('Forbids adding too large properties to a token (NFT)', async ({helper}) =>  {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
-    await testForbidsAddingTooLargeProperties(token, amount);
-  });
-
-  itSub.ifWithPallets('Forbids adding too large properties to a token (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
-    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
-    await testForbidsAddingTooLargeProperties(token, amount);
-  });
-
-  [
-    {mode: 'nft' as const, requiredPallets: []},
-    {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
-  ].map(testCase =>
-    itSub.ifWithPallets(`Forbids adding too many propeties to a token (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
-      const collection = await helper[testCase.mode].mintCollection(alice);
-      const maxPropertiesPerItem = 64;
-
-      for(let i = 0; i < maxPropertiesPerItem; i++) {
-        await collection.setTokenPropertyPermissions(alice, [{
-          key: `${i+1}`,
-          permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
-        }]);
-      }
-
-      await expect(collection.setTokenPropertyPermissions(alice, [{
-        key: `${maxPropertiesPerItem}-th`,
-        permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
-      }])).to.be.rejectedWith(/common\.PropertyLimitReached/);
-    }));
-
-  [
-    {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
-    {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
-  ].map(testCase =>
-    itSub.ifWithPallets(`Forbids force_repair_item from non-sudo (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
-      const propKey = 'tok-prop';
-
-      const collection = await helper[testCase.mode].mintCollection(alice, {
-        tokenPropertyPermissions: [
-          {
-            key: propKey,
-            permission: {mutable: true, tokenOwner: true},
-          },
-        ],
-      });
-      const token = await (
-        testCase.pieces
-          ? collection.mintToken(alice, testCase.pieces as any)
-          : collection.mintToken(alice)
-      );
-
-      const propDataSize = 4096;
-      const propData = 'a'.repeat(propDataSize);
-      await token.setProperties(alice, [{key: propKey, value: propData}]);
-
-      await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairItem', [token.collectionId, token.tokenId], true))
-        .to.be.rejectedWith(/BadOrigin/);
-    }));
-});
-
-describe('ReFungible token properties permissions tests', () => {
-  let alice: IKeyringPair;
-  let bob: IKeyringPair;
-  let charlie: IKeyringPair;
-
-  before(async function() {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
-
-      const donor = await privateKey({url: import.meta.url});
-      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
-    });
-  });
-
-  async function prepare(helper: UniqueHelper): Promise<UniqueRFToken> {
-    const collection = await helper.rft.mintCollection(alice);
-    const token = await collection.mintToken(alice, 100n);
-
-    await collection.addAdmin(alice, {Substrate: bob.address});
-    await collection.setTokenPropertyPermissions(alice, [{key: 'fractals', permission: {mutable: true, tokenOwner: true}}]);
-
-    return token;
-  }
-
-  itSub('Forbids adding token property with tokenOwner==true when signer doesn\'t have all pieces', async ({helper}) =>  {
-    const token = await prepare(helper);
-
-    await token.transfer(alice, {Substrate: charlie.address}, 33n);
-
-    await expect(token.setProperties(alice, [
-      {key: 'fractals', value: 'multiverse'},
-    ])).to.be.rejectedWith(/common\.NoPermission/);
-  });
-
-  itSub('Forbids mutating token property with tokenOwner==true when signer doesn\'t have all pieces', async ({helper}) =>  {
-    const token = await prepare(helper);
-
-    await expect(token.collection.setTokenPropertyPermissions(alice, [{key: 'fractals', permission: {mutable:true, tokenOwner: true}}]))
-      .to.be.fulfilled;
-
-    await expect(token.setProperties(alice, [
-      {key: 'fractals', value: 'multiverse'},
-    ])).to.be.fulfilled;
-
-    await token.transfer(alice, {Substrate: charlie.address}, 33n);
-
-    await expect(token.setProperties(alice, [
-      {key: 'fractals', value: 'want to rule the world'},
-    ])).to.be.rejectedWith(/common\.NoPermission/);
-  });
-
-  itSub('Forbids deleting token property with tokenOwner==true when signer doesn\'t have all pieces', async ({helper}) =>  {
-    const token = await prepare(helper);
-
-    await expect(token.setProperties(alice, [
-      {key: 'fractals', value: 'one headline - why believe it'},
-    ])).to.be.fulfilled;
-
-    await token.transfer(alice, {Substrate: charlie.address}, 33n);
-
-    await expect(token.deleteProperties(alice, ['fractals'])).
-      to.be.rejectedWith(/common\.NoPermission/);
-  });
-
-  itSub('Allows token property mutation with collectionOwner==true when admin doesn\'t have all pieces', async ({helper}) =>  {
-    const token = await prepare(helper);
-
-    await token.transfer(alice, {Substrate: charlie.address}, 33n);
-
-    await expect(token.collection.setTokenPropertyPermissions(alice, [{key: 'fractals', permission: {mutable:true, collectionAdmin: true}}]))
-      .to.be.fulfilled;
-
-    await expect(token.setProperties(alice, [
-      {key: 'fractals', value: 'multiverse'},
-    ])).to.be.fulfilled;
-  });
-});
deletedjs-packages/tests/nesting/unnest.test.tsdiffbeforeafterboth
--- a/js-packages/tests/nesting/unnest.test.ts
+++ /dev/null
@@ -1,325 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
-
-import type {IKeyringPair} from '@polkadot/types/types';
-import {expect, itSub, Pallets, usingPlaygrounds} from '../util/index.js';
-import {CrossAccountId, UniqueFTCollection, UniqueNFToken, UniqueRFToken} from '@unique/playgrounds/unique.js';
-
-describe('Integration Test: Unnesting', () => {
-  let alice: IKeyringPair;
-  let bob: IKeyringPair;
-  let charlie: IKeyringPair;
-
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 50n, 50n], donor);
-    });
-  });
-
-  itSub('NFT: allows the owner to successfully unnest a token', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
-    const targetToken = await collection.mintToken(alice);
-
-    // Create a nested token
-    const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
-
-    // Unnest
-    await expect(nestedToken.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}), 'while unnesting').to.be.fulfilled;
-    expect(await nestedToken.getOwner()).to.be.deep.equal({Substrate: alice.address});
-
-    // Nest and burn
-    await nestedToken.nest(alice, targetToken);
-    await expect(nestedToken.burnFrom(alice, targetToken.nestingAccount()), 'while burning').to.be.fulfilled;
-    await expect(nestedToken.getOwner()).to.be.rejected;
-  });
-
-  itSub('NativeFungible: allows the owner to successfully unnest a token', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
-    const targetToken = await collection.mintToken(alice);
-
-    const collectionFT = helper.ft.getCollectionObject(0);
-
-    // Nest
-    await collectionFT.transfer(alice, targetToken.nestingAccount(), 10n);
-    // Unnest
-    await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;
-
-    expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
-  });
-
-  itSub('Fungible: allows the owner to successfully unnest a token', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
-    const targetToken = await collection.mintToken(alice);
-
-    const collectionFT = await helper.ft.mintCollection(alice);
-
-    // Nest and unnest
-    await collectionFT.mint(alice, 10n, targetToken.nestingAccount());
-    await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;
-    expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(9n);
-    expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
-
-    // Nest and burn
-    await collectionFT.transfer(alice, targetToken.nestingAccount(), 5n);
-    await expect(collectionFT.burnTokensFrom(alice, targetToken.nestingAccount(), 6n), 'while burning').to.be.fulfilled;
-    expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(4n);
-    expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(0n);
-    expect(await targetToken.getChildren()).to.be.length(0);
-  });
-
-  itSub.ifWithPallets('ReFungible: allows the owner to successfully unnest a token', [Pallets.ReFungible], async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
-    const targetToken = await collection.mintToken(alice);
-
-    const collectionRFT = await helper.rft.mintCollection(alice);
-
-    // Nest and unnest
-    const token = await collectionRFT.mintToken(alice, 10n, targetToken.nestingAccount());
-    await expect(token.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;
-    expect(await token.getBalance({Substrate: alice.address})).to.be.equal(9n);
-    expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
-
-    // Nest and burn
-    await token.transfer(alice, targetToken.nestingAccount(), 5n);
-    await expect(token.burnFrom(alice, targetToken.nestingAccount(), 6n), 'while burning').to.be.fulfilled;
-    expect(await token.getBalance({Substrate: alice.address})).to.be.equal(4n);
-    expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(0n);
-    expect(await targetToken.getChildren()).to.be.length(0);
-  });
-
-  async function checkNestedAmountState({
-    expectedBalance,
-    childrenShouldPresent,
-    nested,
-    targetNft,
-  }: {
-    expectedBalance: bigint,
-    childrenShouldPresent: boolean,
-    nested: UniqueFTCollection | UniqueRFToken,
-    targetNft: UniqueNFToken,
-  }) {
-    const balance = await nested.getBalance(targetNft.nestingAccount());
-    expect(balance).to.be.equal(expectedBalance);
-
-    const children = await targetNft.getChildren();
-
-    if(childrenShouldPresent) {
-      expect(children[0]).to.be.deep.equal({
-        collectionId: nested.collectionId,
-        tokenId: (nested instanceof UniqueFTCollection) ? 0 : nested.tokenId,
-      });
-    } else {
-      expect(children.length).to.be.equal(0);
-    }
-  }
-
-  function ownerOrAdminUnnestCases(modes: ('ft' | 'nft' | 'rft')[]): {
-    mode: 'ft' | 'nft' | 'rft',
-    sender: string,
-    op: 'transfer' | 'burn',
-    requiredPallets: Pallets[],
-  }[] {
-    const senders = ['owner', 'admin'];
-    const ops = ['transfer', 'burn'];
-
-    const cases = [];
-    for(const mode of modes) {
-      const requiredPallets = (mode === 'rft')
-        ? [Pallets.ReFungible]
-        : [];
-
-      for(const sender of senders) {
-        for(const op of ops) {
-          cases.push({
-            mode: mode as 'ft' | 'nft' | 'rft',
-            sender,
-            op: op as 'transfer' | 'burn',
-            requiredPallets,
-          });
-        }
-      }
-    }
-
-    return cases;
-  }
-
-  ownerOrAdminUnnestCases(['ft', 'rft']).map(testCase =>
-    itSub.ifWithPallets(`[${testCase.mode}]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, testCase.requiredPallets, async({helper}) => {
-      const owner = alice;
-      const admin = bob;
-
-      const unnester = (testCase.sender === 'owner')
-        ? owner
-        : admin;
-
-      const collectionNFT = await helper.nft.mintCollection(owner);
-      await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});
-
-      const collectionNested = await helper[testCase.mode as 'ft' | 'rft'].mintCollection(owner, {
-        limits: {
-          ownerCanTransfer: true,
-        },
-      });
-      await collectionNested.addAdmin(owner, {Substrate: admin.address});
-
-      const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});
-
-      let nested: UniqueFTCollection | UniqueRFToken;
-      const totalAmount = 5n;
-      const firstUnnestAmount = 2n;
-      const restUnnestAmount = totalAmount - firstUnnestAmount;
-
-      if(collectionNested instanceof UniqueFTCollection) {
-        await collectionNested.mint(owner, totalAmount, {Substrate: charlie.address});
-        nested = collectionNested;
-      } else {
-        nested = await collectionNested.mintToken(owner, totalAmount, {Substrate: charlie.address});
-      }
-
-      // transfer/burn `amount` of nested assets by `unnester`.
-      const doOperationAndCheck = async ({
-        amount,
-        shouldBeNestedAfterOp,
-      }: {
-        amount: bigint,
-        shouldBeNestedAfterOp: boolean,
-      }) => {
-        const nestedBalanceBeforeOp = await nested.getBalance(targetNft.nestingAccount());
-
-        if(testCase.op === 'transfer') {
-          const bobBalanceBeforeOp = await nested.getBalance({Substrate: bob.address});
-
-          await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address}, amount);
-          expect(await nested.getBalance({Substrate: bob.address})).to.be.equal(bobBalanceBeforeOp + amount);
-        } else {
-          if(nested instanceof UniqueFTCollection) {
-            await nested.burnTokensFrom(unnester, targetNft.nestingAccount(), amount);
-          } else {
-            await nested.burnFrom(unnester, targetNft.nestingAccount(), amount);
-          }
-        }
-
-        await checkNestedAmountState({
-          expectedBalance: nestedBalanceBeforeOp - amount,
-          childrenShouldPresent: shouldBeNestedAfterOp,
-          nested,
-          targetNft,
-        });
-      };
-
-      // Initial setup: nest (fungibles/rft parts).
-      // Check NFT's balance of nested assets and NFT's children.
-      await nested.transfer(charlie, targetNft.nestingAccount(), totalAmount);
-      await checkNestedAmountState({
-        expectedBalance: totalAmount,
-        childrenShouldPresent: true,
-        nested,
-        targetNft,
-      });
-
-      // Transfer/burn only a part of nested assets.
-      // Check that NFT's balance of the nested assets correctly decreased and NFT's children are not changed.
-      await doOperationAndCheck({
-        amount: firstUnnestAmount,
-        shouldBeNestedAfterOp: true,
-      });
-
-      // Transfer/burn all remaining nested assets.
-      // Check that NFT's balance of the nested assets is 0 and NFT has no more children.
-      await doOperationAndCheck({
-        amount: restUnnestAmount,
-        shouldBeNestedAfterOp: false,
-      });
-    }));
-
-  ownerOrAdminUnnestCases(['nft']).map(testCase =>
-    itSub(`[nft]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, async ({helper}) => {
-      const owner = alice;
-      const admin = bob;
-
-      const unnester = (testCase.sender === 'owner')
-        ? owner
-        : admin;
-
-      const collectionNFT = await helper.nft.mintCollection(owner);
-      await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});
-
-      const collectionNested = await helper.nft.mintCollection(owner, {
-        limits: {
-          ownerCanTransfer: true,
-        },
-      });
-      await collectionNested.addAdmin(owner, {Substrate: admin.address});
-
-      const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});
-      const nested = await collectionNested.mintToken(owner, {Substrate: charlie.address});
-
-      await nested.transfer(charlie, targetNft.nestingAccount());
-      expect(await targetNft.getChildren()).to.be.deep.equal([{
-        collectionId: nested.collectionId,
-        tokenId: nested.tokenId,
-      }]);
-
-      if(testCase.op === 'transfer') {
-        await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address});
-      } else {
-        await nested.burnFrom(unnester, targetNft.nestingAccount());
-      }
-
-      expect((await targetNft.getChildren()).length).to.be.equal(0);
-    }));
-});
-
-describe('Negative Test: Unnesting', () => {
-  let alice: IKeyringPair;
-  let bob: IKeyringPair;
-
-  before(async () => {
-    await usingPlaygrounds(async (helper, privateKey) => {
-      const donor = await privateKey({url: import.meta.url});
-      [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
-    });
-  });
-
-  itSub('Disallows a non-owner to unnest/burn a token', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
-    const targetToken = await collection.mintToken(alice);
-
-    // Create a nested token
-    const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
-
-    // Try to unnest
-    await expect(nestedToken.unnest(bob, targetToken, {Substrate: alice.address})).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
-    expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
-
-    // Try to burn
-    await expect(nestedToken.burnFrom(bob, targetToken.nestingAccount())).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
-    expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
-  });
-
-  // todo another test for creating excessive depth matryoshka with Ethereum?
-
-  // Recursive nesting
-  itSub('Prevents Ouroboros creation', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
-    const targetToken = await collection.mintToken(alice);
-
-    // Fail to create a nested token ouroboros
-    const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
-    await expect(targetToken.nest(alice, nestedToken)).to.be.rejectedWith(/^structure\.OuroborosDetected$/);
-  });
-});
modifiedjs-packages/tests/package.jsondiffbeforeafterboth
--- a/js-packages/tests/package.json
+++ b/js-packages/tests/package.json
@@ -21,8 +21,9 @@
         "test": "yarn _test './**/*.*test.ts'",
         "testParallel": "yarn _testParallel './**/*.test.ts'",
         "testSequential": "yarn _test './**/*.seqtest.ts'",
-        "testGovernance": "RUN_GOV_TESTS=1 yarn _test ./**/governance/*.*test.ts",
-        "testCollators": "RUN_COLLATOR_TESTS=1 yarn _test ./**/collator-selection/**.*test.ts --timeout 49999999",
+        "testEth": "yarn _test ./**/eth/*.*test.ts",
+        "testGovernance": "RUN_GOV_TESTS=1 yarn _test ./**/sub/governance/*.*test.ts",
+        "testCollators": "RUN_COLLATOR_TESTS=1 yarn _test ./**/sub/collator-selection/**.*test.ts --timeout 49999999",
         "testFullXcmUnique": "RUN_XCM_TESTS=1 yarn _test ./**/xcm/*Unique.test.ts",
         "testFullXcmQuartz": "RUN_XCM_TESTS=1 yarn _test ./**/xcm/*Quartz.test.ts",
         "testXcmOpal": "RUN_XCM_TESTS=1 yarn _test ./**/xcm/xcmOpal.test.ts",
modifiedjs-packages/tests/scheduler.seqtest.tsdiffbeforeafterboth
--- a/js-packages/tests/scheduler.seqtest.ts
+++ b/js-packages/tests/scheduler.seqtest.ts
@@ -507,7 +507,7 @@
     for(let offset = 0; offset < numFilledBlocks; offset ++) {
       for(let i = 0; i < maxScheduledPerBlock; i++) {
 
-        const scheduledTx = helper.constructApiCall('api.tx.balances.transfer', [bob.address, 1n]);
+        const scheduledTx = helper.constructApiCall('api.tx.balances.transferKeepAlive', [bob.address, 1n]);
 
         const when = firstExecutionBlockNumber + period + offset;
         const mandatoryArgs = [when, null, null, scheduledTx];
@@ -710,7 +710,7 @@
     //   await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address);
 
     //   // Grace zeroBalance with money, enough to cover future transactions
-    //   const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);
+    //   const balanceTx = api.tx.balances.transferKeepAlive(zeroBalance.address, 1n * UNIQUE);
     //   await submitTransactionAsync(alice, balanceTx);
 
     //   // Mint a fresh NFT
@@ -722,7 +722,7 @@
     //   await scheduleTransferExpectSuccess(api, collectionId, tokenId, zeroBalance, alice, 1, waitForBlocks, scheduledId);
 
     //   // Get rid of the account's funds before the scheduled transaction takes place
-    //   const balanceTx2 = api.tx.balances.transfer(alice.address, UNIQUE * 68n / 100n);
+    //   const balanceTx2 = api.tx.balances.transferKeepAlive(alice.address, UNIQUE * 68n / 100n);
     //   const events = await submitTransactionAsync(zeroBalance, balanceTx2);
     //   expect(getGenericResult(events).success).to.be.true;
     //   /*const emptyBalanceTx = api.tx.balances.setBalance(zeroBalance.address, 0, 0); // do not null reserved?
@@ -742,7 +742,7 @@
 
     // await usingApi(async (api, privateKey) => {
     //   const zeroBalance = await findUnusedAddress(api, privateKey);
-    //   const balanceTx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE);
+    //   const balanceTx = api.tx.balances.transferKeepAlive(zeroBalance.address, 1n * UNIQUE);
     //   await submitTransactionAsync(alice, balanceTx);
 
     //   await setCollectionSponsorExpectSuccess(collectionId, zeroBalance.address);
addedjs-packages/tests/sub/check-event/burnItemEvent.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/check-event/burnItemEvent.test.ts
@@ -0,0 +1,44 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub} from '../../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+
+describe('Burn Item event ', () => {
+  let alice: IKeyringPair;
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice] = await helper.arrange.createAccounts([10n], donor);
+    });
+  });
+  itSub('Check event from burnItem(): ', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+    const token = await collection.mintToken(alice, {Substrate: alice.address});
+    await token.burn(alice);
+    await helper.wait.newBlocks(1);
+
+    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+    const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+    expect(eventStrings).to.contains('common.ItemDestroyed');
+    expect(eventStrings).to.contains('treasury.Deposit');
+    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+  });
+});
addedjs-packages/tests/sub/check-event/createCollectionEvent.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/check-event/createCollectionEvent.test.ts
@@ -0,0 +1,40 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect} from '../../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+describe('Create collection event ', () => {
+  let alice: IKeyringPair;
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice] = await helper.arrange.createAccounts([10n], donor);
+    });
+  });
+  itSub('Check event from createCollection(): ', async ({helper}) => {
+    await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+    await helper.wait.newBlocks(1);
+    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+    const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+    expect(eventStrings).to.contains('common.CollectionCreated');
+    expect(eventStrings).to.contains('treasury.Deposit');
+    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+  });
+});
addedjs-packages/tests/sub/check-event/createItemEvent.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/check-event/createItemEvent.test.ts
@@ -0,0 +1,41 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect} from '../../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+describe('Create Item event ', () => {
+  let alice: IKeyringPair;
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice] = await helper.arrange.createAccounts([10n], donor);
+    });
+  });
+  itSub('Check event from createItem(): ', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+    await collection.mintToken(alice, {Substrate: alice.address});
+    await helper.wait.newBlocks(1);
+    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+    const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+    expect(eventStrings).to.contains('common.ItemCreated');
+    expect(eventStrings).to.contains('treasury.Deposit');
+    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+  });
+});
addedjs-packages/tests/sub/check-event/createMultipleItemsEvent.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/check-event/createMultipleItemsEvent.test.ts
@@ -0,0 +1,46 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect} from '../../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+describe('Create Multiple Items Event event ', () => {
+  let alice: IKeyringPair;
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice] = await helper.arrange.createAccounts([10n], donor);
+    });
+  });
+  itSub('Check event from createMultipleItems(): ', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+
+    await collection.mintMultipleTokens(alice, [
+      {owner: {Substrate: alice.address}},
+      {owner: {Substrate: alice.address}},
+    ]);
+
+    await helper.wait.newBlocks(1);
+    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+    const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+    expect(eventStrings).to.contains('common.ItemCreated');
+    expect(eventStrings).to.contains('treasury.Deposit');
+    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+  });
+});
addedjs-packages/tests/sub/check-event/destroyCollectionEvent.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/check-event/destroyCollectionEvent.test.ts
@@ -0,0 +1,42 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, usingPlaygrounds, expect} from '../../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+describe('Destroy collection event ', () => {
+  let alice: IKeyringPair;
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice] = await helper.arrange.createAccounts([10n], donor);
+    });
+  });
+
+  itSub('Check event from destroyCollection(): ', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+    await collection.burn(alice);
+    await helper.wait.newBlocks(1);
+    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+    const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+    expect(eventStrings).to.contains('common.CollectionDestroyed');
+    expect(eventStrings).to.contains('treasury.Deposit');
+    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+  });
+});
addedjs-packages/tests/sub/check-event/transferEvent.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/check-event/transferEvent.test.ts
@@ -0,0 +1,45 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub} from '../../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+describe('Transfer event ', () => {
+  let alice: IKeyringPair;
+  let bob: IKeyringPair;
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
+    });
+  });
+
+  itSub('Check event from transfer(): ', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+    const token = await collection.mintToken(alice, {Substrate: alice.address});
+    await token.transfer(alice, {Substrate: bob.address});
+    await helper.wait.newBlocks(1);
+    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+    const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+    expect(eventStrings).to.contains('common.Transfer');
+    expect(eventStrings).to.contains('treasury.Deposit');
+    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+  });
+});
addedjs-packages/tests/sub/check-event/transferFromEvent.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/check-event/transferFromEvent.test.ts
@@ -0,0 +1,44 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub} from '../../util/index.js';
+import type {IEvent} from '@unique/playgrounds/types.js';
+
+describe('Transfer event ', () => {
+  let alice: IKeyringPair;
+  let bob: IKeyringPair;
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
+    });
+  });
+
+  itSub('Check event from transfer(): ', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+    const token = await collection.mintToken(alice, {Substrate: alice.address});
+    await token.transferFrom(alice, {Substrate: alice.address}, {Substrate: bob.address});
+    await helper.wait.newBlocks(1);
+    const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
+    const eventStrings = event.map(e => `${e.section}.${e.method}`);
+
+    expect(eventStrings).to.contains('common.Transfer');
+    expect(eventStrings).to.contains('treasury.Deposit');
+    expect(eventStrings).to.contains('system.ExtrinsicSuccess');
+  });
+});
addedjs-packages/tests/sub/collator-selection/collatorSelection.seqtest.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/collator-selection/collatorSelection.seqtest.ts
@@ -0,0 +1,423 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from '../../util/index.js';
+
+async function nodeAddress(name: string) {
+  // eslint-disable-next-line require-await
+  return await usingPlaygrounds(async (helper) => {
+    const envNodeStash = `RELAY_UNIQUE_NODE_${name.toUpperCase()}_STASH`;
+
+    const nodeStash = process.env[envNodeStash];
+    if(nodeStash) {
+      return helper.address.normalizeSubstrateToChainFormat(nodeStash);
+    } else {
+      throw Error(`"${envNodeStash}" env var is not set`);
+    }
+  });
+}
+
+async function getInitialInvulnerables() {
+  return await Promise.all([
+    nodeAddress('alpha'),
+    nodeAddress('beta'),
+    nodeAddress('gamma'),
+    nodeAddress('delta'),
+  ]);
+}
+
+async function resetInvulnerables() {
+  await usingPlaygrounds(async (helper, privateKey) => {
+    const superuser = await privateKey('//Alice');
+    const initialInvulnerables = await getInitialInvulnerables();
+
+    const invulnerables = await helper.collatorSelection.getInvulnerables();
+
+    // Remove all invulnerables but the first one
+    const firstInvulnerable = invulnerables[0];
+
+    let nonce = await helper.chain.getNonce(superuser.address);
+    await Promise.all(invulnerables.slice(1).map(invulnerable => helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [invulnerable], true, {nonce: nonce++})));
+
+    // Add the initial invulnerables
+    await Promise.all(initialInvulnerables.map(invulnerable => helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [invulnerable], true, {nonce: nonce++})));
+
+    // Remove the first invulnerable if it's not an initial one
+    if(!initialInvulnerables.includes(firstInvulnerable)) {
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [firstInvulnerable]);
+    }
+  });
+}
+
+// todo:collator Most preferable to launch this test in parallel somehow -- or change the session period (1 hr).
+describe('Integration Test: Collator Selection', () => {
+  let superuser: IKeyringPair;
+  let previousLicenseBond = 0n;
+  let licenseBond = 0n;
+
+  before(async function() {
+    if(!process.env.RUN_COLLATOR_TESTS) this.skip();
+
+    await usingPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.CollatorSelection]);
+      superuser = await privateKey('//Alice');
+
+      previousLicenseBond = await helper.collatorSelection.getLicenseBond();
+      licenseBond = 10n * helper.balance.getOneTokenNominal();
+      await helper.getSudo().collatorSelection.setLicenseBond(superuser, licenseBond);
+    });
+  });
+
+  describe('Dynamic shuffling of collators', () => {
+    // These two are the default invulnerables, and should return to be invulnerables after this suite.
+    let alphaNode: string;
+    let betaNode: string;
+
+    let gammaNode: string;
+    let deltaNode: string;
+
+    before(async function() {
+      await usingPlaygrounds(async (helper) => {
+        // todo:collator see again if blocks start to be finalized in dev mode
+        // Skip the collator block production in dev mode, since the blocks are sealed automatically.
+        if(await helper.arrange.isDevNode()) this.skip();
+
+        [alphaNode, betaNode, gammaNode, deltaNode] = await getInitialInvulnerables();
+
+        const invulnerables = await helper.collatorSelection.getInvulnerables();
+        expect(invulnerables.length, 'Invalid initial invulnerables number').to.be.equal(4);
+        expect(invulnerables, 'Invalid initial invulnerables').containSubset([alphaNode, betaNode, gammaNode, deltaNode]);
+      });
+    });
+
+    itSub('Change invulnerables and make sure they start producing blocks', async ({helper}) => {
+      let nonce = await helper.chain.getNonce(superuser.address);
+
+      nonce = await helper.chain.getNonce(superuser.address);
+      await expect(Promise.all([
+        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [alphaNode], true, {nonce: nonce++}),
+        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [betaNode], true, {nonce: nonce++}),
+      ])).to.be.fulfilled;
+
+      const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+      expect(newInvulnerables).to.contain(gammaNode).and.contain(deltaNode).and.be.length(2);
+
+      await helper.wait.newSessions(2);
+
+      const newValidators = await helper.callRpc('api.query.session.validators');
+      expect(newValidators).to.contain(gammaNode).and.contain(deltaNode).and.be.length(2);
+
+      const lastBlockNumber = await helper.chain.getLatestBlockNumber();
+      await helper.wait.newBlocks(1);
+      const lastGammaBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [gammaNode])).toNumber();
+      const lastDeltaBlock = (await helper.callRpc('api.query.collatorSelection.lastAuthoredBlock', [deltaNode])).toNumber();
+      expect(lastGammaBlock >= lastBlockNumber || lastDeltaBlock >= lastBlockNumber).to.be.true;
+    });
+
+    after(async () => {
+      await resetInvulnerables();
+    });
+  });
+
+  describe('Getting and releasing licenses to collate', () => {
+    let crowd: IKeyringPair[];
+
+    before(async function() {
+      await usingPlaygrounds(async (helper) => {
+        crowd = await helper.arrange.createCrowd(20, 100n, superuser);
+
+        // set session keys for everyone
+        await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));
+      });
+    });
+
+    describe('Positive', () => {
+      itSub('Can lease and release a license', async ({helper}) => {
+        const account = crowd.pop()!;
+
+        // make sure it does not have any reserved funds
+        expect((await helper.balance.getSubstrateFull(account.address)).reserved).to.be.equal(0n);
+
+        // getting a license reserves a license bond cost
+        await helper.collatorSelection.obtainLicense(account);
+        expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(licenseBond);
+        expect((await helper.balance.getSubstrateFull(account.address)).reserved).to.be.equal(licenseBond);
+
+        // releasing a license un-reserves the license bond cost
+        await helper.collatorSelection.releaseLicense(account);
+        expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(0n);
+
+        const balance = await helper.balance.getSubstrateFull(account.address);
+        expect(balance.reserved).to.be.equal(0n);
+        expect(balance.free > 100n - licenseBond);
+      });
+
+      itSub('Can force revoke a license', async ({helper}) => {
+        const account = crowd.pop()!;
+
+        // getting a license reserves a license bond cost
+        const previousBalance = await helper.balance.getSubstrateFull(account.address);
+        await helper.collatorSelection.obtainLicense(account);
+        expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(licenseBond);
+
+        // force-releasing a license un-reserves the license bond cost as well
+        await helper.getSudo().collatorSelection.forceReleaseLicense(superuser, account.address);
+        expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(previousBalance.reserved);
+
+        const balance = await helper.balance.getSubstrateFull(account.address);
+        expect(balance.reserved).to.be.equal(previousBalance.reserved);
+        expect(balance.free > previousBalance.free - licenseBond);
+      });
+    });
+
+    describe('Negative', () => {
+      itSub('Cannot get a license without session keys set', async ({helper}) => {
+        const [account] = await helper.arrange.createAccounts([100n], superuser);
+        await expect(helper.collatorSelection.obtainLicense(account))
+          .to.be.rejectedWith(/collatorSelection.ValidatorNotRegistered/);
+      });
+
+      itSub('Cannot register a license twice', async ({helper}) => {
+        const account = crowd.pop()!;
+        await helper.collatorSelection.obtainLicense(account);
+        await expect(helper.collatorSelection.obtainLicense(account))
+          .to.be.rejectedWith(/collatorSelection.AlreadyHoldingLicense/);
+      });
+
+      itSub('Cannot release a license twice', async ({helper}) => {
+        const account = crowd.pop()!;
+        await helper.collatorSelection.obtainLicense(account);
+        await helper.collatorSelection.releaseLicense(account);
+        await expect(helper.collatorSelection.releaseLicense(account))
+          .to.be.rejectedWith(/collatorSelection.NoLicense/);
+      });
+
+      itSub('Cannot force revoke a license as non-sudo', async ({helper}) => {
+        const account = crowd.pop()!;
+        await helper.collatorSelection.obtainLicense(account);
+        await expect(helper.collatorSelection.forceReleaseLicense(superuser, account.address))
+          .to.be.rejectedWith(/BadOrigin/);
+      });
+    });
+  });
+
+  describe('Onboarding, collating, and offboarding as collator candidates', () => {
+    let crowd: IKeyringPair[];
+
+    before(async function() {
+      await usingPlaygrounds(async (helper) => {
+        crowd = await helper.arrange.createCrowd(20, 100n, superuser);
+
+        // set session keys for everyone
+        await Promise.all(crowd.map(acc => helper.session.setOwnKeysFromAddress(acc)));
+      });
+    });
+
+    describe('Positive', () => {
+      itSub('Can onboard and offboard repeatedly', async ({helper}) => {
+        const account = crowd.pop()!;
+        await helper.collatorSelection.obtainLicense(account);
+        await helper.collatorSelection.onboard(account);
+        expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([account.address]);
+
+        await helper.collatorSelection.offboard(account);
+        expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([]);
+
+        await helper.collatorSelection.onboard(account);
+        expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([account.address]);
+
+        await helper.collatorSelection.offboard(account);
+        expect(await helper.collatorSelection.getCandidates()).to.be.deep.equal([]);
+      });
+
+      itSub('Penalizes and forfeits license from faulty collators', async ({helper}) => {
+        // This one shouldn't even be able to produce blocks.
+        const account = crowd.pop()!;
+        await helper.collatorSelection.obtainLicense(account);
+        await helper.collatorSelection.onboard(account);
+        expect(await helper.collatorSelection.getCandidates()).to.contain(account.address);
+
+        // Wait for 3 new sessions before checking that the collator will be kicked:
+        // one to get collator onboarded, and another two for the collator to fail
+        await helper.wait.newSessions(3);
+
+        expect(await helper.collatorSelection.getCandidates()).to.not.contain(account.address);
+        expect(await helper.collatorSelection.hasLicense(account.address)).to.be.equal(0n);
+
+        // The account's reserved funds get slashed as a penalty
+        const balance = await helper.balance.getSubstrateFull(account.address);
+        expect(balance.reserved).to.be.equal(0n);
+        expect(balance.free < 100n - licenseBond);
+      });
+    });
+
+    describe('Negative', () => {
+      itSub('Cannot onboard without a license', async ({helper}) => {
+        const account = crowd.pop()!;
+        await expect(helper.collatorSelection.onboard(account))
+          .to.be.rejectedWith(/collatorSelection.NoLicense/);
+      });
+
+      itSub('Cannot offboard without a license', async ({helper}) => {
+        const account = crowd.pop()!;
+        await expect(helper.collatorSelection.offboard(account))
+          .to.be.rejectedWith(/collatorSelection.NotCandidate/);
+      });
+
+      itSub('Cannot offboard while not onboarded', async ({helper}) => {
+        const account = crowd.pop()!;
+        await helper.collatorSelection.obtainLicense(account);
+        await expect(helper.collatorSelection.offboard(account))
+          .to.be.rejectedWith(/collatorSelection.NotCandidate/);
+      });
+
+      itSub('Cannot onboard while already onboarded', async ({helper}) => {
+        const account = crowd.pop()!;
+        await helper.collatorSelection.obtainLicense(account);
+        await helper.collatorSelection.onboard(account);
+        await expect(helper.collatorSelection.onboard(account))
+          .to.be.rejectedWith(/collatorSelection.AlreadyCandidate/);
+      });
+    });
+  });
+
+  describe('Addition and removal of invulnerables', () => {
+    describe('Positive', () => {
+      itSub('Adds an invulnerable', async ({helper}) => {
+        const [account] = await helper.arrange.createAccounts([10n], superuser);
+        const invulnerables = await helper.collatorSelection.getInvulnerables();
+
+        await helper.session.setOwnKeysFromAddress(account);
+        await helper.getSudo().collatorSelection.addInvulnerable(superuser, account.address);
+
+        const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+        expect(invulnerables.concat(account.address)).to.have.all.members(newInvulnerables);
+      });
+
+      itSub('Removes an invulnerable', async ({helper}) => {
+        const invulnerables = await helper.collatorSelection.getInvulnerables();
+        const lastInvulnerable = invulnerables.pop()!;
+
+        await helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable);
+        const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+        // invulnerables had its last element removed, so they should be equal
+        expect(newInvulnerables).to.have.all.members(invulnerables);
+      });
+    });
+
+    describe('Negative', () => {
+      itSub('Does not duplicate an invulnerable', async ({helper}) => {
+        const invulnerables = await helper.collatorSelection.getInvulnerables();
+        // adding an already invulnerable should not fail, but should not duplicate it either
+        await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, invulnerables[0]))
+          .to.be.fulfilled;
+        const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+        expect(newInvulnerables).to.have.all.members(invulnerables);
+      });
+
+      itSub('Cannot remove a non-existent invulnerable', async ({helper}) => {
+        const [account] = await helper.arrange.createAccounts([0n], superuser);
+        await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, account.address))
+          .to.be.rejectedWith(/collatorSelection.NotInvulnerable/);
+      });
+
+      itSub('Cannot allow invulnerables to be empty', async ({helper}) => {
+        const invulnerables = await helper.collatorSelection.getInvulnerables();
+        const lastInvulnerable = invulnerables.pop()!;
+
+        let nonce = await helper.chain.getNonce(superuser.address);
+        await Promise.all(invulnerables.map((i: any) =>
+          helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i], true, {nonce: nonce++})));
+
+        await expect(helper.getSudo().collatorSelection.removeInvulnerable(superuser, lastInvulnerable))
+          .to.be.rejectedWith(/collatorSelection.TooFewInvulnerables/);
+
+        const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+        expect(newInvulnerables).to.be.deep.equal([lastInvulnerable]);
+
+        // restore the invulnerables to the previous state
+        nonce = await helper.chain.getNonce(superuser.address);
+        await Promise.all(invulnerables.map((i: any) =>
+          helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i], true, {nonce: nonce++})));
+      });
+
+      itSub('Cannot have too many invulnerables', async ({helper}) => {
+        // todo:collator make sure that there is enough session time for a set of tests
+        // 28 non-functioning collators, teehee.
+
+        const invulnerablesLength = (await helper.collatorSelection.getInvulnerables()).length;
+        const invulnerablesUntilLimit = (await helper.collatorSelection.getDesiredCollators()) - invulnerablesLength;
+        const newInvulnerables = await helper.arrange.createAccounts(Array(invulnerablesUntilLimit).fill(10n), superuser);
+        const [lastInvulnerable] = await helper.arrange.createAccounts([10n], superuser);
+
+        await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
+          helper.session.setOwnKeysFromAddress(i)));
+        await helper.session.setOwnKeysFromAddress(lastInvulnerable);
+
+        let nonce = await helper.chain.getNonce(superuser.address);
+        await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
+          helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.addInvulnerable', [i.address], true, {nonce: nonce++})));
+
+        await expect(helper.getSudo().collatorSelection.addInvulnerable(superuser, lastInvulnerable.address))
+          .to.be.rejectedWith(/collatorSelection.TooManyInvulnerables/);
+
+        // restore the invulnerables to the previous state
+        nonce = await helper.chain.getNonce(superuser.address);
+        await Promise.all(newInvulnerables.map((i: IKeyringPair) =>
+          helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.removeInvulnerable', [i.address], true, {nonce: nonce++})));
+      });
+
+      itSub('Forbids a non-sudo to add an invulnerable', async ({helper}) => {
+        const [account] = await helper.arrange.createAccounts([10n], superuser);
+        const invulnerables = await helper.collatorSelection.getInvulnerables();
+
+        await helper.session.setOwnKeysFromAddress(account);
+        await expect(helper.collatorSelection.addInvulnerable(superuser, account.address))
+          .to.be.rejectedWith(/BadOrigin/);
+
+        const newInvulnerables = await helper.collatorSelection.getInvulnerables();
+        expect(newInvulnerables).to.be.members(invulnerables);
+      });
+
+      itSub('Forbids a non-sudo to remove an invulnerable', async ({helper}) => {
+        const invulnerables = await helper.collatorSelection.getInvulnerables();
+        await expect(helper.collatorSelection.removeInvulnerable(superuser, invulnerables[0]))
+          .to.be.rejectedWith(/BadOrigin/);
+        expect(await helper.collatorSelection.getInvulnerables()).to.have.all.members(invulnerables);
+      });
+
+      after(async function() {
+        await resetInvulnerables();
+      });
+    });
+  });
+
+  after(async function() {
+    if(!process.env.RUN_COLLATOR_TESTS) return;
+
+    await usingPlaygrounds(async (helper) => {
+      if(helper.fetchMissingPalletNames([Pallets.CollatorSelection]).length != 0) return;
+
+      await helper.getSudo().collatorSelection.setLicenseBond(superuser, previousLicenseBond);
+
+      const candidates = await helper.collatorSelection.getCandidates();
+      let nonce = await helper.chain.getNonce(superuser.address);
+      await Promise.all(candidates.map(candidate =>
+        helper.getSudo().executeExtrinsic(superuser, 'api.tx.collatorSelection.forceReleaseLicense', [candidate], true, {nonce: nonce++})));
+    });
+  });
+});
addedjs-packages/tests/sub/collator-selection/identity.seqtest.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/collator-selection/identity.seqtest.ts
@@ -0,0 +1,284 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, expect, itSub, Pallets, requirePalletsOrSkip} from '../../util/index.js';
+import {UniqueHelper} from '@unique/playgrounds/unique.js';
+
+async function getIdentities(helper: UniqueHelper) {
+  const identities: [string, any][] = [];
+  for(const [key, value] of await helper.getApi().query.identity.identityOf.entries())
+    identities.push([(key as any).toHuman(), (value as any).unwrap()]);
+  return identities;
+}
+
+async function getIdentityAccounts(helper: UniqueHelper) {
+  return (await getIdentities(helper)).flatMap(([key, _value]) => key);
+}
+
+async function getSubIdentityAccounts(helper: UniqueHelper, address: string) {
+  return ((await helper.getApi().query.identity.subsOf(address)).toHuman() as any)[1];
+}
+
+async function getSubIdentityName(helper: UniqueHelper, address: string) {
+  return ((await helper.getApi().query.identity.superOf(address)).toHuman() as any);
+}
+
+describe('Integration Test: Identities Manipulation', () => {
+  let superuser: IKeyringPair;
+
+  before(async function() {
+    if(!process.env.RUN_COLLATOR_TESTS) this.skip();
+
+    await usingPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.Identity]);
+      superuser = await privateKey('//Alice');
+    });
+  });
+
+  itSub('Normal calls do not work', async ({helper}) => {
+    // console.error = () => {};
+    await expect(helper.executeExtrinsic(superuser, 'api.tx.identity.setIdentity', [{info: {display: {Raw: 'Meowser'}}}] as any))
+      .to.be.rejectedWith(/Transaction call is not expected/);
+  });
+
+  describe('Identities', () => {
+    itSub('Sets identities', async ({helper}) => {
+      const oldIdentitiesCount = (await getIdentityAccounts(helper)).length;
+
+      const crowdSize = 10;
+      const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
+      const identities = crowd.map((acc, i) => [acc.address, {info: {display: {Raw: `accounter #${i}`}}}]);
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
+
+      expect((await getIdentityAccounts(helper)).length).to.be.equal(oldIdentitiesCount + crowdSize);
+    });
+
+    itSub('Setting identities does not delete existing but does overwrite', async ({helper}) => {
+      const crowd = await helper.arrange.createCrowd(10, 0n, superuser);
+      const identities = crowd.map((acc, i) => [acc.address, {info: {display: {Raw: `accounter #${i}`}}}]);
+
+      // insert a single identity
+      let singleIdentity = identities.pop()!;
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [[singleIdentity]] as any);
+
+      const oldIdentitiesCount = (await getIdentityAccounts(helper)).length;
+
+      // change an identity and push it with a few new others
+      singleIdentity = [singleIdentity[0], {info: {display: {Raw: 'something special'}}}];
+      identities.push(singleIdentity);
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
+
+      // oldIdentitiesCount + 9 because one identity is overwritten, not inserted on top
+      expect((await getIdentityAccounts(helper)).length).to.be.equal(oldIdentitiesCount + 9);
+      expect((await helper.callRpc('api.query.identity.identityOf', [singleIdentity[0]])).toHuman().info.display)
+        .to.be.deep.equal({Raw: 'something special'});
+    });
+
+    itSub('Removes identities', async ({helper}) => {
+      const crowd = await helper.arrange.createCrowd(10, 0n, superuser);
+      const identities = crowd.map((acc, i) => [acc.address, {info: {display: {Raw: `accounter #${i}`}}}]);
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
+      const oldIdentities = await getIdentityAccounts(helper);
+
+      // delete a couple, check that they are no longer there
+      const scapegoats = [crowd.pop()!.address, crowd.pop()!.address];
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceRemoveIdentities', [scapegoats]);
+      const newIdentities = await getIdentityAccounts(helper);
+      expect(newIdentities.concat(scapegoats)).to.be.have.members(oldIdentities);
+    });
+  });
+
+  describe('Sub-identities', () => {
+    itSub('Sets subs', async ({helper}) => {
+      const crowdSize = 18;
+      const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
+      const supers = [crowd.pop()!, crowd.pop()!, crowd.pop()!];
+
+      const subsPerSup = crowd.length / supers.length;
+      let subCount = 0;
+      const subs = [
+        crowd.slice(subCount, subCount += subsPerSup + 1),
+        crowd.slice(subCount, subCount += subsPerSup),
+        crowd.slice(subCount, subCount += subsPerSup - 1),
+      ];
+
+      const subsInfo = supers.map((acc, i) => [
+        acc.address, [
+          1000000n + BigInt(i + 1),
+          subs[i].map((sub, j) => [
+            sub.address, {Raw: `accounter #${j}`},
+          ]),
+        ],
+      ]);
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo] as any);
+
+      for(let i = 0; i < supers.length; i++) {
+        // check deposit
+        expect(((await helper.getApi().query.identity.subsOf(supers[i].address)).toJSON() as any)[0]).to.be.equal(1000001 + i);
+
+        const subsAccounts = await getSubIdentityAccounts(helper, supers[i].address);
+        // check sub-identities as account ids
+        expect(subsAccounts).to.include.members(subs[i].map(x => x.address));
+
+        for(let j = 0; j < subsAccounts.length; j++) {
+          // check sub-identities' names
+          expect((await getSubIdentityName(helper, subsAccounts[j]))[1]).to.be.deep.equal({Raw: `accounter #${j}`});
+        }
+      }
+    });
+
+    itSub('Setting sub-identities does not delete other existing but does overwrite own', async ({helper}) => {
+      const crowdSize = 18;
+      const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
+      const supers = [crowd.pop()!, crowd.pop()!, crowd.pop()!];
+
+      const subsPerSup = crowd.length / supers.length;
+      let subCount = 0;
+      const subs = [
+        crowd.slice(subCount, subCount += subsPerSup + 1),
+        crowd.slice(subCount, subCount += subsPerSup),
+        crowd.slice(subCount, subCount += subsPerSup - 1),
+      ];
+
+      const subsInfo1 = supers.map((acc, i) => [
+        acc.address, [
+          1000000n + BigInt(i + 1),
+          subs[i].map((sub, j) => [
+            sub.address, {Raw: `accounter #${j}`},
+          ]),
+        ],
+      ]);
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo1] as any);
+
+      // change some sub-identities...
+      subs[2].pop(); subs[2].pop(); subs[2].push(...await helper.arrange.createAccounts([0n], superuser));
+
+      // ...and set them
+      const subsInfo2 = [[
+        supers[2].address, [
+          999999n,
+          subs[2].map((sub, j) => [
+            sub.address, {Raw: `discounter #${j}`},
+          ]),
+        ],
+      ]];
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo2] as any);
+
+      // make sure everything else is the same
+      for(let i = 0; i < supers.length - 1; i++) {
+        // check deposit
+        expect(((await helper.getApi().query.identity.subsOf(supers[i].address)).toJSON() as any)[0]).to.be.equal(1000001 + i);
+
+        const subsAccounts = await getSubIdentityAccounts(helper, supers[i].address);
+        // check sub-identities as account ids
+        expect(subsAccounts).to.include.members(subs[i].map(x => x.address));
+
+        for(let j = 0; j < subsAccounts; j++) {
+          // check sub-identities' names
+          expect((await getSubIdentityName(helper, subsAccounts[j]))[1]).to.be.deep.equal({Raw: `accounter #${j}`});
+        }
+      }
+
+      // check deposit
+      expect(((await helper.getApi().query.identity.subsOf(supers[2].address)).toJSON() as any)[0]).to.be.equal(999999);
+
+      const subsAccounts = await getSubIdentityAccounts(helper, supers[2].address);
+      // check sub-identities as account ids
+      expect(subsAccounts).to.include.members(subs[2].map(x => x.address));
+
+      for(let j = 0; j < subsAccounts.length; j++) {
+        // check sub-identities' names
+        expect((await getSubIdentityName(helper, subsAccounts[j]))[1]).to.be.deep.equal({Raw: `discounter #${j}`});
+      }
+    });
+
+    itSub('Removes sub-identities', async ({helper}) => {
+      const crowdSize = 3;
+      const crowd = await helper.arrange.createCrowd(crowdSize, 0n, superuser);
+      const sup = crowd.pop()!;
+
+      const subsInfo1 = [[
+        sup.address, [
+          1000000n,
+          crowd.map((sub, j) => [
+            sub.address, {Raw: `accounter #${j}`},
+          ]),
+        ],
+      ]];
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo1] as any);
+
+      // empty sub-identities should delete the records
+      const subsInfo2 = [[
+        sup.address, [
+          1000000n,
+          [],
+        ],
+      ]];
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo2] as any);
+
+      // check deposit
+      expect((await helper.getApi().query.identity.subsOf(sup.address)).toHuman()).to.be.deep.equal(['0', []]);
+
+      for(let j = 0; j < crowd.length; j++) {
+        // check sub-identities' names
+        expect((await getSubIdentityName(helper, crowd[j].address))).to.be.null;
+      }
+    });
+
+    itSub('Removing identities deletes associated sub-identities', async ({helper}) => {
+      const crowd = await helper.arrange.createCrowd(3, 0n, superuser);
+      const sup = crowd.pop()!;
+
+      // insert identity
+      const identities = [[sup.address, {info: {display: {Raw: 'mental'}}}]];
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceInsertIdentities', [identities] as any);
+
+      // and its sub-identities
+      const subsInfo = [[
+        sup.address, [
+          1000000n,
+          crowd.map((sub, j) => [
+            sub.address, {Raw: `accounter #${j}`},
+          ]),
+        ],
+      ]];
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceSetSubs', [subsInfo] as any);
+
+      // delete top identity
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceRemoveIdentities', [[sup.address]]);
+
+      // check that sub-identities are deleted
+      expect((await helper.getApi().query.identity.subsOf(sup.address)).toHuman()).to.be.deep.equal(['0', []]);
+
+      for(let j = 0; j < crowd.length; j++) {
+        // check sub-identities' names
+        expect((await getSubIdentityName(helper, crowd[j].address))).to.be.null;
+      }
+    });
+  });
+
+  after(async function() {
+    if(!process.env.RUN_COLLATOR_TESTS) return;
+
+    await usingPlaygrounds(async helper => {
+      if(helper.fetchMissingPalletNames([Pallets.Identity]).length != 0) return;
+
+      const identitiesToRemove: string[] = await getIdentityAccounts(helper);
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.identity.forceRemoveIdentities', [identitiesToRemove]);
+    });
+  });
+});
addedjs-packages/tests/sub/governance/council.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/governance/council.test.ts
@@ -0,0 +1,457 @@
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../../util/index.js';
+import {Event} from '@unique/playgrounds/unique.dev.js';
+import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, councilMotionDuration, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, initTechComm, clearFellowship, dummyProposal, dummyProposalCall, initFellowship, defaultEnactmentMoment, fellowshipPropositionOrigin} from './util.js';
+import type {ICounselors} from './util.js';
+
+describeGov('Governance: Council tests', () => {
+  let donor: IKeyringPair;
+  let counselors: ICounselors;
+  let sudoer: IKeyringPair;
+
+  const moreThanHalfCouncilThreshold = 3;
+
+  before(async function() {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.Council]);
+
+      donor = await privateKey({url: import.meta.url});
+      sudoer = await privateKey('//Alice');
+    });
+  });
+
+  beforeEach(async () => {
+    counselors = await initCouncil(donor, sudoer);
+  });
+
+  afterEach(async () => {
+    await clearCouncil(sudoer);
+    await clearTechComm(sudoer);
+  });
+
+  async function proposalFromMoreThanHalfCouncil(proposal: any) {
+    return await usingPlaygrounds(async (helper) => {
+      expect((await helper.callRpc('api.query.councilMembership.members')).toJSON().length).to.be.equal(5);
+      const proposeResult = await helper.council.collective.propose(
+        counselors.filip,
+        proposal,
+        moreThanHalfCouncilThreshold,
+      );
+
+      const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
+      const proposalIndex = councilProposedEvent.proposalIndex;
+      const proposalHash = councilProposedEvent.proposalHash;
+
+
+      await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
+      await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);
+      await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);
+
+      return await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
+    });
+  }
+
+  async function proposalFromAllCouncil(proposal: any) {
+    return await usingPlaygrounds(async (helper) => {
+      expect((await helper.callRpc('api.query.councilMembership.members')).toJSON().length).to.be.equal(5);
+      const proposeResult = await helper.council.collective.propose(
+        counselors.filip,
+        proposal,
+        moreThanHalfCouncilThreshold,
+      );
+
+      const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
+      const proposalIndex = councilProposedEvent.proposalIndex;
+      const proposalHash = councilProposedEvent.proposalHash;
+
+
+      await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
+      await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);
+      await helper.council.collective.vote(counselors.ildar, proposalHash, proposalIndex, true);
+      await helper.council.collective.vote(counselors.irina, proposalHash, proposalIndex, true);
+      await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);
+
+      return await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
+    });
+  }
+
+  itSub('>50% of Council can externally propose SuperMajorityAgainst', async ({helper}) => {
+    const forceSetBalanceReceiver = helper.arrange.createEmptyAccount();
+    const forceSetBalanceTestValue = 20n * 10n ** 25n;
+
+    const democracyProposal = await helper.constructApiCall('api.tx.balances.forceSetBalance', [
+      forceSetBalanceReceiver.address, forceSetBalanceTestValue,
+    ]);
+
+    const councilProposal = await helper.democracy.externalProposeDefaultCall(democracyProposal);
+
+    const proposeResult = await helper.council.collective.propose(
+      counselors.filip,
+      councilProposal,
+      moreThanHalfCouncilThreshold,
+    );
+
+    const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
+    const proposalIndex = councilProposedEvent.proposalIndex;
+    const proposalHash = councilProposedEvent.proposalHash;
+
+    await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
+    await helper.council.collective.vote(counselors.charu, proposalHash, proposalIndex, true);
+    await helper.council.collective.vote(counselors.filip, proposalHash, proposalIndex, true);
+
+    await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
+
+    const democracyStartedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+    const democracyReferendumIndex = democracyStartedEvent.referendumIndex;
+    const democracyThreshold = democracyStartedEvent.threshold;
+
+    expect(democracyThreshold).to.be.equal('SuperMajorityAgainst');
+
+    await helper.democracy.vote(counselors.filip, democracyReferendumIndex, {
+      Standard: {
+        vote: {
+          aye: true,
+          conviction: 1,
+        },
+        balance: 10_000n,
+      },
+    });
+
+    await helper.democracy.vote(counselors.charu, democracyReferendumIndex, {
+      Standard: {
+        vote: {
+          aye: false,
+          conviction: 1,
+        },
+        balance: 50_000n,
+      },
+    });
+
+    const passedReferendumEvent = await helper.wait.expectEvent(democracyVotingPeriod, Event.Democracy.Passed);
+    expect(passedReferendumEvent.referendumIndex).to.be.equal(democracyReferendumIndex);
+
+    await helper.wait.expectEvent(democracyEnactmentPeriod, Event.Scheduler.Dispatched);
+    const receiverBalance = await helper.balance.getSubstrate(forceSetBalanceReceiver.address);
+    expect(receiverBalance).to.be.equal(forceSetBalanceTestValue);
+  });
+
+  itSub('Council prime member vote is the default', async ({helper}) => {
+    const newTechCommMember = helper.arrange.createEmptyAccount();
+    const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address);
+    const proposeResult = await helper.council.collective.propose(
+      counselors.filip,
+      addMemberProposal,
+      moreThanHalfCouncilThreshold,
+    );
+
+    const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
+    const proposalIndex = councilProposedEvent.proposalIndex;
+    const proposalHash = councilProposedEvent.proposalHash;
+
+    await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
+
+    await helper.wait.newBlocks(councilMotionDuration);
+    const closeResult = await helper.council.collective.close(counselors.filip, proposalHash, proposalIndex);
+    const closeEvent = Event.Council.Closed.expect(closeResult);
+    const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON() as string[];
+    expect(closeEvent.yes).to.be.equal(members.length);
+  });
+
+  itSub('Superuser can add a member', async ({helper}) => {
+    const newMember = helper.arrange.createEmptyAccount();
+    await expect(helper.getSudo().council.membership.addMember(sudoer, newMember.address)).to.be.fulfilled;
+
+    const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
+    expect(members).to.contains(newMember.address);
+  });
+
+  itSub('Superuser can remove a member', async ({helper}) => {
+    await expect(helper.getSudo().council.membership.removeMember(sudoer, counselors.alex.address)).to.be.fulfilled;
+
+    const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
+    expect(members).to.not.contains(counselors.alex.address);
+  });
+
+  itSub('>50% Council can add TechComm member', async ({helper}) => {
+    const newTechCommMember = helper.arrange.createEmptyAccount();
+    const addMemberProposal = helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address);
+
+    await proposalFromMoreThanHalfCouncil(addMemberProposal);
+
+    const techCommMembers = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
+    expect(techCommMembers).to.contains(newTechCommMember.address);
+  });
+
+  itSub('Council can remove TechComm member', async ({helper}) => {
+    const techComm = await initTechComm(donor, sudoer);
+    const removeMemberPrpoposal = helper.technicalCommittee.membership.removeMemberCall(techComm.andy.address);
+    await proposalFromMoreThanHalfCouncil(removeMemberPrpoposal);
+
+    const techCommMembers = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
+    expect(techCommMembers).to.not.contains(techComm.andy.address);
+  });
+
+  itSub.skip('Council member can add Fellowship member', async ({helper}) => {
+    const newFellowshipMember = helper.arrange.createEmptyAccount();
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.fellowship.collective.addMemberCall(newFellowshipMember.address),
+    )).to.be.fulfilled;
+    const fellowshipMembers = (await helper.callRpc('api.query.fellowshipCollective.members')).toJSON();
+    expect(fellowshipMembers).to.contains(newFellowshipMember.address);
+  });
+
+  itSub('>50% Council can promote Fellowship member', async ({helper}) => {
+    const fellowship = await initFellowship(donor, sudoer);
+    const memberWithZeroRank = fellowship[0][0];
+
+    const proposal = helper.fellowship.collective.promoteCall(memberWithZeroRank.address);
+    await proposalFromMoreThanHalfCouncil(proposal);
+    const record = (await helper.callRpc('api.query.fellowshipCollective.members', [memberWithZeroRank.address])).toJSON();
+    expect(record).to.be.deep.equal({rank: 1});
+
+    await clearFellowship(sudoer);
+  });
+
+  itSub('>50% Council can demote Fellowship member', async ({helper}) => {
+    const fellowship = await initFellowship(donor, sudoer);
+    const memberWithRankOne = fellowship[1][0];
+
+    const proposal = helper.fellowship.collective.demoteCall(memberWithRankOne.address);
+    await proposalFromMoreThanHalfCouncil(proposal);
+
+    const record = (await helper.callRpc('api.query.fellowshipCollective.members', [memberWithRankOne.address])).toJSON();
+    expect(record).to.be.deep.equal({rank: 0});
+
+    await clearFellowship(sudoer);
+  });
+
+  itSub('>50% Council can add\remove Fellowship member', async ({helper}) => {
+    try {
+      const newMember = helper.arrange.createEmptyAccount();
+
+      const proposalAdd = helper.fellowship.collective.addMemberCall(newMember.address);
+      const proposalRemove = helper.fellowship.collective.removeMemberCall(newMember.address, fellowshipRankLimit);
+      await expect(proposalFromMoreThanHalfCouncil(proposalAdd)).to.be.fulfilled;
+      expect(await helper.fellowship.collective.getMembers()).to.be.deep.contain(newMember.address);
+      await expect(proposalFromMoreThanHalfCouncil(proposalRemove)).to.be.fulfilled;
+      expect(await helper.fellowship.collective.getMembers()).to.be.not.deep.contain(newMember.address);
+    }
+    finally {
+      await clearFellowship(sudoer);
+    }
+  });
+
+  itSub('Council can blacklist Democracy proposals', async ({helper}) => {
+    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+    await expect(proposalFromAllCouncil(helper.democracy.blacklistCall(preimageHash, null))).to.be.fulfilled;
+  });
+
+  itSub('Sudo can blacklist Democracy proposals', async ({helper}) => {
+    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+    await expect(helper.getSudo().democracy.blacklist(sudoer, preimageHash)).to.be.fulfilled;
+  });
+
+  itSub('[Negative] Council cannot add Council member', async ({helper}) => {
+    const newCouncilMember = helper.arrange.createEmptyAccount();
+    const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
+
+    await expect(proposalFromAllCouncil(addMemberProposal)).to.be.rejected;
+  });
+
+  itSub('[Negative] Council cannot remove Council member', async ({helper}) => {
+    const removeMemberProposal = helper.council.membership.removeMemberCall(counselors.alex.address);
+
+    await expect(proposalFromAllCouncil(removeMemberProposal)).to.be.rejected;
+  });
+
+  itSub('[Negative] Council cannot submit regular democracy proposal', async ({helper}) => {
+    const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
+
+    await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);
+  });
+
+  itSub('[Negative] Council cannot externally propose SimpleMajority', async ({helper}) => {
+    const councilProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
+
+    await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);
+  });
+
+  itSub('[Negative] Council cannot externally propose SuperMajorityApprove', async ({helper}) => {
+    const councilProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
+
+    await expect(proposalFromAllCouncil(councilProposal)).to.be.rejectedWith(/BadOrigin/);
+  });
+
+  itSub('[Negative] Council member cannot add/remove a Council member', async ({helper}) => {
+    const newCouncilMember = helper.arrange.createEmptyAccount();
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.council.membership.addMemberCall(newCouncilMember.address),
+    )).to.be.rejectedWith('BadOrigin');
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.council.membership.removeMemberCall(counselors.charu.address),
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] Council cannot set/clear Council prime member', async ({helper}) => {
+    const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
+    const proposalForClear = await helper.council.membership.clearPrimeCall();
+
+    await expect(proposalFromAllCouncil(proposalForSet)).to.be.rejectedWith(/BadOrigin/);
+    await expect(proposalFromAllCouncil(proposalForClear)).to.be.rejectedWith(/BadOrigin/);
+
+  });
+
+  itSub('[Negative] Council member cannot set/clear Council prime member', async ({helper}) => {
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.council.membership.setPrimeCall(counselors.charu.address),
+    )).to.be.rejectedWith('BadOrigin');
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.council.membership.clearPrimeCall(),
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] Council member cannot add/remove a TechComm member', async ({helper}) => {
+    const newTechCommMember = helper.arrange.createEmptyAccount();
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.technicalCommittee.membership.addMemberCall(newTechCommMember.address),
+    )).to.be.rejectedWith('BadOrigin');
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.technicalCommittee.membership.removeMemberCall(newTechCommMember.address),
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] Council member cannot promote/demote a Fellowship member', async ({helper}) => {
+    const fellowship = await initFellowship(donor, sudoer);
+    const memberWithRankOne = fellowship[1][0];
+
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.fellowship.collective.promoteCall(memberWithRankOne.address),
+    )).to.be.rejectedWith('BadOrigin');
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.fellowship.collective.demoteCall(memberWithRankOne.address),
+    )).to.be.rejectedWith('BadOrigin');
+    await clearFellowship(sudoer);
+  });
+
+  itSub('[Negative] Council cannot fast-track Democracy proposals', async ({helper}) => {
+    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+    await expect(proposalFromAllCouncil(helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0)))
+      .to.be.rejectedWith(/BadOrigin/);
+  });
+
+  itSub('[Negative] Council member cannot fast-track Democracy proposals', async ({helper}) => {
+    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0),
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] Council cannot cancel Democracy proposals', async ({helper}) => {
+    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
+    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
+
+    await expect(proposalFromAllCouncil(helper.democracy.cancelProposalCall(proposalIndex)))
+      .to.be.rejectedWith(/BadOrigin/);
+  });
+
+  itSub('[Negative] Council member cannot cancel Democracy proposals', async ({helper}) => {
+
+    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
+    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
+
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.democracy.cancelProposalCall(proposalIndex),
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] Council cannot cancel ongoing Democracy referendums', async ({helper}) => {
+    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
+    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+    const referendumIndex = startedEvent.referendumIndex;
+
+    await expect(proposalFromAllCouncil(helper.democracy.emergencyCancelCall(referendumIndex)))
+      .to.be.rejectedWith(/BadOrigin/);
+  });
+
+  itSub('[Negative] Council member cannot cancel ongoing Democracy referendums', async ({helper}) => {
+    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
+    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+    const referendumIndex = startedEvent.referendumIndex;
+
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.democracy.emergencyCancelCall(referendumIndex),
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] Council cannot cancel Fellowship referendums', async ({helper}) => {
+    const fellowship = await initFellowship(donor, sudoer);
+    const fellowshipProposer = fellowship[5][0];
+    const proposal = dummyProposal(helper);
+
+    const submitResult = await helper.fellowship.referenda.submit(
+      fellowshipProposer,
+      fellowshipPropositionOrigin,
+      proposal,
+      defaultEnactmentMoment,
+    );
+
+    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+
+    await expect(proposalFromAllCouncil(helper.fellowship.referenda.cancelCall(referendumIndex)))
+      .to.be.rejectedWith(/BadOrigin/);
+  });
+
+  itSub('[Negative] Council member cannot cancel Fellowship referendums', async ({helper}) => {
+    const fellowship = await initFellowship(donor, sudoer);
+    const fellowshipProposer = fellowship[5][0];
+    const proposal = dummyProposal(helper);
+
+    const submitResult = await helper.fellowship.referenda.submit(
+      fellowshipProposer,
+      fellowshipPropositionOrigin,
+      proposal,
+      defaultEnactmentMoment,
+    );
+    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+    await expect(helper.council.collective.execute(
+      counselors.alex,
+      helper.fellowship.referenda.cancelCall(referendumIndex),
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] Council referendum cannot be closed until the voting threshold is met', async ({helper}) => {
+    const councilSize = (await helper.callRpc('api.query.councilMembership.members')).toJSON().length as any as number;
+    expect(councilSize).is.greaterThan(1);
+    const proposeResult = await helper.council.collective.propose(
+      counselors.filip,
+      dummyProposalCall(helper),
+      councilSize,
+    );
+
+    const councilProposedEvent = Event.Council.Proposed.expect(proposeResult);
+    const proposalIndex = councilProposedEvent.proposalIndex;
+    const proposalHash = councilProposedEvent.proposalHash;
+
+
+    await helper.council.collective.vote(counselors.alex, proposalHash, proposalIndex, true);
+    await expect(helper.council.collective.close(counselors.filip, proposalHash, proposalIndex)).to.be.rejectedWith('TooEarly');
+  });
+
+});
addedjs-packages/tests/sub/governance/democracy.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/governance/democracy.test.ts
@@ -0,0 +1,89 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../../util/index.js';
+import {clearFellowship, democracyLaunchPeriod, democracyTrackMinRank, dummyProposalCall, fellowshipConfirmPeriod, fellowshipMinEnactPeriod, fellowshipPreparePeriod, fellowshipPropositionOrigin, initFellowship, voteUnanimouslyInFellowship} from './util.js';
+import {Event} from '@unique/playgrounds/unique.dev.js';
+
+describeGov('Governance: Democracy tests', () => {
+  let regularUser: IKeyringPair;
+  let donor: IKeyringPair;
+  let sudoer: IKeyringPair;
+
+  before(async function() {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.Democracy]);
+
+      donor = await privateKey({url: import.meta.url});
+      sudoer = await privateKey('//Alice');
+
+      [regularUser] = await helper.arrange.createAccounts([1000n], donor);
+    });
+  });
+
+  itSub('Regular user can vote', async ({helper}) => {
+    const fellows = await initFellowship(donor, sudoer);
+    const rank1Proposer = fellows[1][0];
+
+    const democracyProposalCall = dummyProposalCall(helper);
+    const fellowshipProposal = {
+      Inline: helper.democracy.proposeCall(democracyProposalCall, 0n).method.toHex(),
+    };
+
+    const submitResult = await helper.fellowship.referenda.submit(
+      rank1Proposer,
+      fellowshipPropositionOrigin,
+      fellowshipProposal,
+      {After: 0},
+    );
+
+    const fellowshipReferendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+    await voteUnanimouslyInFellowship(helper, fellows, democracyTrackMinRank, fellowshipReferendumIndex);
+    await helper.fellowship.referenda.placeDecisionDeposit(donor, fellowshipReferendumIndex);
+
+    await helper.wait.expectEvent(
+      fellowshipPreparePeriod + fellowshipConfirmPeriod + fellowshipMinEnactPeriod,
+      Event.Democracy.Proposed,
+    );
+
+    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+    const referendumIndex = startedEvent.referendumIndex;
+
+    const ayeBalance = 10_000n;
+
+    await helper.democracy.vote(regularUser, referendumIndex, {
+      Standard: {
+        vote: {
+          aye: true,
+          conviction: 1,
+        },
+        balance: ayeBalance,
+      },
+    });
+
+    const referendumInfo = await helper.democracy.referendumInfo(referendumIndex);
+    const tally = referendumInfo.ongoing.tally;
+
+    expect(BigInt(tally.ayes)).to.be.equal(ayeBalance);
+
+    await clearFellowship(sudoer);
+  });
+
+  itSub('[Negative] Regular user cannot submit a regular proposal', async ({helper}) => {
+    const submitResult = helper.democracy.propose(regularUser, dummyProposalCall(helper), 0n);
+    await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
+  });
+
+  itSub('[Negative] Regular user cannot externally propose SuperMajorityAgainst', async ({helper}) => {
+    const submitResult = helper.democracy.externalProposeDefault(regularUser, dummyProposalCall(helper));
+    await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
+  });
+
+  itSub('[Negative] Regular user cannot externally propose SimpleMajority', async ({helper}) => {
+    const submitResult = helper.democracy.externalProposeMajority(regularUser, dummyProposalCall(helper));
+    await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
+  });
+
+  itSub('[Negative] Regular user cannot externally propose SuperMajorityApprove', async ({helper}) => {
+    const submitResult = helper.democracy.externalPropose(regularUser, dummyProposalCall(helper));
+    await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
+  });
+});
addedjs-packages/tests/sub/governance/fellowship.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/governance/fellowship.test.ts
@@ -0,0 +1,335 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../../util/index.js';
+import {DevUniqueHelper, Event} from '@unique/playgrounds/unique.dev.js';
+import {initCouncil, democracyLaunchPeriod, democracyVotingPeriod, democracyFastTrackVotingPeriod, fellowshipRankLimit, clearCouncil, clearTechComm, clearFellowship, defaultEnactmentMoment, dummyProposal, dummyProposalCall, fellowshipPropositionOrigin, initFellowship, initTechComm, voteUnanimouslyInFellowship, democracyTrackMinRank, fellowshipPreparePeriod, fellowshipConfirmPeriod, fellowshipMinEnactPeriod, democracyTrackId, hardResetFellowshipReferenda, hardResetDemocracy, hardResetGovScheduler} from './util.js';
+import type {ICounselors, ITechComms} from './util.js';
+
+describeGov('Governance: Fellowship tests', () => {
+  let members: IKeyringPair[][];
+
+  let rank1Proposer: IKeyringPair;
+
+  let sudoer: any;
+  let donor: any;
+  let counselors: ICounselors;
+  let techcomms: ITechComms;
+
+  const submissionDeposit = 1000n;
+
+  async function testBadFellowshipProposal(
+    helper: DevUniqueHelper,
+    proposalCall: any,
+  ) {
+    const badProposal = {
+      Inline: proposalCall.method.toHex(),
+    };
+    const submitResult = await helper.fellowship.referenda.submit(
+      rank1Proposer,
+      fellowshipPropositionOrigin,
+      badProposal,
+      defaultEnactmentMoment,
+    );
+
+    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+    await voteUnanimouslyInFellowship(helper, members, democracyTrackMinRank, referendumIndex);
+    await helper.fellowship.referenda.placeDecisionDeposit(donor, referendumIndex);
+
+    const enactmentId = await helper.fellowship.referenda.enactmentEventId(referendumIndex);
+    const dispatchedEvent = await helper.wait.expectEvent(
+      fellowshipPreparePeriod + fellowshipConfirmPeriod + defaultEnactmentMoment.After,
+      Event.Scheduler.Dispatched,
+      (event: any) => event.id == enactmentId,
+    );
+
+    expect(dispatchedEvent.result.isErr, 'Bad Fellowship must fail')
+      .to.be.true;
+
+    expect(dispatchedEvent.result.asErr.isBadOrigin, 'Bad Fellowship must fail with BadOrigin')
+      .to.be.true;
+  }
+
+  before(async function() {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.Democracy, Pallets.Fellowship, Pallets.TechnicalCommittee, Pallets.Council]);
+
+      sudoer = await privateKey('//Alice');
+      donor = await privateKey({url: import.meta.url});
+    });
+
+    counselors = await initCouncil(donor, sudoer);
+    techcomms = await initTechComm(donor, sudoer);
+    members = await initFellowship(donor, sudoer);
+
+    rank1Proposer = members[1][0];
+  });
+
+  after(async () => {
+    await clearFellowship(sudoer);
+    await clearTechComm(sudoer);
+    await clearCouncil(sudoer);
+    await hardResetFellowshipReferenda(sudoer);
+    await hardResetDemocracy(sudoer);
+    await hardResetGovScheduler(sudoer);
+  });
+
+  itSub('FellowshipProposition can submit regular Democracy proposals', async ({helper}) => {
+    const democracyProposalCall = dummyProposalCall(helper);
+    const fellowshipProposal = {
+      Inline: helper.democracy.proposeCall(democracyProposalCall, 0n).method.toHex(),
+    };
+
+    const submitResult = await helper.fellowship.referenda.submit(
+      rank1Proposer,
+      fellowshipPropositionOrigin,
+      fellowshipProposal,
+      defaultEnactmentMoment,
+    );
+
+    const fellowshipReferendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+    await voteUnanimouslyInFellowship(helper, members, democracyTrackMinRank, fellowshipReferendumIndex);
+    await helper.fellowship.referenda.placeDecisionDeposit(donor, fellowshipReferendumIndex);
+
+    const democracyProposed = await helper.wait.expectEvent(
+      fellowshipPreparePeriod + fellowshipConfirmPeriod + fellowshipMinEnactPeriod,
+      Event.Democracy.Proposed,
+    );
+
+    const democracyEnqueuedProposal = await helper.democracy.expectPublicProposal(democracyProposed.proposalIndex);
+    expect(democracyEnqueuedProposal.inline, 'Fellowship proposal expected to be in the Democracy')
+      .to.be.equal(democracyProposalCall.method.toHex());
+
+    await helper.wait.newBlocks(democracyVotingPeriod);
+  });
+
+  itSub('Fellowship (rank-1 or greater) member can submit Fellowship proposals on the Democracy track', async ({helper}) => {
+    for(let rank = 1; rank < fellowshipRankLimit; rank++) {
+      const rankMembers = members[rank];
+
+      for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {
+        const member = rankMembers[memberIdx];
+        const newDummyProposal = dummyProposal(helper);
+
+        const submitResult = await helper.fellowship.referenda.submit(
+          member,
+          fellowshipPropositionOrigin,
+          newDummyProposal,
+          defaultEnactmentMoment,
+        );
+
+        const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+        const referendumInfo = await helper.fellowship.referenda.referendumInfo(referendumIndex);
+        expect(referendumInfo.ongoing.track, `${memberIdx}-th member of rank #${rank}: proposal #${referendumIndex} is on invalid track`)
+          .to.be.equal(democracyTrackId);
+      }
+    }
+  });
+
+  itSub(`Fellowship (rank-${democracyTrackMinRank} or greater) members can vote on the Democracy track`, async ({helper}) => {
+    const proposal = dummyProposal(helper);
+
+    const submitResult = await helper.fellowship.referenda.submit(
+      rank1Proposer,
+      fellowshipPropositionOrigin,
+      proposal,
+      defaultEnactmentMoment,
+    );
+
+    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+
+    let expectedAyes = 0;
+    for(let rank = democracyTrackMinRank; rank < fellowshipRankLimit; rank++) {
+      const rankMembers = members[rank];
+
+      for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {
+        const member = rankMembers[memberIdx];
+        await helper.fellowship.collective.vote(member, referendumIndex, true);
+        expectedAyes += 1;
+
+        const referendumInfo = await helper.fellowship.referenda.referendumInfo(referendumIndex);
+        expect(referendumInfo.ongoing.tally.bareAyes, `Vote from ${memberIdx}-th member of rank #${rank} isn't accounted`)
+          .to.be.equal(expectedAyes);
+      }
+    }
+  });
+
+  itSub('Fellowship rank vote strength is correct', async ({helper}) => {
+    const excessRankWeightTable = [
+      1,
+      3,
+      6,
+      10,
+      15,
+      21,
+    ];
+
+    const proposal = dummyProposal(helper);
+
+    const submitResult = await helper.fellowship.referenda.submit(
+      rank1Proposer,
+      fellowshipPropositionOrigin,
+      proposal,
+      defaultEnactmentMoment,
+    );
+
+    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+
+    for(let rank = democracyTrackMinRank; rank < fellowshipRankLimit; rank++) {
+      const rankMembers = members[rank];
+
+      for(let memberIdx = 0; memberIdx < rankMembers.length; memberIdx++) {
+        const member = rankMembers[memberIdx];
+
+        const referendumInfoBefore = await helper.fellowship.referenda.referendumInfo(referendumIndex);
+        const ayesBefore = referendumInfoBefore.ongoing.tally.ayes;
+
+        await helper.fellowship.collective.vote(member, referendumIndex, true);
+
+        const referendumInfoAfter = await helper.fellowship.referenda.referendumInfo(referendumIndex);
+        const ayesAfter = referendumInfoAfter.ongoing.tally.ayes;
+
+        const expectedVoteWeight = excessRankWeightTable[rank - democracyTrackMinRank];
+        const voteWeight = ayesAfter - ayesBefore;
+
+        expect(voteWeight, `Vote weight of ${memberIdx}-th member of rank #${rank} is invalid`)
+          .to.be.equal(expectedVoteWeight);
+      }
+    }
+  });
+
+  itSub('[Negative] FellowshipProposition cannot externally propose SuperMajorityAgainst', async ({helper}) => {
+    await testBadFellowshipProposal(helper, helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper)));
+  });
+
+  itSub('[Negative] FellowshipProposition cannot externally propose SimpleMajority', async ({helper}) => {
+    await testBadFellowshipProposal(helper, helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper)));
+  });
+
+  itSub('[Negative] FellowshipProposition cannot externally propose SuperMajorityApprove', async ({helper}) => {
+    await testBadFellowshipProposal(helper, helper.democracy.externalProposeCall(dummyProposalCall(helper)));
+  });
+
+  itSub('[Negative] Fellowship (rank-0) member cannot submit Fellowship proposals on the Democracy track', async ({helper}) => {
+    const rank0Proposer = members[0][0];
+
+    const proposal = dummyProposal(helper);
+
+    const submitResult = helper.fellowship.referenda.submit(
+      rank0Proposer,
+      fellowshipPropositionOrigin,
+      proposal,
+      defaultEnactmentMoment,
+    );
+
+    await expect(submitResult).to.be.rejectedWith(/BadOrigin/);
+  });
+
+  itSub('[Negative] Fellowship (rank-1 or greater) member cannot submit if no deposit can be provided', async ({helper}) => {
+    const poorMember = rank1Proposer;
+
+    const balanceBefore = await helper.balance.getSubstrate(poorMember.address);
+    await helper.getSudo().balance.setBalanceSubstrate(sudoer, poorMember.address, submissionDeposit - 1n);
+
+    const proposal = dummyProposal(helper);
+
+    const submitResult = helper.fellowship.referenda.submit(
+      poorMember,
+      fellowshipPropositionOrigin,
+      proposal,
+      defaultEnactmentMoment,
+    );
+
+    await expect(submitResult).to.be.rejectedWith(/account balance too low/);
+
+    await helper.getSudo().balance.setBalanceSubstrate(sudoer, poorMember.address, balanceBefore);
+  });
+
+  itSub(`[Negative] Fellowship (rank-${democracyTrackMinRank - 1} or less) members cannot vote on the Democracy track`, async ({helper}) => {
+    const proposal = dummyProposal(helper);
+
+    const submitResult = await helper.fellowship.referenda.submit(
+      rank1Proposer,
+      fellowshipPropositionOrigin,
+      proposal,
+      defaultEnactmentMoment,
+    );
+
+    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+
+    for(let rank = 0; rank < democracyTrackMinRank; rank++) {
+      for(const member of members[rank]) {
+        const voteResult = helper.fellowship.collective.vote(member, referendumIndex, true);
+        await expect(voteResult).to.be.rejectedWith(/RankTooLow/);
+      }
+    }
+  });
+
+  itSub('[Negative] FellowshipProposition cannot add/remove a Council member', async ({helper}) => {
+    const [councilNonMember] = await helper.arrange.createAccounts([10n], donor);
+
+    await testBadFellowshipProposal(helper, helper.council.membership.addMemberCall(councilNonMember.address));
+    await testBadFellowshipProposal(helper, helper.council.membership.removeMemberCall(counselors.ildar.address));
+  });
+
+  itSub('[Negative] FellowshipProposition cannot set/clear Council prime member', async ({helper}) => {
+    await testBadFellowshipProposal(helper, helper.council.membership.setPrimeCall(counselors.ildar.address));
+    await testBadFellowshipProposal(helper, helper.council.membership.clearPrimeCall());
+  });
+
+  itSub('[Negative] FellowshipProposition cannot add/remove a TechComm member', async ({helper}) => {
+    const [techCommNonMember] = await helper.arrange.createAccounts([10n], donor);
+
+    await testBadFellowshipProposal(helper, helper.technicalCommittee.membership.addMemberCall(techCommNonMember.address));
+    await testBadFellowshipProposal(helper, helper.technicalCommittee.membership.removeMemberCall(techcomms.constantine.address));
+  });
+
+  itSub('[Negative] FellowshipProposition cannot add/remove a Fellowship member', async ({helper}) => {
+    const [fellowshipNonMember] = await helper.arrange.createAccounts([10n], donor);
+
+    await testBadFellowshipProposal(helper, helper.fellowship.collective.addMemberCall(fellowshipNonMember.address));
+    await testBadFellowshipProposal(helper, helper.fellowship.collective.removeMemberCall(rank1Proposer.address, 1));
+  });
+
+  itSub('[Negative] FellowshipProposition cannot promote/demote a Fellowship member', async ({helper}) => {
+    await testBadFellowshipProposal(helper, helper.fellowship.collective.promoteCall(rank1Proposer.address));
+    await testBadFellowshipProposal(helper, helper.fellowship.collective.demoteCall(rank1Proposer.address));
+  });
+
+  itSub('[Negative] FellowshipProposition cannot fast-track Democracy proposals', async ({helper}) => {
+    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+
+    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+    await testBadFellowshipProposal(helper, helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0));
+  });
+
+  itSub('[Negative] FellowshipProposition cannot cancel Democracy proposals', async ({helper}) => {
+    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
+    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
+
+    await testBadFellowshipProposal(helper, helper.democracy.cancelProposalCall(proposalIndex));
+  });
+
+  itSub('[Negative] FellowshipProposition cannot cancel ongoing Democracy referendums', async ({helper}) => {
+    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
+    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+    const referendumIndex = startedEvent.referendumIndex;
+
+    await testBadFellowshipProposal(helper, helper.democracy.emergencyCancelCall(referendumIndex));
+  });
+
+  itSub('[Negative] FellowshipProposition cannot blacklist Democracy proposals', async ({helper}) => {
+    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+
+    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+    await testBadFellowshipProposal(helper, helper.democracy.blacklistCall(preimageHash, null));
+  });
+
+  itSub('[Negative] FellowshipProposition cannot veto external proposals', async ({helper}) => {
+    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+
+    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+    await testBadFellowshipProposal(helper, helper.democracy.vetoExternalCall(preimageHash));
+  });
+});
addedjs-packages/tests/sub/governance/init.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/governance/init.test.ts
@@ -0,0 +1,193 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../../util/index.js';
+import {Event} from '@unique/playgrounds/unique.dev.js';
+import {democracyLaunchPeriod, democracyVotingPeriod, democracyEnactmentPeriod, clearCouncil, clearTechComm, clearFellowship} from './util.js';
+import type {ICounselors, ITechComms} from './util.js';
+
+describeGov('Governance: Initialization', () => {
+  let donor: IKeyringPair;
+  let sudoer: IKeyringPair;
+  let counselors: ICounselors;
+  let techcomms: ITechComms;
+  let coreDevs: any;
+
+  const expectedAlexFellowRank = 7;
+  const expectedFellowRank = 6;
+
+  before(async function() {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.Democracy, Pallets.Council, Pallets.TechnicalCommittee]);
+
+      const councilMembers = await helper.council.membership.getMembers();
+      const techcommMembers = await helper.technicalCommittee.membership.getMembers();
+      expect(councilMembers.length == 0, 'The Council must be empty before the Gov Init');
+      expect(techcommMembers.length == 0, 'The Technical Commettee must be empty before the Gov Init');
+
+      donor = await privateKey({url: import.meta.url});
+      sudoer = await privateKey('//Alice');
+
+      const counselorsNum = 5;
+      const techCommsNum = 3;
+      const coreDevsNum = 2;
+      const [
+        alex,
+        ildar,
+        charu,
+        filip,
+        irina,
+
+        greg,
+        andy,
+        constantine,
+
+        yaroslav,
+        daniel,
+      ] = await helper.arrange.createAccounts(new Array(counselorsNum + techCommsNum + coreDevsNum).fill(10_000n), donor);
+
+      counselors = {
+        alex,
+        ildar,
+        charu,
+        filip,
+        irina,
+      };
+
+      techcomms = {
+        greg,
+        andy,
+        constantine,
+      };
+
+      coreDevs = {
+        yaroslav: yaroslav,
+        daniel: daniel,
+      };
+    });
+  });
+
+  itSub('Initialize Governance', async ({helper}) => {
+    const promoteFellow = (fellow: string, promotionsNum: number) => new Array(promotionsNum).fill(helper.fellowship.collective.promoteCall(fellow));
+
+    const expectFellowRank = async (fellow: string, expectedRank: number) => {
+      expect(await helper.fellowship.collective.getMemberRank(fellow)).to.be.equal(expectedRank);
+    };
+
+    console.log('\t- Setup the Prime of the Council via sudo');
+    await helper.getSudo().utility.batchAll(sudoer, [
+      helper.council.membership.addMemberCall(counselors.alex.address),
+      helper.council.membership.setPrimeCall(counselors.alex.address),
+
+      helper.fellowship.collective.addMemberCall(counselors.alex.address),
+      ...promoteFellow(counselors.alex.address, expectedAlexFellowRank),
+    ]);
+
+    let councilMembers = await helper.council.membership.getMembers();
+    const councilPrime = await helper.council.collective.getPrimeMember();
+    const alexFellowRank = await helper.fellowship.collective.getMemberRank(counselors.alex.address);
+    expect(councilMembers).to.be.deep.equal([counselors.alex.address]);
+    expect(councilPrime).to.be.equal(counselors.alex.address);
+    expect(alexFellowRank).to.be.equal(expectedAlexFellowRank);
+
+    console.log('\t- The Council Prime initializes the Technical Commettee');
+    const councilProposalThreshold = 1;
+
+    await helper.council.collective.propose(
+      counselors.alex,
+      helper.utility.batchAllCall([
+        helper.technicalCommittee.membership.addMemberCall(techcomms.greg.address),
+        helper.technicalCommittee.membership.addMemberCall(techcomms.andy.address),
+        helper.technicalCommittee.membership.addMemberCall(techcomms.constantine.address),
+
+        helper.technicalCommittee.membership.setPrimeCall(techcomms.greg.address),
+      ]),
+      councilProposalThreshold,
+    );
+
+    const techCommMembers = await helper.technicalCommittee.membership.getMembers();
+    const techCommPrime = await helper.technicalCommittee.membership.getPrimeMember();
+    const expectedTechComms = [techcomms.greg.address, techcomms.andy.address, techcomms.constantine.address];
+    expect(techCommMembers.length).to.be.equal(expectedTechComms.length);
+    expect(techCommMembers).to.containSubset(expectedTechComms);
+    expect(techCommPrime).to.be.equal(techcomms.greg.address);
+
+    console.log('\t- The Council Prime initiates a referendum to add counselors');
+    const returnPreimageHash = true;
+    const preimageHash = await helper.preimage.notePreimageFromCall(counselors.alex, helper.utility.batchAllCall([
+      helper.council.membership.addMemberCall(counselors.ildar.address),
+      helper.council.membership.addMemberCall(counselors.charu.address),
+      helper.council.membership.addMemberCall(counselors.filip.address),
+      helper.council.membership.addMemberCall(counselors.irina.address),
+
+      helper.fellowship.collective.addMemberCall(counselors.charu.address),
+      helper.fellowship.collective.addMemberCall(counselors.ildar.address),
+      helper.fellowship.collective.addMemberCall(counselors.irina.address),
+      helper.fellowship.collective.addMemberCall(counselors.filip.address),
+      helper.fellowship.collective.addMemberCall(techcomms.greg.address),
+      helper.fellowship.collective.addMemberCall(techcomms.andy.address),
+      helper.fellowship.collective.addMemberCall(techcomms.constantine.address),
+      helper.fellowship.collective.addMemberCall(coreDevs.yaroslav.address),
+      helper.fellowship.collective.addMemberCall(coreDevs.daniel.address),
+
+      ...promoteFellow(counselors.charu.address, expectedFellowRank),
+      ...promoteFellow(counselors.ildar.address, expectedFellowRank),
+      ...promoteFellow(counselors.irina.address, expectedFellowRank),
+      ...promoteFellow(counselors.filip.address, expectedFellowRank),
+      ...promoteFellow(techcomms.greg.address, expectedFellowRank),
+      ...promoteFellow(techcomms.andy.address, expectedFellowRank),
+      ...promoteFellow(techcomms.constantine.address, expectedFellowRank),
+      ...promoteFellow(coreDevs.yaroslav.address, expectedFellowRank),
+      ...promoteFellow(coreDevs.daniel.address, expectedFellowRank),
+    ]), returnPreimageHash);
+
+    await helper.council.collective.propose(
+      counselors.alex,
+      helper.democracy.externalProposeDefaultWithPreimageCall(preimageHash),
+      councilProposalThreshold,
+    );
+
+    console.log('\t- The referendum is being decided');
+    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+
+    await helper.democracy.vote(counselors.filip, startedEvent.referendumIndex, {
+      Standard: {
+        vote: {
+          aye: true,
+          conviction: 1,
+        },
+        balance: 10_000n,
+      },
+    });
+
+    const passedReferendumEvent = await helper.wait.expectEvent(democracyVotingPeriod, Event.Democracy.Passed);
+    expect(passedReferendumEvent.referendumIndex).to.be.equal(startedEvent.referendumIndex);
+
+    await helper.wait.expectEvent(democracyEnactmentPeriod, Event.Scheduler.Dispatched);
+
+    councilMembers = await helper.council.membership.getMembers();
+    const expectedCounselors = [
+      counselors.alex.address,
+      counselors.ildar.address,
+      counselors.charu.address,
+      counselors.filip.address,
+      counselors.irina.address,
+    ];
+    expect(councilMembers.length).to.be.equal(expectedCounselors.length);
+    expect(councilMembers).to.containSubset(expectedCounselors);
+
+    await expectFellowRank(counselors.ildar.address, expectedFellowRank);
+    await expectFellowRank(counselors.charu.address, expectedFellowRank);
+    await expectFellowRank(counselors.filip.address, expectedFellowRank);
+    await expectFellowRank(counselors.irina.address, expectedFellowRank);
+    await expectFellowRank(techcomms.greg.address, expectedFellowRank);
+    await expectFellowRank(techcomms.andy.address, expectedFellowRank);
+    await expectFellowRank(techcomms.constantine.address, expectedFellowRank);
+    await expectFellowRank(coreDevs.yaroslav.address, expectedFellowRank);
+    await expectFellowRank(coreDevs.daniel.address, expectedFellowRank);
+  });
+
+  after(async function() {
+    await clearFellowship(sudoer);
+    await clearTechComm(sudoer);
+    await clearCouncil(sudoer);
+  });
+});
addedjs-packages/tests/sub/governance/technicalCommittee.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/governance/technicalCommittee.test.ts
@@ -0,0 +1,383 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {usingPlaygrounds, itSub, expect, Pallets, requirePalletsOrSkip, describeGov} from '../../util/index.js';
+import {Event} from '@unique/playgrounds/unique.dev.js';
+import {initCouncil, democracyLaunchPeriod, democracyFastTrackVotingPeriod, clearCouncil, clearTechComm, clearFellowship, defaultEnactmentMoment, dummyProposal, dummyProposalCall, fellowshipPropositionOrigin, initFellowship, initTechComm, hardResetFellowshipReferenda, hardResetDemocracy, hardResetGovScheduler} from './util.js';
+import type {ITechComms} from './util.js';
+
+describeGov('Governance: Technical Committee tests', () => {
+  let sudoer: IKeyringPair;
+  let techcomms: ITechComms;
+  let donor: IKeyringPair;
+  let preImageHash: string;
+
+
+  const allTechCommitteeThreshold = 3;
+
+  before(async function() {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.TechnicalCommittee]);
+      sudoer = await privateKey('//Alice');
+      donor = await privateKey({url: import.meta.url});
+
+      techcomms = await initTechComm(donor, sudoer);
+
+      const proposalCall = await helper.constructApiCall('api.tx.balances.forceSetBalance', [donor.address, 20n * 10n ** 25n]);
+      preImageHash = await helper.preimage.notePreimageFromCall(sudoer, proposalCall, true);
+    });
+  });
+
+  after(async () => {
+    await usingPlaygrounds(async (helper) => {
+      await clearTechComm(sudoer);
+
+      await helper.preimage.unnotePreimage(sudoer, preImageHash);
+      await hardResetFellowshipReferenda(sudoer);
+      await hardResetDemocracy(sudoer);
+      await hardResetGovScheduler(sudoer);
+    });
+  });
+
+  function proposalFromAllCommittee(proposal: any) {
+    return usingPlaygrounds(async (helper) => {
+      expect((await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON().length).to.be.equal(allTechCommitteeThreshold);
+      const proposeResult = await helper.technicalCommittee.collective.propose(
+        techcomms.andy,
+        proposal,
+        allTechCommitteeThreshold,
+      );
+
+      const commiteeProposedEvent = Event.TechnicalCommittee.Proposed.expect(proposeResult);
+      const proposalIndex = commiteeProposedEvent.proposalIndex;
+      const proposalHash = commiteeProposedEvent.proposalHash;
+
+
+      await helper.technicalCommittee.collective.vote(techcomms.andy, proposalHash, proposalIndex, true);
+      await helper.technicalCommittee.collective.vote(techcomms.constantine, proposalHash, proposalIndex, true);
+      await helper.technicalCommittee.collective.vote(techcomms.greg, proposalHash, proposalIndex, true);
+
+      const closeResult = await helper.technicalCommittee.collective.close(techcomms.andy, proposalHash, proposalIndex);
+      Event.TechnicalCommittee.Closed.expect(closeResult);
+      Event.TechnicalCommittee.Approved.expect(closeResult);
+      const {result} = Event.TechnicalCommittee.Executed.expect(closeResult);
+      expect(result).to.eq('Ok');
+
+      return closeResult;
+    });
+  }
+
+  itSub('TechComm can fast-track Democracy proposals', async ({helper}) => {
+    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+    await helper.wait.parachainBlockMultiplesOf(35n);
+
+    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+    const fastTrackProposal = await proposalFromAllCommittee(helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0));
+    Event.Democracy.Started.expect(fastTrackProposal);
+  });
+
+  itSub('TechComm can cancel Democracy proposals', async ({helper}) => {
+    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
+    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
+
+    const cancelProposal = await proposalFromAllCommittee(helper.democracy.cancelProposalCall(proposalIndex));
+    Event.Democracy.ProposalCanceled.expect(cancelProposal);
+  });
+
+  itSub('TechComm can cancel ongoing Democracy referendums', async ({helper}) => {
+    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
+    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+    const referendumIndex = startedEvent.referendumIndex;
+
+    const emergencyCancelProposal = await proposalFromAllCommittee(helper.democracy.emergencyCancelCall(referendumIndex));
+    Event.Democracy.Cancelled.expect(emergencyCancelProposal);
+  });
+
+  itSub('TechComm member can veto Democracy proposals', async ({helper}) => {
+    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+    const vetoExternalCall = await helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      helper.democracy.vetoExternalCall(preimageHash),
+    );
+    Event.Democracy.Vetoed.expect(vetoExternalCall);
+  });
+
+  itSub('TechComm can cancel Fellowship referendums', async ({helper}) => {
+    const fellowship = await initFellowship(donor, sudoer);
+    const fellowshipProposer = fellowship[5][0];
+    const proposal = dummyProposal(helper);
+
+    const submitResult = await helper.fellowship.referenda.submit(
+      fellowshipProposer,
+      fellowshipPropositionOrigin,
+      proposal,
+      defaultEnactmentMoment,
+    );
+    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+    const cancelProposal = await proposalFromAllCommittee(helper.fellowship.referenda.cancelCall(referendumIndex));
+    Event.FellowshipReferenda.Cancelled.expect(cancelProposal);
+  });
+
+  itSub.skip('TechComm member can add a Fellowship member', async ({helper}) => {
+    const newFellowshipMember = helper.arrange.createEmptyAccount();
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      helper.fellowship.collective.addMemberCall(newFellowshipMember.address),
+    )).to.be.fulfilled;
+    const fellowshipMembers = (await helper.callRpc('api.query.fellowshipCollective.members')).toJSON();
+    expect(fellowshipMembers).to.contains(newFellowshipMember.address);
+    await clearFellowship(sudoer);
+  });
+
+  itSub('[Negative] TechComm cannot submit regular democracy proposal', async ({helper}) => {
+    const councilProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
+
+    await expect(proposalFromAllCommittee(councilProposal)).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm cannot externally propose SuperMajorityAgainst', async ({helper}) => {
+    const commiteeProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));
+
+    await expect(proposalFromAllCommittee(commiteeProposal)).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm cannot externally propose SimpleMajority', async ({helper}) => {
+    const commiteeProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
+
+    await expect(proposalFromAllCommittee(commiteeProposal)).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm cannot externally propose SuperMajorityApprove', async ({helper}) => {
+    const commiteeProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
+
+    await expect(proposalFromAllCommittee(commiteeProposal)).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm member cannot submit regular democracy proposal', async ({helper}) => {
+    const memberProposal = await helper.democracy.proposeCall(dummyProposalCall(helper), 0n);
+
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      memberProposal,
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm member cannot externally propose SuperMajorityAgainst', async ({helper}) => {
+    const memberProposal = await helper.democracy.externalProposeDefaultCall(dummyProposalCall(helper));
+
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      memberProposal,
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm member cannot externally propose SimpleMajority', async ({helper}) => {
+    const memberProposal = await helper.democracy.externalProposeMajorityCall(dummyProposalCall(helper));
+
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      memberProposal,
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm member cannot externally propose SuperMajorityApprove', async ({helper}) => {
+    const memberProposal = await helper.democracy.externalProposeCall(dummyProposalCall(helper));
+
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      memberProposal,
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+
+  itSub.skip('[Negative] TechComm cannot promote/demote Fellowship member', async () => {
+
+  });
+
+  itSub.skip('[Negative] TechComm member cannot promote/demote Fellowship member', async () => {
+
+  });
+
+  itSub('[Negative] TechComm cannot add/remove a Council member', async ({helper}) => {
+    const newCouncilMember = helper.arrange.createEmptyAccount();
+    const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
+    const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);
+
+    await expect(proposalFromAllCommittee(addMemberProposal)).to.be.rejectedWith('BadOrigin');
+    await expect(proposalFromAllCommittee(removeMemberProposal)).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm member cannot add/remove a Council member', async ({helper}) => {
+    const newCouncilMember = helper.arrange.createEmptyAccount();
+    const addMemberProposal = helper.council.membership.addMemberCall(newCouncilMember.address);
+    const removeMemberProposal = helper.council.membership.removeMemberCall(newCouncilMember.address);
+
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      addMemberProposal,
+    )).to.be.rejectedWith('BadOrigin');
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      removeMemberProposal,
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm cannot set/clear Council prime member', async ({helper}) => {
+    const counselors = await initCouncil(donor, sudoer);
+    const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
+    const proposalForClear = await helper.council.membership.clearPrimeCall();
+
+    await expect(proposalFromAllCommittee(proposalForSet)).to.be.rejectedWith('BadOrigin');
+    await expect(proposalFromAllCommittee(proposalForClear)).to.be.rejectedWith('BadOrigin');
+    await clearCouncil(sudoer);
+  });
+
+  itSub('[Negative] TechComm member cannot set/clear Council prime member', async ({helper}) => {
+    const counselors = await initCouncil(donor, sudoer);
+    const proposalForSet = await helper.council.membership.setPrimeCall(counselors.charu.address);
+    const proposalForClear = await helper.council.membership.clearPrimeCall();
+
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      proposalForSet,
+    )).to.be.rejectedWith('BadOrigin');
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      proposalForClear,
+    )).to.be.rejectedWith('BadOrigin');
+    await clearCouncil(sudoer);
+  });
+
+  itSub('[Negative] TechComm cannot add/remove a TechComm member', async ({helper}) => {
+    const newCommMember = helper.arrange.createEmptyAccount();
+    const addMemberProposal = helper.council.membership.addMemberCall(newCommMember.address);
+    const removeMemberProposal = helper.council.membership.removeMemberCall(newCommMember.address);
+
+    await expect(proposalFromAllCommittee(addMemberProposal)).to.be.rejectedWith('BadOrigin');
+    await expect(proposalFromAllCommittee(removeMemberProposal)).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm member cannot add/remove a TechComm member', async ({helper}) => {
+    const newCommMember = helper.arrange.createEmptyAccount();
+    const addMemberProposal = helper.council.membership.addMemberCall(newCommMember.address);
+    const removeMemberProposal = helper.council.membership.removeMemberCall(newCommMember.address);
+
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      addMemberProposal,
+    )).to.be.rejectedWith('BadOrigin');
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      removeMemberProposal,
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm cannot remove a Fellowship member', async ({helper}) => {
+    const fellowship = await initFellowship(donor, sudoer);
+
+    await expect(proposalFromAllCommittee(helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5))).to.be.rejectedWith('BadOrigin');
+    await clearFellowship(sudoer);
+  });
+
+  itSub('[Negative] TechComm member cannot remove a Fellowship member', async ({helper}) => {
+    const fellowship = await initFellowship(donor, sudoer);
+
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      helper.fellowship.collective.removeMemberCall(fellowship[5][0].address, 5),
+    )).to.be.rejectedWith('BadOrigin');
+    await clearFellowship(sudoer);
+  });
+
+  itSub('[Negative] TechComm member cannot fast-track Democracy proposals', async ({helper}) => {
+    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      helper.democracy.fastTrackCall(preimageHash, democracyFastTrackVotingPeriod, 0),
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm member cannot cancel Democracy proposals', async ({helper}) => {
+    const proposeResult = await helper.getSudo().democracy.propose(sudoer, dummyProposalCall(helper), 0n);
+    const proposalIndex = Event.Democracy.Proposed.expect(proposeResult).proposalIndex;
+
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      helper.democracy.cancelProposalCall(proposalIndex),
+    ))
+      .to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm member cannot cancel ongoing Democracy referendums', async ({helper}) => {
+    await helper.getSudo().democracy.externalProposeDefault(sudoer, dummyProposalCall(helper));
+    const startedEvent = await helper.wait.expectEvent(democracyLaunchPeriod, Event.Democracy.Started);
+    const referendumIndex = startedEvent.referendumIndex;
+
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      helper.democracy.emergencyCancelCall(referendumIndex),
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm cannot blacklist Democracy proposals', async ({helper}) => {
+    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+    await expect(proposalFromAllCommittee(helper.democracy.blacklistCall(preimageHash))).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm member cannot blacklist Democracy proposals', async ({helper}) => {
+    const preimageHash = await helper.preimage.notePreimageFromCall(sudoer, dummyProposalCall(helper), true);
+    await helper.getSudo().democracy.externalProposeDefaultWithPreimage(sudoer, preimageHash);
+
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      helper.democracy.blacklistCall(preimageHash),
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub.skip('[Negative] TechComm member cannot veto external Democracy proposals until the cool-off period pass', async () => {
+
+  });
+
+  itSub('[Negative] TechComm member cannot cancel Fellowship referendums', async ({helper}) => {
+    const fellowship = await initFellowship(donor, sudoer);
+    const fellowshipProposer = fellowship[5][0];
+    const proposal = dummyProposal(helper);
+
+    const submitResult = await helper.fellowship.referenda.submit(
+      fellowshipProposer,
+      fellowshipPropositionOrigin,
+      proposal,
+      defaultEnactmentMoment,
+    );
+
+    const referendumIndex = Event.FellowshipReferenda.Submitted.expect(submitResult).referendumIndex;
+
+    await expect(helper.technicalCommittee.collective.execute(
+      techcomms.andy,
+      helper.fellowship.referenda.cancelCall(referendumIndex),
+    )).to.be.rejectedWith('BadOrigin');
+  });
+
+  itSub('[Negative] TechComm referendum cannot be closed until the voting threshold is met', async ({helper}) => {
+    const committeeSize = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON().length as any as number;
+    expect(committeeSize).is.greaterThan(1);
+    const proposeResult = await helper.technicalCommittee.collective.propose(
+      techcomms.andy,
+      dummyProposalCall(helper),
+      committeeSize,
+    );
+
+    const committeeProposedEvent = Event.TechnicalCommittee.Proposed.expect(proposeResult);
+    const proposalIndex = committeeProposedEvent.proposalIndex;
+    const proposalHash = committeeProposedEvent.proposalHash;
+
+    await helper.technicalCommittee.collective.vote(techcomms.constantine, proposalHash, proposalIndex, true);
+
+    await expect(helper.technicalCommittee.collective.close(techcomms.andy, proposalHash, proposalIndex)).to.be.rejectedWith('TooEarly');
+  });
+});
addedjs-packages/tests/sub/governance/util.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/governance/util.ts
@@ -0,0 +1,224 @@
+import type {IKeyringPair} from '@polkadot/types/types';
+import {xxhashAsHex} from '@polkadot/util-crypto';
+import type {u32} from '@polkadot/types-codec';
+import {usingPlaygrounds, expect} from '../../util/index.js';
+import {UniqueHelper} from '@unique/playgrounds/unique.js';
+import {DevUniqueHelper} from '@unique/playgrounds/unique.dev.js';
+
+export const democracyLaunchPeriod = 35;
+export const democracyVotingPeriod = 35;
+export const councilMotionDuration = 35;
+export const democracyEnactmentPeriod = 40;
+export const democracyFastTrackVotingPeriod = 5;
+
+export const fellowshipRankLimit = 7;
+export const fellowshipPropositionOrigin = 'FellowshipProposition';
+export const fellowshipPreparePeriod = 3;
+export const fellowshipConfirmPeriod = 3;
+export const fellowshipMinEnactPeriod = 1;
+
+export const defaultEnactmentMoment = {After: 0};
+
+export const democracyTrackId = 10;
+export const democracyTrackMinRank = 3;
+const twox128 = (data: any) => xxhashAsHex(data, 128);
+export interface ICounselors {
+  alex: IKeyringPair;
+  ildar: IKeyringPair;
+  charu: IKeyringPair;
+  filip: IKeyringPair;
+  irina: IKeyringPair;
+}
+export interface ITechComms {
+    greg: IKeyringPair;
+    andy: IKeyringPair;
+    constantine: IKeyringPair;
+}
+
+export async function initCouncil(donor: IKeyringPair, superuser: IKeyringPair) {
+  let counselors: IKeyringPair[] = [];
+
+  await usingPlaygrounds(async (helper) => {
+    const [alex, ildar, charu, filip, irina] = await helper.arrange.createAccounts([10_000n, 10_000n, 10_000n, 10_000n, 10_000n], donor);
+    const sudo = helper.getSudo();
+    {
+      const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON() as [];
+      if(members.length != 0) {
+        await clearCouncil(superuser);
+      }
+    }
+    const expectedMembers = [alex, ildar, charu, filip, irina];
+    for(const member of expectedMembers) {
+      await sudo.executeExtrinsic(superuser, 'api.tx.councilMembership.addMember', [member.address]);
+    }
+    await sudo.executeExtrinsic(superuser, 'api.tx.councilMembership.setPrime', [alex.address]);
+    {
+      const members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
+      expect(members).to.containSubset(expectedMembers.map((x: IKeyringPair) => x.address));
+      expect(members.length).to.be.equal(expectedMembers.length);
+    }
+
+    counselors = [alex, ildar, charu, filip, irina];
+  });
+  return {
+    alex: counselors[0],
+    ildar: counselors[1],
+    charu: counselors[2],
+    filip: counselors[3],
+    irina: counselors[4],
+  };
+}
+
+export async function clearCouncil(superuser: IKeyringPair) {
+  await usingPlaygrounds(async (helper) => {
+    let members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
+    if(members.length) {
+      const sudo = helper.getSudo();
+      for(const address of members) {
+        await sudo.executeExtrinsic(superuser, 'api.tx.councilMembership.removeMember', [address]);
+      }
+      members = (await helper.callRpc('api.query.councilMembership.members')).toJSON();
+    }
+    expect(members).to.be.deep.equal([]);
+  });
+}
+
+
+export async function initTechComm(donor: IKeyringPair, superuser: IKeyringPair) {
+  let techcomms: IKeyringPair[] = [];
+
+  await usingPlaygrounds(async (helper) => {
+    const [greg, andy, constantine] = await helper.arrange.createAccounts([10_000n, 10_000n, 10_000n], donor);
+    const sudo = helper.getSudo();
+    {
+      const members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON() as [];
+      if(members.length != 0) {
+        await clearTechComm(superuser);
+      }
+    }
+    await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.addMember', [greg.address]);
+    await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.addMember', [andy.address]);
+    await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.addMember', [constantine.address]);
+    await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.setPrime', [greg.address]);
+    {
+      const members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
+      expect(members).to.containSubset([greg.address, andy.address, constantine.address]);
+      expect(members.length).to.be.equal(3);
+    }
+
+    techcomms = [greg, andy, constantine];
+  });
+
+  return {
+    greg: techcomms[0],
+    andy: techcomms[1],
+    constantine: techcomms[2],
+  };
+}
+
+export async function clearTechComm(superuser: IKeyringPair) {
+  await usingPlaygrounds(async (helper) => {
+    let members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
+    if(members.length) {
+      const sudo = helper.getSudo();
+      for(const address of members) {
+        await sudo.executeExtrinsic(superuser, 'api.tx.technicalCommitteeMembership.removeMember', [address]);
+      }
+      members = (await helper.callRpc('api.query.technicalCommitteeMembership.members')).toJSON();
+    }
+    expect(members).to.be.deep.equal([]);
+  });
+}
+
+export async function initFellowship(donor: IKeyringPair, sudoer: IKeyringPair) {
+  const numMembersInRank = 3;
+  const memberBalance = 5000n;
+  const members: IKeyringPair[][] = [];
+
+  await usingPlaygrounds(async (helper) => {
+    const currentFellows = await helper.getApi().query.fellowshipCollective.members.keys();
+
+    if(currentFellows.length != 0) {
+      await clearFellowship(sudoer);
+    }
+    for(let i = 0; i < fellowshipRankLimit; i++) {
+      const rankMembers = await helper.arrange.createAccounts(
+        Array(numMembersInRank).fill(memberBalance),
+        donor,
+      );
+
+      for(const member of rankMembers) {
+        await helper.getSudo().fellowship.collective.addMember(sudoer, member.address);
+
+        for(let rank = 0; rank < i; rank++) {
+          await helper.getSudo().fellowship.collective.promote(sudoer, member.address);
+        }
+      }
+
+      members.push(rankMembers);
+    }
+  });
+
+  return members;
+}
+
+export async function clearFellowship(sudoer: IKeyringPair) {
+  await usingPlaygrounds(async (helper) => {
+    const fellowship = (await helper.getApi().query.fellowshipCollective.members.keys())
+      .map((key) => key.args[0].toString());
+    for(const  member of fellowship) {
+      await helper.getSudo().fellowship.collective.removeMember(sudoer, member, fellowshipRankLimit);
+    }
+  });
+}
+
+export async function clearFellowshipReferenda(sudoer: IKeyringPair) {
+  await usingPlaygrounds(async (helper) => {
+    const proposalsCount = (await helper.getApi().query.fellowshipReferenda.referendumCount()) as u32;
+    for(let i = 0; i < proposalsCount.toNumber(); i++) {
+      await helper.getSudo().fellowship.referenda.cancel(sudoer, i);
+    }
+  });
+}
+
+export async function hardResetFellowshipReferenda(sudoer: IKeyringPair) {
+  await usingPlaygrounds(async (helper) => {
+    const api = helper.getApi();
+    const prefix = twox128('FellowshipReferenda');
+    await helper.signTransaction(sudoer, api.tx.sudo.sudo(api.tx.system.killPrefix(prefix, 100)));
+  });
+}
+
+export async function hardResetDemocracy(sudoer: IKeyringPair) {
+  await usingPlaygrounds(async (helper) => {
+    const api = helper.getApi();
+    const prefix = twox128('Democracy');
+    await helper.signTransaction(sudoer, api.tx.sudo.sudo(api.tx.system.killPrefix(prefix, 100)));
+  });
+}
+
+export async function hardResetGovScheduler(sudoer: IKeyringPair) {
+  await usingPlaygrounds(async (helper) => {
+    const api = helper.getApi();
+    const prefix = twox128('GovScheduler');
+    await helper.signTransaction(sudoer, api.tx.sudo.sudo(api.tx.system.killPrefix(prefix, 500)));
+  });
+}
+
+export async function voteUnanimouslyInFellowship(helper: DevUniqueHelper, fellows: IKeyringPair[][], minRank: number, referendumIndex: number) {
+  for(let rank = minRank; rank < fellowshipRankLimit; rank++) {
+    for(const member of fellows[rank]) {
+      await helper.fellowship.collective.vote(member, referendumIndex, true);
+    }
+  }
+}
+
+export function dummyProposalCall(helper: UniqueHelper) {
+  return helper.constructApiCall('api.tx.system.remark', ['dummy proposal' + (new Date()).getTime()]);
+}
+
+export function dummyProposal(helper: UniqueHelper) {
+  return {
+    Inline: dummyProposalCall(helper).method.toHex(),
+  };
+}
addedjs-packages/tests/sub/nesting/collectionProperties.seqtest.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/nesting/collectionProperties.seqtest.ts
@@ -0,0 +1,61 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip, sizeOfProperty} from '../../util/index.js';
+
+describe('Integration Test: Collection Properties with sudo', () => {
+  let superuser: IKeyringPair;
+  let alice: IKeyringPair;
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      superuser = await privateKey('//Alice');
+      const donor = await privateKey({url: import.meta.url});
+      [alice] = await helper.arrange.createAccounts([100n], donor);
+    });
+  });
+
+  [
+    {mode: 'nft' as const, requiredPallets: []},
+    {mode: 'ft' as const, requiredPallets: []},
+    {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+  ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
+    before(async function() {
+      // eslint-disable-next-line require-await
+      await usingPlaygrounds(async helper => {
+        requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
+      });
+    });
+
+    itSub('Repairing an unbroken collection\'s properties preserves the consumed space', async({helper}) => {
+      const properties = [
+        {key: 'sea-creatures', value: 'mermaids'},
+        {key: 'goldenratio', value: '1.6180339887498948482045868343656381177203091798057628621354486227052604628189'},
+      ];
+      const collection = await helper[testSuite.mode].mintCollection(alice, {properties});
+
+      const newProperty = {key: 'space', value: ' '.repeat(4096)};
+      await collection.setProperties(alice, [newProperty]);
+      const originalSpace = await collection.getPropertiesConsumedSpace();
+      expect(originalSpace).to.be.equal(sizeOfProperty(properties[0]) + sizeOfProperty(properties[1]) + sizeOfProperty(newProperty));
+
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.unique.forceRepairCollection', [collection.collectionId], true);
+      const recomputedSpace = await collection.getPropertiesConsumedSpace();
+      expect(recomputedSpace).to.be.equal(originalSpace);
+    });
+  }));
+});
addedjs-packages/tests/sub/nesting/collectionProperties.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/nesting/collectionProperties.test.ts
@@ -0,0 +1,326 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip, sizeOfProperty} from '../../util/index.js';
+
+describe('Integration Test: Collection Properties', () => {
+  let alice: IKeyringPair;
+  let bob: IKeyringPair;
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice, bob] = await helper.arrange.createAccounts([200n, 10n], donor);
+    });
+  });
+
+  itSub('Properties are initially empty', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice);
+    expect(await collection.getProperties()).to.be.empty;
+  });
+
+  [
+    {mode: 'nft' as const, requiredPallets: []},
+    {mode: 'ft' as const, requiredPallets: []},
+    {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+  ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
+    before(async function() {
+      // eslint-disable-next-line require-await
+      await usingPlaygrounds(async helper => {
+        requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
+      });
+    });
+
+    itSub('Sets properties for a collection', async ({helper}) =>  {
+      const collection = await helper[testSuite.mode].mintCollection(alice);
+
+      // As owner
+      await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}])).to.be.fulfilled;
+
+      await collection.addAdmin(alice, {Substrate: bob.address});
+
+      // As administrator
+      await expect(collection.setProperties(bob, [{key: 'black_hole'}])).to.be.fulfilled;
+
+      const properties = await collection.getProperties();
+      expect(properties).to.include.deep.members([
+        {key: 'electron', value: 'come bond'},
+        {key: 'black_hole', value: ''},
+      ]);
+    });
+
+    itSub('Check valid names for collection properties keys', async ({helper}) =>  {
+      const collection = await helper[testSuite.mode].mintCollection(alice);
+
+      // alpha symbols
+      await expect(collection.setProperties(alice, [{key: 'answer'}])).to.be.fulfilled;
+
+      // numeric symbols
+      await expect(collection.setProperties(alice, [{key: '451'}])).to.be.fulfilled;
+
+      // underscore symbol
+      await expect(collection.setProperties(alice, [{key: 'black_hole'}])).to.be.fulfilled;
+
+      // dash symbol
+      await expect(collection.setProperties(alice, [{key: '-'}])).to.be.fulfilled;
+
+      // dot symbol
+      await expect(collection.setProperties(alice, [{key: 'once.in.a.long.long.while...', value: 'you get a little lost'}])).to.be.fulfilled;
+
+      const properties = await collection.getProperties();
+      expect(properties).to.include.deep.members([
+        {key: 'answer', value: ''},
+        {key: '451', value: ''},
+        {key: 'black_hole', value: ''},
+        {key: '-', value: ''},
+        {key: 'once.in.a.long.long.while...', value: 'you get a little lost'},
+      ]);
+    });
+
+    itSub('Changes properties of a collection', async ({helper}) =>  {
+      const collection = await helper[testSuite.mode].mintCollection(alice);
+
+      await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: ''}])).to.be.fulfilled;
+
+      // Mutate the properties
+      await expect(collection.setProperties(alice, [{key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled;
+
+      const properties = await collection.getProperties();
+      expect(properties).to.include.deep.members([
+        {key: 'electron', value: 'come bond'},
+        {key: 'black_hole', value: 'LIGO'},
+      ]);
+    });
+
+    itSub('Deletes properties of a collection', async ({helper}) =>  {
+      const collection = await helper[testSuite.mode].mintCollection(alice);
+
+      await expect(collection.setProperties(alice, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}])).to.be.fulfilled;
+
+      await expect(collection.deleteProperties(alice, ['electron'])).to.be.fulfilled;
+
+      const properties = await collection.getProperties(['black_hole', 'electron']);
+      expect(properties).to.be.deep.equal([
+        {key: 'black_hole', value: 'LIGO'},
+      ]);
+    });
+
+    itSub('Allows modifying a collection property multiple times with the same size', async({helper}) => {
+      const propKey = 'tok-prop';
+
+      const collection = await helper[testSuite.mode].mintCollection(alice);
+
+      const maxCollectionPropertiesSize = 40960;
+
+      const propDataSize = 4096;
+
+      let propDataChar = 'a';
+      const makeNewPropData = () => {
+        propDataChar = String.fromCharCode(propDataChar.charCodeAt(0) + 1);
+        return `${propDataChar}`.repeat(propDataSize);
+      };
+
+      const property = {key: propKey, value: makeNewPropData()};
+      await collection.setProperties(alice, [property]);
+      const originalSpace = await collection.getPropertiesConsumedSpace();
+      expect(originalSpace).to.be.equal(sizeOfProperty(property));
+
+      const sameSizePropertiesPossibleNum = maxCollectionPropertiesSize / propDataSize;
+
+      // It is possible to modify a property as many times as needed.
+      // It will not consume any additional space.
+      for(let i = 0; i < sameSizePropertiesPossibleNum + 1; i++) {
+        await collection.setProperties(alice, [{key: propKey, value: makeNewPropData()}]);
+        const consumedSpace = await collection.getPropertiesConsumedSpace();
+        expect(consumedSpace).to.be.equal(originalSpace);
+      }
+    });
+
+    itSub('Adding then removing a collection property doesn\'t change the consumed space', async({helper}) => {
+      const propKey = 'tok-prop';
+
+      const collection = await helper[testSuite.mode].mintCollection(alice);
+      const originalSpace = await collection.getPropertiesConsumedSpace();
+
+      const propDataSize = 4096;
+      const propData = 'a'.repeat(propDataSize);
+
+      const property = {key: propKey, value: propData};
+      await collection.setProperties(alice, [property]);
+      let consumedSpace = await collection.getPropertiesConsumedSpace();
+      expect(consumedSpace).to.be.equal(sizeOfProperty(property));
+
+      await collection.deleteProperties(alice, [propKey]);
+      consumedSpace = await collection.getPropertiesConsumedSpace();
+      expect(consumedSpace).to.be.equal(originalSpace);
+    });
+
+    itSub('Modifying a collection property with different sizes correctly changes the consumed space', async({helper}) => {
+      const propKey = 'tok-prop';
+
+      const collection = await helper[testSuite.mode].mintCollection(alice);
+      const originalSpace = await collection.getPropertiesConsumedSpace();
+
+      const initProp = {key: propKey, value: 'a'.repeat(4096)};
+      const biggerProp = {key: propKey, value: 'b'.repeat(5000)};
+      const smallerProp = {key: propKey, value: 'c'.repeat(4000)};
+
+      let consumedSpace;
+      let expectedConsumedSpaceDiff;
+
+      await collection.setProperties(alice, [initProp]);
+      consumedSpace = await collection.getPropertiesConsumedSpace();
+      expectedConsumedSpaceDiff = sizeOfProperty(initProp) - originalSpace;
+      expect(consumedSpace).to.be.equal(originalSpace + expectedConsumedSpaceDiff);
+
+      await collection.setProperties(alice, [biggerProp]);
+      consumedSpace = await collection.getPropertiesConsumedSpace();
+      expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(initProp);
+      expect(consumedSpace).to.be.equal(sizeOfProperty(initProp) + expectedConsumedSpaceDiff);
+
+      await collection.setProperties(alice, [smallerProp]);
+      consumedSpace = await collection.getPropertiesConsumedSpace();
+      expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(smallerProp);
+      expect(consumedSpace).to.be.equal(sizeOfProperty(biggerProp) - expectedConsumedSpaceDiff);
+    });
+  }));
+});
+
+describe('Negative Integration Test: Collection Properties', () => {
+  let alice: IKeyringPair;
+  let bob: IKeyringPair;
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice, bob] = await helper.arrange.createAccounts([1000n, 100n], donor);
+    });
+  });
+
+  [
+    {mode: 'nft' as const, requiredPallets: []},
+    {mode: 'ft' as const, requiredPallets: []},
+    {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+  ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
+    before(async function() {
+      // eslint-disable-next-line require-await
+      await usingPlaygrounds(async helper => {
+        requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
+      });
+    });
+
+    itSub('Fails to set properties in a collection if not its onwer/administrator', async ({helper}) =>  {
+      const collection = await helper[testSuite.mode].mintCollection(alice);
+
+      await expect(collection.setProperties(bob, [{key: 'electron', value: 'come bond'}, {key: 'black_hole', value: 'LIGO'}]))
+        .to.be.rejectedWith(/common\.NoPermission/);
+
+      expect(await collection.getProperties()).to.be.empty;
+    });
+
+    itSub('Fails to set properties that exceed the limits', async ({helper}) =>  {
+      const collection = await helper[testSuite.mode].mintCollection(alice);
+
+      const spaceLimit = (helper.getApi().consts.unique.maxCollectionPropertiesSize as any).toNumber();
+
+      // Mute the general tx parsing error, too many bytes to process
+      {
+        console.error = () => {};
+        await expect(collection.setProperties(alice, [
+          {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))},
+        ])).to.be.rejected;
+      }
+
+      expect(await collection.getProperties(['electron'])).to.be.empty;
+
+      await expect(collection.setProperties(alice, [
+        {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 18))},
+        {key: 'black_hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))},
+      ])).to.be.rejectedWith(/common\.NoSpaceForProperty/);
+
+      expect(await collection.getProperties(['electron', 'black_hole'])).to.be.empty;
+    });
+
+    itSub('Fails to set more properties than it is allowed', async ({helper}) =>  {
+      const collection = await helper[testSuite.mode].mintCollection(alice);
+
+      const propertiesToBeSet = [];
+      for(let i = 0; i < 65; i++) {
+        propertiesToBeSet.push({
+          key: 'electron_' + i,
+          value: Math.random() > 0.5 ? 'high' : 'low',
+        });
+      }
+
+      await expect(collection.setProperties(alice, propertiesToBeSet)).
+        to.be.rejectedWith(/common\.PropertyLimitReached/);
+
+      expect(await collection.getProperties()).to.be.empty;
+    });
+
+    itSub('Fails to set properties with invalid names', async ({helper}) => {
+      const collection = await helper[testSuite.mode].mintCollection(alice);
+
+      const invalidProperties = [
+        [{key: 'electron', value: 'negative'}, {key: 'string theory', value: 'understandable'}],
+        [{key: 'Mr/Sandman', value: 'Bring me a gene'}],
+        [{key: 'déjà vu', value: 'hmm...'}],
+      ];
+
+      for(let i = 0; i < invalidProperties.length; i++) {
+        await expect(
+          collection.setProperties(alice, invalidProperties[i]),
+          `on rejecting the new badly-named property #${i}`,
+        ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
+      }
+
+      await expect(
+        collection.setProperties(alice, [{key: '', value: 'nothing must not exist'}]),
+        'on rejecting an unnamed property',
+      ).to.be.rejectedWith(/common\.EmptyPropertyKey/);
+
+      await expect(
+        collection.setProperties(alice, [{key: 'CRISPR-Cas9', value: 'rewriting nature!'}]),
+        'on setting the correctly-but-still-badly-named property',
+      ).to.be.fulfilled;
+
+      const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat('CRISPR-Cas9').concat('');
+
+      const properties = await collection.getProperties(keys);
+      expect(properties).to.be.deep.equal([
+        {key: 'CRISPR-Cas9', value: 'rewriting nature!'},
+      ]);
+
+      for(let i = 0; i < invalidProperties.length; i++) {
+        await expect(
+          collection.deleteProperties(alice, invalidProperties[i].map(propertySet => propertySet.key)),
+          `on trying to delete the non-existent badly-named property #${i}`,
+        ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
+      }
+    });
+
+    itSub('Forbids to repair a collection if called with non-sudo', async({helper}) => {
+      const collection = await helper[testSuite.mode].mintCollection(alice, {properties: [
+        {key: 'sea-creatures', value: 'mermaids'},
+        {key: 'goldenratio', value: '1.6180339887498948482045868343656381177203091798057628621354486227052604628189'},
+      ]});
+
+      await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairCollection', [collection.collectionId], true))
+        .to.be.rejectedWith(/BadOrigin/);
+    });
+  }));
+});
addedjs-packages/tests/sub/nesting/graphs.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/nesting/graphs.test.ts
@@ -0,0 +1,86 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, usingPlaygrounds} from '../../util/index.js';
+import {UniqueHelper, UniqueNFTCollection, UniqueNFToken} from '@unique/playgrounds/unique.js';
+
+/**
+ * ```dot
+ * 4 -> 3 -> 2 -> 1
+ * 7 -> 6 -> 5 -> 2
+ * 8 -> 5
+ * ```
+ */
+async function buildComplexObjectGraph(helper: UniqueHelper, sender: IKeyringPair): Promise<[UniqueNFTCollection,UniqueNFToken[]]> {
+  const collection = await helper.nft.mintCollection(sender, {permissions: {nesting: {tokenOwner: true}}});
+  const tokens = await collection.mintMultipleTokens(sender, Array(8).fill({owner: {Substrate: sender.address}}));
+
+  await tokens[7].nest(sender, tokens[4]);
+  await tokens[6].nest(sender, tokens[5]);
+  await tokens[5].nest(sender, tokens[4]);
+  await tokens[4].nest(sender, tokens[1]);
+  await tokens[3].nest(sender, tokens[2]);
+  await tokens[2].nest(sender, tokens[1]);
+  await tokens[1].nest(sender, tokens[0]);
+
+  return [collection, tokens];
+}
+
+describe('Graphs', () => {
+  let alice: IKeyringPair;
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice] = await helper.arrange.createAccounts([10n], donor);
+    });
+  });
+
+  itSub('Ouroboros can\'t be created in a complex graph', async ({helper}) => {
+    const [collection, tokens] = await buildComplexObjectGraph(helper, alice);
+
+    await collection.setPermissions(alice, {nesting: {collectionAdmin: false, tokenOwner: true}});
+
+    // [token owner] to self
+    await expect(
+      tokens[0].nest(alice, tokens[0]),
+      '[token owner] self-nesting is forbidden',
+    ).to.be.rejectedWith(/structure\.OuroborosDetected/);
+    // [token owner] to nested part of graph
+    await expect(
+      tokens[0].nest(alice, tokens[4]),
+      '[token owner] cannot nest the root node into an internal node',
+    ).to.be.rejectedWith(/structure\.OuroborosDetected/);
+    await expect(
+      tokens[1].transferFrom(alice, tokens[0].nestingAccount(), tokens[7].nestingAccount()),
+      '[token owner] cannot nest higher internal node into lower internal node',
+    ).to.be.rejectedWith(/structure\.OuroborosDetected/);
+
+    await collection.setPermissions(alice, {nesting: {collectionAdmin: true, tokenOwner: false}});
+
+    // [collection owner] to self
+    await expect(
+      tokens[0].nest(alice, tokens[0]),
+      '[collection owner] self-nesting is forbidden',
+    ).to.be.rejectedWith(/structure\.OuroborosDetected/);
+    // [collection owner] to nested part of graph
+    await expect(
+      tokens[0].nest(alice, tokens[4]),
+      '[collection owner] cannot nest the root node into an internal node',
+    ).to.be.rejectedWith(/structure\.OuroborosDetected/);
+  });
+});
addedjs-packages/tests/sub/nesting/propertyPermissions.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/nesting/propertyPermissions.test.ts
@@ -0,0 +1,198 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, usingPlaygrounds, expect} from '../../util/index.js';
+import {UniqueNFTCollection, UniqueRFTCollection} from '@unique/playgrounds/unique.js';
+
+describe('Integration Test: Access Rights to Token Properties', () => {
+  let alice: IKeyringPair;
+  let bob: IKeyringPair;
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice, bob] = await helper.arrange.createAccounts([100n, 10n], donor);
+    });
+  });
+
+  itSub('Reads access rights to properties of a collection', async ({helper}) =>  {
+    const collection = await helper.nft.mintCollection(alice);
+    const propertyRights = (await helper.callRpc('api.query.common.collectionPropertyPermissions', [collection.collectionId])).toJSON();
+    expect(propertyRights).to.be.empty;
+  });
+
+  async function testSetsAccessRightsToProperties(collection: UniqueNFTCollection | UniqueRFTCollection) {
+    await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true}}]))
+      .to.be.fulfilled;
+
+    await collection.addAdmin(alice, {Substrate: bob.address});
+
+    await expect(collection.setTokenPropertyPermissions(bob, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]))
+      .to.be.fulfilled;
+
+    const propertyRights = await collection.getPropertyPermissions(['skullduggery', 'mindgame']);
+    expect(propertyRights).to.include.deep.members([
+      {key: 'skullduggery', permission: {mutable: true, collectionAdmin: false, tokenOwner: false}},
+      {key: 'mindgame', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},
+    ]);
+  }
+
+  itSub('Sets access rights to properties of a collection (NFT)', async ({helper}) =>  {
+    await testSetsAccessRightsToProperties(await helper.nft.mintCollection(alice));
+  });
+
+  itSub.ifWithPallets('Sets access rights to properties of a collection (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+    await testSetsAccessRightsToProperties(await helper.rft.mintCollection(alice));
+  });
+
+  async function testChangesAccessRightsToProperty(collection: UniqueNFTCollection | UniqueRFTCollection) {
+    await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]))
+      .to.be.fulfilled;
+
+    await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]))
+      .to.be.fulfilled;
+
+    const propertyRights = await collection.getPropertyPermissions();
+    expect(propertyRights).to.be.deep.equal([
+      {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
+    ]);
+  }
+
+  itSub('Changes access rights to properties of a NFT collection', async ({helper}) =>  {
+    await testChangesAccessRightsToProperty(await helper.nft.mintCollection(alice));
+  });
+
+  itSub.ifWithPallets('Changes access rights to properties of a ReFungible collection', [Pallets.ReFungible], async ({helper}) => {
+    await testChangesAccessRightsToProperty(await helper.rft.mintCollection(alice));
+  });
+});
+
+describe('Negative Integration Test: Access Rights to Token Properties', () => {
+  let alice: IKeyringPair;
+  let bob: IKeyringPair;
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
+    });
+  });
+
+  async function testPreventsFromSettingAccessRightsNotAdminOrOwner(collection: UniqueNFTCollection | UniqueRFTCollection) {
+    await expect(collection.setTokenPropertyPermissions(bob, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]))
+      .to.be.rejectedWith(/common\.NoPermission/);
+
+    const propertyRights = await collection.getPropertyPermissions(['skullduggery']);
+    expect(propertyRights).to.be.empty;
+  }
+
+  itSub('Prevents from setting access rights to properties of a NFT collection if not an onwer/admin', async ({helper}) =>  {
+    await testPreventsFromSettingAccessRightsNotAdminOrOwner(await helper.nft.mintCollection(alice));
+  });
+
+  itSub.ifWithPallets('Prevents from setting access rights to properties of a ReFungible collection if not an onwer/admin', [Pallets.ReFungible], async ({helper}) => {
+    await testPreventsFromSettingAccessRightsNotAdminOrOwner(await helper.rft.mintCollection(alice));
+  });
+
+  async function testPreventFromAddingTooManyPossibleProperties(collection: UniqueNFTCollection | UniqueRFTCollection) {
+    const constitution = [];
+    for(let i = 0; i < 65; i++) {
+      constitution.push({
+        key: 'property_' + i,
+        permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},
+      });
+    }
+
+    await expect(collection.setTokenPropertyPermissions(alice, constitution))
+      .to.be.rejectedWith(/common\.PropertyLimitReached/);
+
+    const propertyRights = await collection.getPropertyPermissions();
+    expect(propertyRights).to.be.empty;
+  }
+
+  itSub('Prevents from adding too many possible properties (NFT)', async ({helper}) =>  {
+    await testPreventFromAddingTooManyPossibleProperties(await helper.nft.mintCollection(alice));
+  });
+
+  itSub.ifWithPallets('Prevents from adding too many possible properties (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+    await testPreventFromAddingTooManyPossibleProperties(await helper.rft.mintCollection(alice));
+  });
+
+  async function testPreventAccessRightsModifiedIfConstant(collection: UniqueNFTCollection | UniqueRFTCollection) {
+    await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]))
+      .to.be.fulfilled;
+
+    await expect(collection.setTokenPropertyPermissions(alice, [{key: 'skullduggery', permission: {collectionAdmin: true}}]))
+      .to.be.rejectedWith(/common\.NoPermission/);
+
+    const propertyRights = await collection.getPropertyPermissions(['skullduggery']);
+    expect(propertyRights).to.deep.equal([
+      {key: 'skullduggery', permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
+    ]);
+  }
+
+  itSub('Prevents access rights to be modified if constant (NFT)', async ({helper}) =>  {
+    await testPreventAccessRightsModifiedIfConstant(await helper.nft.mintCollection(alice));
+  });
+
+  itSub.ifWithPallets('Prevents access rights to be modified if constant (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+    await testPreventAccessRightsModifiedIfConstant(await helper.rft.mintCollection(alice));
+  });
+
+  async function testPreventsAddingPropertiesWithInvalidNames(collection: UniqueNFTCollection | UniqueRFTCollection) {
+    const invalidProperties = [
+      [{key: 'skullduggery', permission: {tokenOwner: true}}, {key: 'im possible', permission: {collectionAdmin: true}}],
+      [{key: 'G#4', permission: {tokenOwner: true}}],
+      [{key: 'HÆMILTON', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}],
+    ];
+
+    for(let i = 0; i < invalidProperties.length; i++) {
+      await expect(
+        collection.setTokenPropertyPermissions(alice, invalidProperties[i]),
+        `on setting the new badly-named property #${i}`,
+      ).to.be.rejectedWith(/common\.InvalidCharacterInPropertyKey/);
+    }
+
+    await expect(
+      collection.setTokenPropertyPermissions(alice, [{key: '', permission: {}}]),
+      'on rejecting an unnamed property',
+    ).to.be.rejectedWith(/common\.EmptyPropertyKey/);
+
+    const correctKey = '--0x03116e387820CA05'; // PolkadotJS would parse this as an already encoded hex-string
+    await expect(
+      collection.setTokenPropertyPermissions(alice, [
+        {key: correctKey, permission: {collectionAdmin: true}},
+      ]),
+      'on setting the correctly-but-still-badly-named property',
+    ).to.be.fulfilled;
+
+    const keys = invalidProperties.flatMap(propertySet => propertySet.map(property => property.key)).concat(correctKey).concat('');
+
+    const propertyRights = await collection.getPropertyPermissions(keys);
+    expect(propertyRights).to.be.deep.equal([
+      {key: correctKey, permission: {mutable: false, collectionAdmin: true, tokenOwner: false}},
+    ]);
+  }
+
+  itSub('Prevents adding properties with invalid names (NFT)', async ({helper}) =>  {
+    await testPreventsAddingPropertiesWithInvalidNames(await helper.nft.mintCollection(alice));
+  });
+
+  itSub.ifWithPallets('Prevents adding properties with invalid names (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+    await testPreventsAddingPropertiesWithInvalidNames(await helper.rft.mintCollection(alice));
+  });
+});
addedjs-packages/tests/sub/nesting/tokenProperties.seqtest.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/nesting/tokenProperties.seqtest.ts
@@ -0,0 +1,71 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, usingPlaygrounds, expect, requirePalletsOrSkip, sizeOfProperty} from '../../util/index.js';
+
+describe('Integration Test: Token Properties with sudo', () => {
+  let superuser: IKeyringPair;
+  let alice: IKeyringPair; // collection owner
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      superuser = await privateKey('//Alice');
+      const donor = await privateKey({url: import.meta.url});
+      [alice] = await helper.arrange.createAccounts([100n], donor);
+    });
+  });
+
+  [
+    {mode: 'nft' as const, pieces: undefined, requiredPallets: []} as const,
+    {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]} as const,
+  ].map(testSuite => describe(`${testSuite.mode.toUpperCase()}`, () => {
+    before(async function() {
+      // eslint-disable-next-line require-await
+      await usingPlaygrounds(async helper => {
+        requirePalletsOrSkip(this, helper, testSuite.requiredPallets);
+      });
+    });
+
+    itSub('force_repair_item preserves valid consumed space', async({helper}) => {
+      const propKey = 'tok-prop';
+
+      const collection = await helper[testSuite.mode].mintCollection(alice, {
+        tokenPropertyPermissions: [
+          {
+            key: propKey,
+            permission: {mutable: true, tokenOwner: true},
+          },
+        ],
+      });
+      const token = await (
+        testSuite.pieces
+          ? collection.mintToken(alice, testSuite.pieces as any)
+          : collection.mintToken(alice)
+      );
+
+      const prop = {key: propKey, value: 'a'.repeat(4096)};
+
+      await token.setProperties(alice, [prop]);
+      const originalSpace = await token.getTokenPropertiesConsumedSpace();
+      expect(originalSpace).to.be.equal(sizeOfProperty(prop));
+
+      await helper.getSudo().executeExtrinsic(superuser, 'api.tx.unique.forceRepairItem', [token.collectionId, token.tokenId], true);
+      const recomputedSpace = await token.getTokenPropertiesConsumedSpace();
+      expect(recomputedSpace).to.be.equal(originalSpace);
+    });
+  }));
+});
addedjs-packages/tests/sub/nesting/tokenProperties.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/nesting/tokenProperties.test.ts
@@ -0,0 +1,816 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds, expect, sizeOfProperty} from '../../util/index.js';
+import {UniqueHelper, UniqueNFToken, UniqueRFToken} from '@unique/playgrounds/unique.js';
+
+describe('Integration Test: Token Properties', () => {
+  let alice: IKeyringPair; // collection owner
+  let bob: IKeyringPair; // collection admin
+  let charlie: IKeyringPair; // token owner
+
+  let permissions: {permission: any, signers: IKeyringPair[]}[];
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 100n, 100n], donor);
+    });
+
+    permissions = [
+      {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},
+      {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob]},
+      {permission: {mutable: true, tokenOwner: true}, signers: [charlie]},
+      {permission: {mutable: false, tokenOwner: true}, signers: [charlie]},
+      {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},
+      {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},
+    ];
+  });
+
+  async function mintCollectionWithAllPermissionsAndToken(helper: UniqueHelper, mode: 'NFT' | 'RFT'): Promise<[UniqueNFToken | UniqueRFToken, bigint]> {
+    const collection = await (mode == 'NFT' ? helper.nft : helper.rft).mintCollection(alice, {
+      tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
+        signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
+    });
+    return mode == 'NFT' ? [await collection.mintToken(alice), 1n] : [await collection.mintToken(alice, 100n as any), 100n];
+  }
+
+  async function testReadsYetEmptyProperties(token: UniqueNFToken | UniqueRFToken) {
+    const properties = await token.getProperties();
+    expect(properties).to.be.empty;
+
+    const tokenData = await token.getData();
+    expect(tokenData!.properties).to.be.empty;
+  }
+
+  itSub('Reads yet empty properties of a token (NFT)', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice);
+    const token = await collection.mintToken(alice);
+    await testReadsYetEmptyProperties(token);
+  });
+
+  itSub.ifWithPallets('Reads yet empty properties of a token (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+    const collection = await helper.rft.mintCollection(alice);
+    const token = await collection.mintToken(alice);
+    await testReadsYetEmptyProperties(token);
+  });
+
+  async function testAssignPropertiesAccordingToPermissions(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+    await token.collection.addAdmin(alice, {Substrate: bob.address});
+    await token.transfer(alice, {Substrate: charlie.address}, pieces);
+
+    const propertyKeys: string[] = [];
+    let i = 0;
+    for(const permission of permissions) {
+      i++;
+      let j = 0;
+      for(const signer of permission.signers) {
+        j++;
+        const key = i + '_' + signer.address;
+        propertyKeys.push(key);
+
+        await expect(
+          token.setProperties(signer, [{key: key, value: 'Serotonin increase'}]),
+          `on adding property #${i} by signer #${j}`,
+        ).to.be.fulfilled;
+      }
+    }
+
+    const properties = await token.getProperties(propertyKeys);
+    const tokenData = await token.getData();
+    for(let i = 0; i < properties.length; i++) {
+      expect(properties[i].value).to.be.equal('Serotonin increase');
+      expect(tokenData!.properties[i].value).to.be.equal('Serotonin increase');
+    }
+  }
+
+  itSub('Assigns properties to a token according to permissions (NFT)', async ({helper}) =>  {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+    await testAssignPropertiesAccordingToPermissions(token, amount);
+  });
+
+  itSub.ifWithPallets('Assigns properties to a token according to permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+    await testAssignPropertiesAccordingToPermissions(token, amount);
+  });
+
+  async function testChangesPropertiesAccordingPermission(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+    await token.collection.addAdmin(alice, {Substrate: bob.address});
+    await token.transfer(alice, {Substrate: charlie.address}, pieces);
+
+    const propertyKeys: string[] = [];
+    let i = 0;
+    for(const permission of permissions) {
+      i++;
+      if(!permission.permission.mutable) continue;
+
+      let j = 0;
+      for(const signer of permission.signers) {
+        j++;
+        const key = i + '_' + signer.address;
+        propertyKeys.push(key);
+
+        await expect(
+          token.setProperties(signer, [{key, value: 'Serotonin increase'}]),
+          `on adding property #${i} by signer #${j}`,
+        ).to.be.fulfilled;
+
+        await expect(
+          token.setProperties(signer, [{key, value: 'Serotonin stable'}]),
+          `on changing property #${i} by signer #${j}`,
+        ).to.be.fulfilled;
+      }
+    }
+
+    const properties = await token.getProperties(propertyKeys);
+    const tokenData = await token.getData();
+    for(let i = 0; i < properties.length; i++) {
+      expect(properties[i].value).to.be.equal('Serotonin stable');
+      expect(tokenData!.properties[i].value).to.be.equal('Serotonin stable');
+    }
+  }
+
+  itSub('Changes properties of a token according to permissions (NFT)', async ({helper}) =>  {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+    await testChangesPropertiesAccordingPermission(token, amount);
+  });
+
+  itSub.ifWithPallets('Changes properties of a token according to permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+    await testChangesPropertiesAccordingPermission(token, amount);
+  });
+
+  async function testDeletePropertiesAccordingPermission(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+    await token.collection.addAdmin(alice, {Substrate: bob.address});
+    await token.transfer(alice, {Substrate: charlie.address}, pieces);
+
+    const propertyKeys: string[] = [];
+    let i = 0;
+
+    for(const permission of permissions) {
+      i++;
+      if(!permission.permission.mutable) continue;
+
+      let j = 0;
+      for(const signer of permission.signers) {
+        j++;
+        const key = i + '_' + signer.address;
+        propertyKeys.push(key);
+
+        await expect(
+          token.setProperties(signer, [{key, value: 'Serotonin increase'}]),
+          `on adding property #${i} by signer #${j}`,
+        ).to.be.fulfilled;
+
+        await expect(
+          token.deleteProperties(signer, [key]),
+          `on deleting property #${i} by signer #${j}`,
+        ).to.be.fulfilled;
+      }
+    }
+
+    expect(await token.getProperties(propertyKeys)).to.be.empty;
+    expect((await token.getData())!.properties).to.be.empty;
+  }
+
+  itSub('Deletes properties of a token according to permissions (NFT)', async ({helper}) =>  {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+    await testDeletePropertiesAccordingPermission(token, amount);
+  });
+
+  itSub.ifWithPallets('Deletes properties of a token according to permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+    await testDeletePropertiesAccordingPermission(token, amount);
+  });
+
+  itSub('Assigns properties to a nested token according to permissions', async ({helper}) =>  {
+    const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+    const collectionB = await helper.nft.mintCollection(alice, {
+      tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
+        signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
+    });
+    const targetToken = await collectionA.mintToken(alice);
+    const nestedToken = await collectionB.mintToken(alice, targetToken.nestingAccount());
+
+    await collectionB.addAdmin(alice, {Substrate: bob.address});
+    await targetToken.transfer(alice, {Substrate: charlie.address});
+
+    const propertyKeys: string[] = [];
+    let i = 0;
+    for(const permission of permissions) {
+      i++;
+      let j = 0;
+      for(const signer of permission.signers) {
+        j++;
+        const key = i + '_' + signer.address;
+        propertyKeys.push(key);
+
+        await expect(
+          nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]),
+          `on adding property #${i} by signer #${j}`,
+        ).to.be.fulfilled;
+      }
+    }
+
+    const properties = await nestedToken.getProperties(propertyKeys);
+    const tokenData = await nestedToken.getData();
+    for(let i = 0; i < properties.length; i++) {
+      expect(properties[i].value).to.be.equal('Serotonin increase');
+      expect(tokenData!.properties[i].value).to.be.equal('Serotonin increase');
+    }
+    expect(await targetToken.getProperties()).to.be.empty;
+  });
+
+  itSub('Changes properties of a nested token according to permissions', async ({helper}) =>  {
+    const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+    const collectionB = await helper.nft.mintCollection(alice, {
+      tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
+        signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
+    });
+    const targetToken = await collectionA.mintToken(alice);
+    const nestedToken = await collectionB.mintToken(alice, targetToken.nestingAccount());
+
+    await collectionB.addAdmin(alice, {Substrate: bob.address});
+    await targetToken.transfer(alice, {Substrate: charlie.address});
+
+    const propertyKeys: string[] = [];
+    let i = 0;
+    for(const permission of permissions) {
+      i++;
+      if(!permission.permission.mutable) continue;
+
+      let j = 0;
+      for(const signer of permission.signers) {
+        j++;
+        const key = i + '_' + signer.address;
+        propertyKeys.push(key);
+
+        await expect(
+          nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]),
+          `on adding property #${i} by signer #${j}`,
+        ).to.be.fulfilled;
+
+        await expect(
+          nestedToken.setProperties(signer, [{key, value: 'Serotonin stable'}]),
+          `on changing property #${i} by signer #${j}`,
+        ).to.be.fulfilled;
+      }
+    }
+
+    const properties = await nestedToken.getProperties(propertyKeys);
+    const tokenData = await nestedToken.getData();
+    for(let i = 0; i < properties.length; i++) {
+      expect(properties[i].value).to.be.equal('Serotonin stable');
+      expect(tokenData!.properties[i].value).to.be.equal('Serotonin stable');
+    }
+    expect(await targetToken.getProperties()).to.be.empty;
+  });
+
+  itSub('Deletes properties of a nested token according to permissions', async ({helper}) =>  {
+    const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+    const collectionB = await helper.nft.mintCollection(alice, {
+      tokenPropertyPermissions: permissions.flatMap(({permission, signers}, i) =>
+        signers.map(signer => ({key: `${i+1}_${signer.address}`, permission}))),
+    });
+    const targetToken = await collectionA.mintToken(alice);
+    const nestedToken = await collectionB.mintToken(alice, targetToken.nestingAccount());
+
+    await collectionB.addAdmin(alice, {Substrate: bob.address});
+    await targetToken.transfer(alice, {Substrate: charlie.address});
+
+    const propertyKeys: string[] = [];
+    let i = 0;
+    for(const permission of permissions) {
+      i++;
+      if(!permission.permission.mutable) continue;
+
+      let j = 0;
+      for(const signer of permission.signers) {
+        j++;
+        const key = i + '_' + signer.address;
+        propertyKeys.push(key);
+
+        await expect(
+          nestedToken.setProperties(signer, [{key, value: 'Serotonin increase'}]),
+          `on adding property #${i} by signer #${j}`,
+        ).to.be.fulfilled;
+
+        await expect(
+          nestedToken.deleteProperties(signer, [key]),
+          `on deleting property #${i} by signer #${j}`,
+        ).to.be.fulfilled;
+      }
+    }
+
+    expect(await nestedToken.getProperties(propertyKeys)).to.be.empty;
+    expect((await nestedToken.getData())!.properties).to.be.empty;
+    expect(await targetToken.getProperties()).to.be.empty;
+  });
+
+  [
+    {mode: 'nft' as const, storage: 'nonfungible' as const, pieces: undefined, requiredPallets: []} as const,
+    {mode: 'rft' as const, storage: 'refungible' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]} as const,
+  ].map(testCase =>
+    itSub.ifWithPallets(`Allows modifying a token property multiple times with the same size (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
+      const propKey = 'tok-prop';
+
+      const collection = await helper[testCase.mode].mintCollection(alice, {
+        tokenPropertyPermissions: [
+          {
+            key: propKey,
+            permission: {mutable: true, tokenOwner: true},
+          },
+        ],
+      });
+
+      const maxTokenPropertiesSize = 32768;
+
+      const propDataSize = 4096;
+
+      let propDataChar = 'a';
+      const makeNewPropData = () => {
+        propDataChar = String.fromCharCode(propDataChar.charCodeAt(0) + 1);
+        return `${propDataChar}`.repeat(propDataSize);
+      };
+
+      const token = await (
+        testCase.pieces
+          ? collection.mintToken(alice, testCase.pieces as any)
+          : collection.mintToken(alice)
+      );
+
+      const property = {key: propKey, value: makeNewPropData()};
+      await token.setProperties(alice, [property]);
+      const originalSpace = await token.getTokenPropertiesConsumedSpace();
+      expect(originalSpace).to.be.equal(sizeOfProperty(property));
+
+      const sameSizePropertiesPossibleNum = maxTokenPropertiesSize / propDataSize;
+
+      // It is possible to modify a property as many times as needed.
+      // It will not consume any additional space.
+      for(let i = 0; i < sameSizePropertiesPossibleNum + 1; i++) {
+        await token.setProperties(alice, [{key: propKey, value: makeNewPropData()}]);
+        const consumedSpace = await token.getTokenPropertiesConsumedSpace();
+        expect(consumedSpace).to.be.equal(originalSpace);
+      }
+    }));
+
+  [
+    {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
+    {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
+  ].map(testCase =>
+    itSub.ifWithPallets(`Adding then removing a token property doesn't change the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
+      const propKey = 'tok-prop';
+
+      const collection = await helper[testCase.mode].mintCollection(alice, {
+        tokenPropertyPermissions: [
+          {
+            key: propKey,
+            permission: {mutable: true, tokenOwner: true},
+          },
+        ],
+      });
+      const token = await (
+        testCase.pieces
+          ? collection.mintToken(alice, testCase.pieces as any)
+          : collection.mintToken(alice)
+      );
+      const originalSpace = await token.getTokenPropertiesConsumedSpace();
+
+      const propDataSize = 4096;
+      const propData = 'a'.repeat(propDataSize);
+
+      const property = {key: propKey, value: propData};
+      await token.setProperties(alice, [property]);
+      let consumedSpace = await token.getTokenPropertiesConsumedSpace();
+      expect(consumedSpace).to.be.equal(sizeOfProperty(property));
+
+      await token.deleteProperties(alice, [propKey]);
+      consumedSpace = await token.getTokenPropertiesConsumedSpace();
+      expect(consumedSpace).to.be.equal(originalSpace);
+    }));
+
+  [
+    {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
+    {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
+  ].map(testCase =>
+    itSub.ifWithPallets(`Modifying a token property with different sizes correctly changes the consumed space (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
+      const propKey = 'tok-prop';
+
+      const collection = await helper[testCase.mode].mintCollection(alice, {
+        tokenPropertyPermissions: [
+          {
+            key: propKey,
+            permission: {mutable: true, tokenOwner: true},
+          },
+        ],
+      });
+      const token = await (
+        testCase.pieces
+          ? collection.mintToken(alice, testCase.pieces as any)
+          : collection.mintToken(alice)
+      );
+      const originalSpace = await token.getTokenPropertiesConsumedSpace();
+
+      const initProp = {key: propKey, value: 'a'.repeat(4096)};
+      const biggerProp = {key: propKey, value: 'b'.repeat(5000)};
+      const smallerProp = {key: propKey, value: 'c'.repeat(4000)};
+
+      let consumedSpace;
+      let expectedConsumedSpaceDiff;
+
+      await token.setProperties(alice, [initProp]);
+      consumedSpace = await token.getTokenPropertiesConsumedSpace();
+      expectedConsumedSpaceDiff = sizeOfProperty(initProp) - originalSpace;
+      expect(consumedSpace).to.be.equal(originalSpace + expectedConsumedSpaceDiff);
+
+      await token.setProperties(alice, [biggerProp]);
+      consumedSpace = await token.getTokenPropertiesConsumedSpace();
+      expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(initProp);
+      expect(consumedSpace).to.be.equal(sizeOfProperty(initProp) + expectedConsumedSpaceDiff);
+
+      await token.setProperties(alice, [smallerProp]);
+      consumedSpace = await token.getTokenPropertiesConsumedSpace();
+      expectedConsumedSpaceDiff = sizeOfProperty(biggerProp) - sizeOfProperty(smallerProp);
+      expect(consumedSpace).to.be.equal(sizeOfProperty(biggerProp) - expectedConsumedSpaceDiff);
+    }));
+
+  itSub('Set sponsored properties', async({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {tokenPropertyPermissions: [{key: 'k', permission: {tokenOwner: true}}]});
+
+    await collection.setSponsor(alice, alice.address);
+    await collection.confirmSponsorship(alice);
+    await collection.setPermissions(alice, {access: 'AllowList', mintMode: true});
+    await collection.addToAllowList(alice, {Substrate: bob.address});
+    await collection.setLimits(alice, {sponsoredDataRateLimit: {blocks: 30}});
+
+    const token = await collection.mintToken(alice, {Substrate: bob.address});
+
+    const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address);
+    const bobBalanceBefore = await helper.balance.getSubstrate(bob.address);
+
+    await token.setProperties(bob, [{key: 'k', value: 'val'}]);
+
+    const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address);
+    const bobBalanceAfter = await helper.balance.getSubstrate(bob.address);
+
+    expect(bobBalanceAfter).to.be.equal(bobBalanceBefore);
+    expect(aliceBalanceBefore > aliceBalanceAfter).to.be.true;
+  });
+});
+
+describe('Negative Integration Test: Token Properties', () => {
+  let alice: IKeyringPair; // collection owner
+  let bob: IKeyringPair; // collection admin
+  let charlie: IKeyringPair; // token owner
+
+  let constitution: {permission: any, signers: IKeyringPair[], sinner: IKeyringPair}[];
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      let dave: IKeyringPair;
+      [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);
+
+      // todo:playgrounds probably separate these tests later
+      constitution = [
+        {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},
+        {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},
+        {permission: {mutable: true, tokenOwner: true}, signers: [charlie], sinner: alice},
+        {permission: {mutable: false, tokenOwner: true}, signers: [charlie], sinner: alice},
+        {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},
+        {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},
+      ];
+    });
+  });
+
+  [
+    {mode: 'nft' as const, requiredPallets: [Pallets.NFT]},
+    {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+  ].map(testCase =>
+    itSub.ifWithPallets(`Forbids adding/deleting properties of a token if token doesn't exist (${testCase.mode.toLocaleUpperCase})`, testCase.requiredPallets, async({helper}) => {
+      const collection = await helper[testCase.mode].mintCollection(alice, {
+        tokenPropertyPermissions: constitution.slice(0, 1).map(({permission}) => ({key: '1', permission})),
+      });
+      const nonExistentToken = collection.getTokenObject(1);
+
+      await expect(
+        nonExistentToken.setProperties(alice, [{key: '1', value: 'Serotonin increase'}]),
+        'on expecting failure whilst adding a property by alice',
+      ).to.be.rejectedWith(/common\.TokenNotFound/);
+
+      await expect(
+        nonExistentToken.deleteProperties(alice, ['1']),
+        'on expecting failure whilst deleting a property by alice',
+      ).to.be.rejectedWith(/common\.TokenNotFound/);
+    }));
+
+  async function mintCollectionWithAllPermissionsAndToken(helper: UniqueHelper, mode: 'NFT' | 'RFT'): Promise<[UniqueNFToken | UniqueRFToken, bigint]> {
+    const collection = await (mode == 'NFT' ? helper.nft : helper.rft).mintCollection(alice, {
+      tokenPropertyPermissions: constitution.map(({permission}, i) => ({key: `${i+1}`, permission})),
+    });
+    return mode == 'NFT' ? [await collection.mintToken(alice), 1n] : [await collection.mintToken(alice, 100n as any), 100n];
+  }
+
+  async function getConsumedSpace(api: any, collectionId: number, tokenId: number, mode: 'NFT' | 'RFT'): Promise<number> {
+    return (await (mode == 'NFT' ? api.query.nonfungible : api.query.refungible).tokenProperties(collectionId, tokenId)).toJSON().consumedSpace;
+  }
+
+  async function prepare(token: UniqueNFToken | UniqueRFToken, pieces: bigint): Promise<number> {
+    await token.collection.addAdmin(alice, {Substrate: bob.address});
+    await token.transfer(alice, {Substrate: charlie.address}, pieces);
+
+    let i = 0;
+    for(const passage of constitution) {
+      i++;
+      const signer = passage.signers[0];
+      await expect(
+        token.setProperties(signer, [{key: `${i}`, value: 'Serotonin increase'}]),
+        `on adding property ${i} by ${signer.address}`,
+      ).to.be.fulfilled;
+    }
+
+    const originalSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
+    return originalSpace;
+  }
+
+  async function testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+    const originalSpace = await prepare(token, pieces);
+
+    let i = 0;
+    for(const forbiddance of constitution) {
+      i++;
+      if(!forbiddance.permission.mutable) continue;
+
+      await expect(
+        token.setProperties(forbiddance.sinner, [{key: `${i}`, value: 'Serotonin down'}]),
+        `on failing to change property ${i} by the malefactor`,
+      ).to.be.rejectedWith(/common\.NoPermission/);
+
+      await expect(
+        token.deleteProperties(forbiddance.sinner, [`${i}`]),
+        `on failing to delete property ${i} by the malefactor`,
+      ).to.be.rejectedWith(/common\.NoPermission/);
+    }
+
+    const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
+    expect(consumedSpace).to.be.equal(originalSpace);
+  }
+
+  itSub('Forbids changing/deleting properties of a token if the user is outside of permissions (NFT)', async ({helper}) =>  {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+    await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token, amount);
+  });
+
+  itSub.ifWithPallets('Forbids changing/deleting properties of a token if the user is outside of permissions (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+    await testForbidsChangingDeletingPropertiesUserOutsideOfPermissions(token, amount);
+  });
+
+  async function testForbidsChangingDeletingPropertiesIfPropertyImmutable(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+    const originalSpace = await prepare(token, pieces);
+
+    let i = 0;
+    for(const permission of constitution) {
+      i++;
+      if(permission.permission.mutable) continue;
+
+      await expect(
+        token.setProperties(permission.signers[0], [{key: `${i}`, value: 'Serotonin down'}]),
+        `on failing to change property ${i} by signer #0`,
+      ).to.be.rejectedWith(/common\.NoPermission/);
+
+      await expect(
+        token.deleteProperties(permission.signers[0], [i.toString()]),
+        `on failing to delete property ${i} by signer #0`,
+      ).to.be.rejectedWith(/common\.NoPermission/);
+    }
+
+    const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
+    expect(consumedSpace).to.be.equal(originalSpace);
+  }
+
+  itSub('Forbids changing/deleting properties of a token if the property is permanent (immutable) (NFT)', async ({helper}) =>  {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+    await testForbidsChangingDeletingPropertiesIfPropertyImmutable(token, amount);
+  });
+
+  itSub.ifWithPallets('Forbids changing/deleting properties of a token if the property is permanent (immutable) (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+    await testForbidsChangingDeletingPropertiesIfPropertyImmutable(token, amount);
+  });
+
+  async function testForbidsAddingPropertiesIfPropertyNotDeclared(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+    const originalSpace = await prepare(token, pieces);
+
+    await expect(
+      token.setProperties(alice, [{key: 'non-existent', value: 'I exist!'}]),
+      'on failing to add a previously non-existent property',
+    ).to.be.rejectedWith(/common\.NoPermission/);
+
+    await expect(
+      token.collection.setTokenPropertyPermissions(alice, [{key: 'now-existent', permission: {}}]),
+      'on setting a new non-permitted property',
+    ).to.be.fulfilled;
+
+    await expect(
+      token.setProperties(alice, [{key: 'now-existent', value: 'I exist!'}]),
+      'on failing to add a property forbidden by the \'None\' permission',
+    ).to.be.rejectedWith(/common\.NoPermission/);
+
+    expect(await token.getProperties(['non-existent', 'now-existent'])).to.be.empty;
+
+    const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
+    expect(consumedSpace).to.be.equal(originalSpace);
+  }
+
+  itSub('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (NFT)', async ({helper}) =>  {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+    await testForbidsAddingPropertiesIfPropertyNotDeclared(token, amount);
+  });
+
+  itSub.ifWithPallets('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+    await testForbidsAddingPropertiesIfPropertyNotDeclared(token, amount);
+  });
+
+  async function testForbidsAddingTooLargeProperties(token: UniqueNFToken | UniqueRFToken, pieces: bigint) {
+    const originalSpace = await prepare(token, pieces);
+
+    await expect(
+      token.collection.setTokenPropertyPermissions(alice, [
+        {key: 'a_holy_book', permission: {collectionAdmin: true, tokenOwner: true}},
+        {key: 'young_years', permission: {collectionAdmin: true, tokenOwner: true}},
+      ]),
+      'on setting new permissions for properties',
+    ).to.be.fulfilled;
+
+    // Mute the general tx parsing error
+    {
+      console.error = () => {};
+      await expect(token.setProperties(alice, [{key: 'a_holy_book', value: 'word '.repeat(6554)}]))
+        .to.be.rejected;
+    }
+
+    await expect(token.setProperties(alice, [
+      {key: 'a_holy_book', value: 'word '.repeat(3277)},
+      {key: 'young_years', value: 'neverending'.repeat(1490)},
+    ])).to.be.rejectedWith(/common\.NoSpaceForProperty/);
+
+    expect(await token.getProperties(['a_holy_book', 'young_years'])).to.be.empty;
+    const consumedSpace = await getConsumedSpace(token.collection.helper.getApi(), token.collectionId, token.tokenId, pieces == 1n ? 'NFT' : 'RFT');
+    expect(consumedSpace).to.be.equal(originalSpace);
+  }
+
+  itSub('Forbids adding too large properties to a token (NFT)', async ({helper}) =>  {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'NFT');
+    await testForbidsAddingTooLargeProperties(token, amount);
+  });
+
+  itSub.ifWithPallets('Forbids adding too large properties to a token (ReFungible)', [Pallets.ReFungible], async ({helper}) => {
+    const [token, amount] = await mintCollectionWithAllPermissionsAndToken(helper, 'RFT');
+    await testForbidsAddingTooLargeProperties(token, amount);
+  });
+
+  [
+    {mode: 'nft' as const, requiredPallets: []},
+    {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},
+  ].map(testCase =>
+    itSub.ifWithPallets(`Forbids adding too many propeties to a token (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
+      const collection = await helper[testCase.mode].mintCollection(alice);
+      const maxPropertiesPerItem = 64;
+
+      for(let i = 0; i < maxPropertiesPerItem; i++) {
+        await collection.setTokenPropertyPermissions(alice, [{
+          key: `${i+1}`,
+          permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
+        }]);
+      }
+
+      await expect(collection.setTokenPropertyPermissions(alice, [{
+        key: `${maxPropertiesPerItem}-th`,
+        permission: {mutable: true, tokenOwner: true, collectionAdmin: true},
+      }])).to.be.rejectedWith(/common\.PropertyLimitReached/);
+    }));
+
+  [
+    {mode: 'nft' as const, pieces: undefined, requiredPallets: []},
+    {mode: 'rft' as const, pieces: 100n, requiredPallets: [Pallets.ReFungible]},
+  ].map(testCase =>
+    itSub.ifWithPallets(`Forbids force_repair_item from non-sudo (${testCase.mode})`, testCase.requiredPallets, async({helper}) => {
+      const propKey = 'tok-prop';
+
+      const collection = await helper[testCase.mode].mintCollection(alice, {
+        tokenPropertyPermissions: [
+          {
+            key: propKey,
+            permission: {mutable: true, tokenOwner: true},
+          },
+        ],
+      });
+      const token = await (
+        testCase.pieces
+          ? collection.mintToken(alice, testCase.pieces as any)
+          : collection.mintToken(alice)
+      );
+
+      const propDataSize = 4096;
+      const propData = 'a'.repeat(propDataSize);
+      await token.setProperties(alice, [{key: propKey, value: propData}]);
+
+      await expect(helper.executeExtrinsic(alice, 'api.tx.unique.forceRepairItem', [token.collectionId, token.tokenId], true))
+        .to.be.rejectedWith(/BadOrigin/);
+    }));
+});
+
+describe('ReFungible token properties permissions tests', () => {
+  let alice: IKeyringPair;
+  let bob: IKeyringPair;
+  let charlie: IKeyringPair;
+
+  before(async function() {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      const donor = await privateKey({url: import.meta.url});
+      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+    });
+  });
+
+  async function prepare(helper: UniqueHelper): Promise<UniqueRFToken> {
+    const collection = await helper.rft.mintCollection(alice);
+    const token = await collection.mintToken(alice, 100n);
+
+    await collection.addAdmin(alice, {Substrate: bob.address});
+    await collection.setTokenPropertyPermissions(alice, [{key: 'fractals', permission: {mutable: true, tokenOwner: true}}]);
+
+    return token;
+  }
+
+  itSub('Forbids adding token property with tokenOwner==true when signer doesn\'t have all pieces', async ({helper}) =>  {
+    const token = await prepare(helper);
+
+    await token.transfer(alice, {Substrate: charlie.address}, 33n);
+
+    await expect(token.setProperties(alice, [
+      {key: 'fractals', value: 'multiverse'},
+    ])).to.be.rejectedWith(/common\.NoPermission/);
+  });
+
+  itSub('Forbids mutating token property with tokenOwner==true when signer doesn\'t have all pieces', async ({helper}) =>  {
+    const token = await prepare(helper);
+
+    await expect(token.collection.setTokenPropertyPermissions(alice, [{key: 'fractals', permission: {mutable:true, tokenOwner: true}}]))
+      .to.be.fulfilled;
+
+    await expect(token.setProperties(alice, [
+      {key: 'fractals', value: 'multiverse'},
+    ])).to.be.fulfilled;
+
+    await token.transfer(alice, {Substrate: charlie.address}, 33n);
+
+    await expect(token.setProperties(alice, [
+      {key: 'fractals', value: 'want to rule the world'},
+    ])).to.be.rejectedWith(/common\.NoPermission/);
+  });
+
+  itSub('Forbids deleting token property with tokenOwner==true when signer doesn\'t have all pieces', async ({helper}) =>  {
+    const token = await prepare(helper);
+
+    await expect(token.setProperties(alice, [
+      {key: 'fractals', value: 'one headline - why believe it'},
+    ])).to.be.fulfilled;
+
+    await token.transfer(alice, {Substrate: charlie.address}, 33n);
+
+    await expect(token.deleteProperties(alice, ['fractals'])).
+      to.be.rejectedWith(/common\.NoPermission/);
+  });
+
+  itSub('Allows token property mutation with collectionOwner==true when admin doesn\'t have all pieces', async ({helper}) =>  {
+    const token = await prepare(helper);
+
+    await token.transfer(alice, {Substrate: charlie.address}, 33n);
+
+    await expect(token.collection.setTokenPropertyPermissions(alice, [{key: 'fractals', permission: {mutable:true, collectionAdmin: true}}]))
+      .to.be.fulfilled;
+
+    await expect(token.setProperties(alice, [
+      {key: 'fractals', value: 'multiverse'},
+    ])).to.be.fulfilled;
+  });
+});
addedjs-packages/tests/sub/nesting/unnest.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/js-packages/tests/sub/nesting/unnest.test.ts
@@ -0,0 +1,325 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import type {IKeyringPair} from '@polkadot/types/types';
+import {expect, itSub, Pallets, usingPlaygrounds} from '../../util/index.js';
+import {CrossAccountId, UniqueFTCollection, UniqueNFToken, UniqueRFToken} from '@unique/playgrounds/unique.js';
+
+describe('Integration Test: Unnesting', () => {
+  let alice: IKeyringPair;
+  let bob: IKeyringPair;
+  let charlie: IKeyringPair;
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 50n, 50n], donor);
+    });
+  });
+
+  itSub('NFT: allows the owner to successfully unnest a token', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+    const targetToken = await collection.mintToken(alice);
+
+    // Create a nested token
+    const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
+
+    // Unnest
+    await expect(nestedToken.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}), 'while unnesting').to.be.fulfilled;
+    expect(await nestedToken.getOwner()).to.be.deep.equal({Substrate: alice.address});
+
+    // Nest and burn
+    await nestedToken.nest(alice, targetToken);
+    await expect(nestedToken.burnFrom(alice, targetToken.nestingAccount()), 'while burning').to.be.fulfilled;
+    await expect(nestedToken.getOwner()).to.be.rejected;
+  });
+
+  itSub('NativeFungible: allows the owner to successfully unnest a token', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+    const targetToken = await collection.mintToken(alice);
+
+    const collectionFT = helper.ft.getCollectionObject(0);
+
+    // Nest
+    await collectionFT.transfer(alice, targetToken.nestingAccount(), 10n);
+    // Unnest
+    await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;
+
+    expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
+  });
+
+  itSub('Fungible: allows the owner to successfully unnest a token', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+    const targetToken = await collection.mintToken(alice);
+
+    const collectionFT = await helper.ft.mintCollection(alice);
+
+    // Nest and unnest
+    await collectionFT.mint(alice, 10n, targetToken.nestingAccount());
+    await expect(collectionFT.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;
+    expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(9n);
+    expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
+
+    // Nest and burn
+    await collectionFT.transfer(alice, targetToken.nestingAccount(), 5n);
+    await expect(collectionFT.burnTokensFrom(alice, targetToken.nestingAccount(), 6n), 'while burning').to.be.fulfilled;
+    expect(await collectionFT.getBalance({Substrate: alice.address})).to.be.equal(4n);
+    expect(await collectionFT.getBalance(targetToken.nestingAccount())).to.be.equal(0n);
+    expect(await targetToken.getChildren()).to.be.length(0);
+  });
+
+  itSub.ifWithPallets('ReFungible: allows the owner to successfully unnest a token', [Pallets.ReFungible], async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+    const targetToken = await collection.mintToken(alice);
+
+    const collectionRFT = await helper.rft.mintCollection(alice);
+
+    // Nest and unnest
+    const token = await collectionRFT.mintToken(alice, 10n, targetToken.nestingAccount());
+    await expect(token.transferFrom(alice, targetToken.nestingAccount(), {Substrate: alice.address}, 9n), 'while unnesting').to.be.fulfilled;
+    expect(await token.getBalance({Substrate: alice.address})).to.be.equal(9n);
+    expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(1n);
+
+    // Nest and burn
+    await token.transfer(alice, targetToken.nestingAccount(), 5n);
+    await expect(token.burnFrom(alice, targetToken.nestingAccount(), 6n), 'while burning').to.be.fulfilled;
+    expect(await token.getBalance({Substrate: alice.address})).to.be.equal(4n);
+    expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(0n);
+    expect(await targetToken.getChildren()).to.be.length(0);
+  });
+
+  async function checkNestedAmountState({
+    expectedBalance,
+    childrenShouldPresent,
+    nested,
+    targetNft,
+  }: {
+    expectedBalance: bigint,
+    childrenShouldPresent: boolean,
+    nested: UniqueFTCollection | UniqueRFToken,
+    targetNft: UniqueNFToken,
+  }) {
+    const balance = await nested.getBalance(targetNft.nestingAccount());
+    expect(balance).to.be.equal(expectedBalance);
+
+    const children = await targetNft.getChildren();
+
+    if(childrenShouldPresent) {
+      expect(children[0]).to.be.deep.equal({
+        collectionId: nested.collectionId,
+        tokenId: (nested instanceof UniqueFTCollection) ? 0 : nested.tokenId,
+      });
+    } else {
+      expect(children.length).to.be.equal(0);
+    }
+  }
+
+  function ownerOrAdminUnnestCases(modes: ('ft' | 'nft' | 'rft')[]): {
+    mode: 'ft' | 'nft' | 'rft',
+    sender: string,
+    op: 'transfer' | 'burn',
+    requiredPallets: Pallets[],
+  }[] {
+    const senders = ['owner', 'admin'];
+    const ops = ['transfer', 'burn'];
+
+    const cases = [];
+    for(const mode of modes) {
+      const requiredPallets = (mode === 'rft')
+        ? [Pallets.ReFungible]
+        : [];
+
+      for(const sender of senders) {
+        for(const op of ops) {
+          cases.push({
+            mode: mode as 'ft' | 'nft' | 'rft',
+            sender,
+            op: op as 'transfer' | 'burn',
+            requiredPallets,
+          });
+        }
+      }
+    }
+
+    return cases;
+  }
+
+  ownerOrAdminUnnestCases(['ft', 'rft']).map(testCase =>
+    itSub.ifWithPallets(`[${testCase.mode}]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, testCase.requiredPallets, async({helper}) => {
+      const owner = alice;
+      const admin = bob;
+
+      const unnester = (testCase.sender === 'owner')
+        ? owner
+        : admin;
+
+      const collectionNFT = await helper.nft.mintCollection(owner);
+      await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});
+
+      const collectionNested = await helper[testCase.mode as 'ft' | 'rft'].mintCollection(owner, {
+        limits: {
+          ownerCanTransfer: true,
+        },
+      });
+      await collectionNested.addAdmin(owner, {Substrate: admin.address});
+
+      const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});
+
+      let nested: UniqueFTCollection | UniqueRFToken;
+      const totalAmount = 5n;
+      const firstUnnestAmount = 2n;
+      const restUnnestAmount = totalAmount - firstUnnestAmount;
+
+      if(collectionNested instanceof UniqueFTCollection) {
+        await collectionNested.mint(owner, totalAmount, {Substrate: charlie.address});
+        nested = collectionNested;
+      } else {
+        nested = await collectionNested.mintToken(owner, totalAmount, {Substrate: charlie.address});
+      }
+
+      // transfer/burn `amount` of nested assets by `unnester`.
+      const doOperationAndCheck = async ({
+        amount,
+        shouldBeNestedAfterOp,
+      }: {
+        amount: bigint,
+        shouldBeNestedAfterOp: boolean,
+      }) => {
+        const nestedBalanceBeforeOp = await nested.getBalance(targetNft.nestingAccount());
+
+        if(testCase.op === 'transfer') {
+          const bobBalanceBeforeOp = await nested.getBalance({Substrate: bob.address});
+
+          await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address}, amount);
+          expect(await nested.getBalance({Substrate: bob.address})).to.be.equal(bobBalanceBeforeOp + amount);
+        } else {
+          if(nested instanceof UniqueFTCollection) {
+            await nested.burnTokensFrom(unnester, targetNft.nestingAccount(), amount);
+          } else {
+            await nested.burnFrom(unnester, targetNft.nestingAccount(), amount);
+          }
+        }
+
+        await checkNestedAmountState({
+          expectedBalance: nestedBalanceBeforeOp - amount,
+          childrenShouldPresent: shouldBeNestedAfterOp,
+          nested,
+          targetNft,
+        });
+      };
+
+      // Initial setup: nest (fungibles/rft parts).
+      // Check NFT's balance of nested assets and NFT's children.
+      await nested.transfer(charlie, targetNft.nestingAccount(), totalAmount);
+      await checkNestedAmountState({
+        expectedBalance: totalAmount,
+        childrenShouldPresent: true,
+        nested,
+        targetNft,
+      });
+
+      // Transfer/burn only a part of nested assets.
+      // Check that NFT's balance of the nested assets correctly decreased and NFT's children are not changed.
+      await doOperationAndCheck({
+        amount: firstUnnestAmount,
+        shouldBeNestedAfterOp: true,
+      });
+
+      // Transfer/burn all remaining nested assets.
+      // Check that NFT's balance of the nested assets is 0 and NFT has no more children.
+      await doOperationAndCheck({
+        amount: restUnnestAmount,
+        shouldBeNestedAfterOp: false,
+      });
+    }));
+
+  ownerOrAdminUnnestCases(['nft']).map(testCase =>
+    itSub(`[nft]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, async ({helper}) => {
+      const owner = alice;
+      const admin = bob;
+
+      const unnester = (testCase.sender === 'owner')
+        ? owner
+        : admin;
+
+      const collectionNFT = await helper.nft.mintCollection(owner);
+      await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});
+
+      const collectionNested = await helper.nft.mintCollection(owner, {
+        limits: {
+          ownerCanTransfer: true,
+        },
+      });
+      await collectionNested.addAdmin(owner, {Substrate: admin.address});
+
+      const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});
+      const nested = await collectionNested.mintToken(owner, {Substrate: charlie.address});
+
+      await nested.transfer(charlie, targetNft.nestingAccount());
+      expect(await targetNft.getChildren()).to.be.deep.equal([{
+        collectionId: nested.collectionId,
+        tokenId: nested.tokenId,
+      }]);
+
+      if(testCase.op === 'transfer') {
+        await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address});
+      } else {
+        await nested.burnFrom(unnester, targetNft.nestingAccount());
+      }
+
+      expect((await targetNft.getChildren()).length).to.be.equal(0);
+    }));
+});
+
+describe('Negative Test: Unnesting', () => {
+  let alice: IKeyringPair;
+  let bob: IKeyringPair;
+
+  before(async () => {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      const donor = await privateKey({url: import.meta.url});
+      [alice, bob] = await helper.arrange.createAccounts([50n, 10n], donor);
+    });
+  });
+
+  itSub('Disallows a non-owner to unnest/burn a token', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+    const targetToken = await collection.mintToken(alice);
+
+    // Create a nested token
+    const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
+
+    // Try to unnest
+    await expect(nestedToken.unnest(bob, targetToken, {Substrate: alice.address})).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+    expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
+
+    // Try to burn
+    await expect(nestedToken.burnFrom(bob, targetToken.nestingAccount())).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
+    expect(await nestedToken.getOwner()).to.be.deep.equal(CrossAccountId.toLowerCase(targetToken.nestingAccount()));
+  });
+
+  // todo another test for creating excessive depth matryoshka with Ethereum?
+
+  // Recursive nesting
+  itSub('Prevents Ouroboros creation', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+    const targetToken = await collection.mintToken(alice);
+
+    // Fail to create a nested token ouroboros
+    const nestedToken = await collection.mintToken(alice, targetToken.nestingAccount());
+    await expect(targetToken.nest(alice, nestedToken)).to.be.rejectedWith(/^structure\.OuroborosDetected$/);
+  });
+});
modifiedjs-packages/tests/util/globalSetup.tsdiffbeforeafterboth
--- a/js-packages/tests/util/globalSetup.ts
+++ b/js-packages/tests/util/globalSetup.ts
@@ -81,7 +81,7 @@
         if(aliceBalance < MINIMUM_DONOR_FUND * oneToken) {
           tx.push(helper.executeExtrinsic(
             alice,
-            'api.tx.balances.transfer',
+            'api.tx.balances.transferKeepAlive',
             [account.address, DONOR_FUNDING * oneToken],
             true,
             {nonce: nonce + balanceGrantedCounter++},
modifiednode/cli/src/service.rsdiffbeforeafterboth
--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -419,6 +419,7 @@
 				Box::new(block_announce_validator)
 			})),
 			warp_sync_params: None,
+			block_relay: None,
 		})?;
 
 	let select_chain = params.select_chain.clone();
@@ -778,6 +779,8 @@
 		},
 		collator_key,
 		relay_chain_slot_duration,
+		#[cfg(not(feature = "lookahead"))]
+		collation_request_receiver: None,
 	};
 
 	task_manager.spawn_essential_handle().spawn(
@@ -887,6 +890,7 @@
 			import_queue,
 			block_announce_validator_builder: None,
 			warp_sync_params: None,
+			block_relay: None,
 		})?;
 
 	let collator = config.role.is_authority();
modifiedpallets/evm-transaction-payment/src/lib.rsdiffbeforeafterboth
--- a/pallets/evm-transaction-payment/src/lib.rs
+++ b/pallets/evm-transaction-payment/src/lib.rs
@@ -171,13 +171,13 @@
 		origin: &T::CrossAccountId,
 	) -> Result<(), TransactionValidationError> {
 		let who = &v.who;
-		let max_fee_per_gas = Some(v.transaction_fee_input()?.0);
+		let max_fee_per_gas = v.transaction_fee_input()?.0;
 		let gas_limit = v.transaction.gas_limit.low_u64();
 		let reason = if let Some(to) = v.transaction.to {
 			WithdrawReason::Call {
 				target: to,
 				input: v.transaction.input.clone(),
-				max_fee_per_gas,
+				max_fee_per_gas: Some(max_fee_per_gas),
 				gas_limit,
 				is_transactional: v.config.is_transactional,
 				is_check: true,
@@ -187,7 +187,7 @@
 		};
 		let sponsor = get_sponsor::<T>(
 			*origin.as_eth(),
-			max_fee_per_gas,
+			Some(max_fee_per_gas),
 			gas_limit,
 			&reason,
 			v.config.is_transactional,
@@ -196,9 +196,7 @@
 		.as_ref()
 		.map(pallet_evm::Pallet::<T>::account_basic_by_id)
 		.map(|v| v.0);
-		let fee = max_fee_per_gas
-			.unwrap()
-			.saturating_mul(v.transaction.gas_limit);
+		let fee = max_fee_per_gas.saturating_mul(v.transaction.gas_limit);
 		if let Some(sponsor) = sponsor.as_ref() {
 			if who.balance < v.transaction.value || sponsor.balance < fee {
 				return Err(TransactionValidationError::BalanceTooLow);
modifiedpallets/inflation/Cargo.tomldiffbeforeafterboth
--- a/pallets/inflation/Cargo.toml
+++ b/pallets/inflation/Cargo.toml
@@ -16,6 +16,7 @@
 
 [features]
 default = ['std']
+fast-inflation = []
 runtime-benchmarks = ['frame-benchmarking']
 std = [
 	'frame-benchmarking/std',
@@ -27,7 +28,6 @@
 	'sp-std/std',
 ]
 try-runtime = ["frame-support/try-runtime"]
-fast-inflation = []
 
 [dependencies]
 parity-scale-codec = { workspace = true }
modifiedprimitives/common/src/constants.rsdiffbeforeafterboth
--- a/primitives/common/src/constants.rs
+++ b/primitives/common/src/constants.rs
@@ -26,7 +26,7 @@
 #[cfg(not(feature = "lookahead"))]
 pub const MILLISECS_PER_BLOCK: u64 = 12000;
 #[cfg(feature = "lookahead")]
-pub const MILLISECS_PER_BLOCK: u64 = 3000;
+pub const MILLISECS_PER_BLOCK: u64 = 6000;
 pub const MILLISECS_PER_RELAY_BLOCK: u64 = 6000;
 
 pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
modifiedruntime/common/config/pallets/preimage.rsdiffbeforeafterboth
--- a/runtime/common/config/pallets/preimage.rs
+++ b/runtime/common/config/pallets/preimage.rs
@@ -14,14 +14,18 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
-use frame_support::parameter_types;
+use frame_support::{
+	parameter_types,
+	traits::{fungible::HoldConsideration, LinearStoragePrice},
+};
 use frame_system::EnsureRoot;
 use up_common::constants::*;
 
-use crate::{AccountId, Balance, Balances, Runtime, RuntimeEvent};
+use crate::{AccountId, Balance, Balances, Runtime, RuntimeEvent, RuntimeHoldReason};
 
 parameter_types! {
 	pub PreimageBaseDeposit: Balance = 1000 * UNIQUE;
+	pub const PreimageHoldReason: RuntimeHoldReason = RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage);
 }
 
 impl pallet_preimage::Config for Runtime {
@@ -29,6 +33,10 @@
 	type RuntimeEvent = RuntimeEvent;
 	type Currency = Balances;
 	type ManagerOrigin = EnsureRoot<AccountId>;
-	type BaseDeposit = PreimageBaseDeposit;
-	type ByteDeposit = TransactionByteFee;
+	type Consideration = HoldConsideration<
+		AccountId,
+		Balances,
+		PreimageHoldReason,
+		LinearStoragePrice<PreimageBaseDeposit, TransactionByteFee, Balance>,
+	>;
 }
modifiedruntime/common/config/parachain.rsdiffbeforeafterboth
--- a/runtime/common/config/parachain.rs
+++ b/runtime/common/config/parachain.rs
@@ -26,7 +26,7 @@
 
 impl cumulus_pallet_parachain_system::Config for Runtime {
 	type RuntimeEvent = RuntimeEvent;
-	type SelfParaId = parachain_info::Pallet<Self>;
+	type SelfParaId = staging_parachain_info::Pallet<Self>;
 	type OnSystemEvent = ();
 	// type DownwardMessageHandlers = cumulus_primitives_utility::UnqueuedDmpAsParent<
 	// 	MaxDownwardMessageWeight,
@@ -43,9 +43,11 @@
 	#[cfg(feature = "lookahead")]
 	type CheckAssociatedRelayNumber =
 		cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases;
+	#[cfg(feature = "lookahead")]
+	type ConsensusHook = ConsensusHook;
 }
 
-impl parachain_info::Config for Runtime {}
+impl staging_parachain_info::Config for Runtime {}
 
 impl cumulus_pallet_aura_ext::Config for Runtime {}
 
modifiedruntime/common/config/substrate.rsdiffbeforeafterboth
--- a/runtime/common/config/substrate.rs
+++ b/runtime/common/config/substrate.rs
@@ -17,7 +17,10 @@
 use frame_support::{
 	dispatch::DispatchClass,
 	ord_parameter_types, parameter_types,
-	traits::{ConstBool, ConstU32, Everything, NeverEnsureOrigin},
+	traits::{
+		tokens::{PayFromAccount, UnityAssetBalanceConversion},
+		ConstBool, ConstU32, ConstU64, Everything, NeverEnsureOrigin,
+	},
 	weights::{
 		constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight},
 		ConstantMultiplier,
@@ -31,7 +34,7 @@
 use pallet_transaction_payment::{ConstFeeMultiplier, Multiplier};
 use sp_arithmetic::traits::One;
 use sp_runtime::{
-	traits::{AccountIdLookup, BlakeTwo256},
+	traits::{AccountIdLookup, BlakeTwo256, IdentityLookup},
 	Perbill, Percent, Permill,
 };
 use sp_std::vec;
@@ -39,7 +42,8 @@
 
 use crate::{
 	runtime_common::DealWithFees, Balances, Block, OriginCaller, PalletInfo, Runtime, RuntimeCall,
-	RuntimeEvent, RuntimeHoldReason, RuntimeOrigin, SS58Prefix, System, Version,
+	RuntimeEvent, RuntimeFreezeReason, RuntimeHoldReason, RuntimeOrigin, SS58Prefix, System,
+	Treasury, Version,
 };
 
 parameter_types! {
@@ -132,17 +136,16 @@
 	// Only root can perform this migration
 	type SignedFilter = EnsureSignedBy<TrieMigrationSigned, AccountId>;
 	type MaxKeyLen = MigrationMaxKeyLen;
-}
-
-parameter_types! {
-	pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
 }
 
 impl pallet_timestamp::Config for Runtime {
 	/// A timestamp: milliseconds since the unix epoch.
 	type Moment = u64;
 	type OnTimestampSet = ();
-	type MinimumPeriod = MinimumPeriod;
+	#[cfg(not(feature = "lookahead"))]
+	type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
+	#[cfg(feature = "lookahead")]
+	type MinimumPeriod = ConstU64<0>;
 	type WeightInfo = ();
 }
 
@@ -171,6 +174,7 @@
 	type AccountStore = System;
 	type WeightInfo = pallet_balances::weights::SubstrateWeight<Self>;
 	type RuntimeHoldReason = RuntimeHoldReason;
+	type RuntimeFreezeReason = RuntimeFreezeReason;
 	type FreezeIdentifier = [u8; 16];
 	type MaxHolds = MaxHolds;
 	type MaxFreezes = MaxFreezes;
@@ -206,6 +210,7 @@
 	pub const BountyDepositBase: Balance = 1 * UNIQUE;
 	pub const BountyDepositPayoutDelay: BlockNumber = 1 * DAYS;
 	pub const TreasuryModuleId: PalletId = PalletId(*b"py/trsry");
+	pub TreasuryAccount: AccountId = Treasury::account_id();
 	pub const BountyUpdatePeriod: BlockNumber = 14 * DAYS;
 	pub const MaximumReasonLength: u32 = 16384;
 	pub const BountyCuratorDeposit: Permill = Permill::from_percent(50);
@@ -230,6 +235,14 @@
 	type SpendFunds = ();
 	type WeightInfo = pallet_treasury::weights::SubstrateWeight<Self>;
 	type MaxApprovals = MaxApprovals;
+	type AssetKind = ();
+	type Beneficiary = AccountId;
+	type BeneficiaryLookup = IdentityLookup<Self::Beneficiary>;
+	type Paymaster = PayFromAccount<Balances, TreasuryAccount>;
+	type BalanceConverter = UnityAssetBalanceConversion;
+	type PayoutPeriod = ConstU32<10>;
+	#[cfg(feature = "runtime-benchmarks")]
+	type BenchmarkHelper = ();
 }
 
 impl pallet_sudo::Config for Runtime {
@@ -247,6 +260,8 @@
 	type DisabledValidators = ();
 	type MaxAuthorities = MaxAuthorities;
 	type AllowMultipleBlocksPerSlot = ConstBool<true>;
+	#[cfg(feature = "lookahead")]
+	type SlotDuration = ConstU64<SLOT_DURATION>;
 }
 
 impl pallet_utility::Config for Runtime {
modifiedruntime/common/config/xcm/foreignassets.rsdiffbeforeafterboth
--- a/runtime/common/config/xcm/foreignassets.rs
+++ b/runtime/common/config/xcm/foreignassets.rs
@@ -132,7 +132,11 @@
 
 	fn check_out(_dest: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {}
 
-	fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult {
+	fn deposit_asset(
+		what: &MultiAsset,
+		who: &MultiLocation,
+		context: Option<&XcmContext>,
+	) -> XcmResult {
 		FungiblesTransactor::deposit_asset(what, who, context)
 	}
 
modifiedruntime/common/config/xcm/mod.rsdiffbeforeafterboth
--- a/runtime/common/config/xcm/mod.rs
+++ b/runtime/common/config/xcm/mod.rs
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
+use cumulus_primitives_core::ParaId;
 use frame_support::{
 	parameter_types,
 	traits::{ConstU32, Contains, Everything, Get, Nothing, ProcessMessageError},
@@ -21,6 +22,7 @@
 use frame_system::EnsureRoot;
 use pallet_xcm::XcmPassthrough;
 use polkadot_parachain_primitives::primitives::Sibling;
+use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery;
 use sp_std::marker::PhantomData;
 use staging_xcm::{
 	latest::{prelude::*, MultiLocation, Weight},
@@ -283,7 +285,6 @@
 	type RuntimeEvent = RuntimeEvent;
 	type XcmExecutor = XcmExecutor<XcmExecutorConfig<Self>>;
 }
-
 impl cumulus_pallet_xcmp_queue::Config for Runtime {
 	type WeightInfo = ();
 	type RuntimeEvent = RuntimeEvent;
@@ -299,7 +300,7 @@
 	type ControllerOrigin = frame_system::EnsureRoot<AccountId>;
 
 	type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
-	type PriceForSiblingDelivery = ();
+	type PriceForSiblingDelivery = NoPriceForMessageDelivery<ParaId>;
 }
 
 impl cumulus_pallet_dmp_queue::Config for Runtime {
modifiedruntime/common/construct_runtime.rsdiffbeforeafterboth
--- a/runtime/common/construct_runtime.rs
+++ b/runtime/common/construct_runtime.rs
@@ -24,7 +24,7 @@
 				StateTrieMigration: pallet_state_trie_migration = 1,
 
 				ParachainSystem: cumulus_pallet_parachain_system = 20,
-				ParachainInfo: parachain_info = 21,
+				ParachainInfo: staging_parachain_info = 21,
 
 				#[cfg(feature = "collator-selection")]
 				Authorship: pallet_authorship = 22,
modifiedruntime/common/ethereum/precompiles/utils/mod.rsdiffbeforeafterboth
--- a/runtime/common/ethereum/precompiles/utils/mod.rs
+++ b/runtime/common/ethereum/precompiles/utils/mod.rs
@@ -22,7 +22,7 @@
 
 mod data;
 
-pub use data::{Bytes, EvmData, EvmDataReader, EvmDataWriter};
+pub use data::{Bytes, EvmDataReader, EvmDataWriter};
 
 /// Alias for Result returning an EVM precompile error.
 pub type EvmResult<T = ()> = Result<T, PrecompileFailure>;
modifiedruntime/common/mod.rsdiffbeforeafterboth
--- a/runtime/common/mod.rs
+++ b/runtime/common/mod.rs
@@ -43,10 +43,7 @@
 use sp_version::NativeVersion;
 use up_common::types::{AccountId, BlockNumber};
 
-use crate::{
-	AllPalletsWithSystem, Aura, Balances, InherentDataExt, Runtime, RuntimeCall, Signature,
-	Treasury,
-};
+use crate::{AllPalletsWithSystem, Aura, Balances, Runtime, RuntimeCall, Signature, Treasury};
 
 #[macro_export]
 macro_rules! unsupported {
@@ -83,19 +80,17 @@
 		can_author_with: Default::default(),
 	}
 }
-
-pub type ChargeTransactionPayment = pallet_charge_transaction::ChargeTransactionPayment<Runtime>;
 
 pub type SignedExtra = (
 	frame_system::CheckSpecVersion<Runtime>,
 	frame_system::CheckTxVersion<Runtime>,
 	frame_system::CheckGenesis<Runtime>,
 	frame_system::CheckEra<Runtime>,
-	frame_system::CheckNonce<Runtime>,
+	pallet_charge_transaction::CheckNonce<Runtime>,
 	frame_system::CheckWeight<Runtime>,
 	maintenance::CheckMaintenance,
 	identity::DisableIdentityCalls,
-	ChargeTransactionPayment,
+	pallet_charge_transaction::ChargeTransactionPayment<Runtime>,
 	//pallet_contract_helpers::ContractHelpersExtension<Runtime>,
 	pallet_ethereum::FakeTransactionFinalizer<Runtime>,
 );
@@ -146,13 +141,17 @@
 	}
 }
 
+#[cfg(not(feature = "lookahead"))]
 pub(crate) struct CheckInherents;
 
+#[cfg(not(feature = "lookahead"))]
 impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
 	fn check_inherents(
 		block: &Block,
 		relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
 	) -> sp_inherents::CheckInherentsResult {
+		use crate::InherentDataExt;
+
 		let relay_chain_slot = relay_state_proof
 			.read_slot()
 			.expect("Could not read the relay chain slot from the proof");
modifiedruntime/common/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/runtime_apis.rs
+++ b/runtime/common/runtime_apis.rs
@@ -485,7 +485,14 @@
 
 			impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
 				fn slot_duration() -> sp_consensus_aura::SlotDuration {
-					sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
+					#[cfg(not(feature = "lookahead"))]
+					{
+						sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
+					}
+					#[cfg(feature = "lookahead")]
+					{
+						sp_consensus_aura::SlotDuration::from_millis(up_common::constants::SLOT_DURATION)
+					}
 				}
 
 				fn authorities() -> Vec<AuraId> {
modifiedruntime/common/tests/xcm.rsdiffbeforeafterboth
--- a/runtime/common/tests/xcm.rs
+++ b/runtime/common/tests/xcm.rs
@@ -37,10 +37,12 @@
 			Box::new(VersionedXcm::from(Xcm(vec![Transact {
 				origin_kind: OriginKind::Native,
 				require_weight_at_most: Weight::from_parts(1000, 1000),
-				call: RuntimeCall::Balances(pallet_balances::Call::<Runtime>::transfer {
-					dest: BOB.into(),
-					value: INITIAL_BALANCE / 2,
-				})
+				call: RuntimeCall::Balances(
+					pallet_balances::Call::<Runtime>::transfer_keep_alive {
+						dest: BOB.into(),
+						value: INITIAL_BALANCE / 2,
+					},
+				)
 				.encode()
 				.into(),
 			}]))),
modifiedruntime/opal/Cargo.tomldiffbeforeafterboth
--- a/runtime/opal/Cargo.toml
+++ b/runtime/opal/Cargo.toml
@@ -61,6 +61,7 @@
 	'pallet-unique/runtime-benchmarks',
 	'pallet-utility/runtime-benchmarks',
 	'pallet-xcm/runtime-benchmarks',
+	'polkadot-runtime-common/runtime-benchmarks',
 	'sp-runtime/runtime-benchmarks',
 	'staging-xcm-builder/runtime-benchmarks',
 ]
@@ -126,7 +127,7 @@
 	'pallet-treasury/std',
 	'pallet-unique/std',
 	'pallet-utility/std',
-	'parachain-info/std',
+	'polkadot-runtime-common/std',
 	'serde',
 	'sp-api/std',
 	'sp-block-builder/std',
@@ -140,6 +141,7 @@
 	'sp-storage/std',
 	'sp-transaction-pool/std',
 	'sp-version/std',
+	'staging-parachain-info/std',
 	'staging-xcm-builder/std',
 	'staging-xcm-executor/std',
 	'staging-xcm/std',
@@ -220,19 +222,20 @@
 	'pallet-unique/try-runtime',
 	'pallet-utility/try-runtime',
 	'pallet-xcm/try-runtime',
-	'parachain-info/try-runtime',
+	'polkadot-runtime-common/try-runtime',
+	'staging-parachain-info/try-runtime',
 ]
 
 app-promotion = []
 collator-selection = []
+fast-inflation = []
 foreign-assets = []
 gov-test-timings = []
 governance = []
-lookahead = []
+lookahead = ['cumulus-pallet-parachain-system/parameterized-consensus-hook', 'pallet-aura/experimental']
 preimage = []
 refungible = []
 session-test-timings = []
-fast-inflation = []
 
 ################################################################################
 # local dependencies
@@ -269,9 +272,9 @@
 pallet-treasury = { workspace = true }
 pallet-utility = { workspace = true }
 pallet-xcm = { workspace = true }
-parachain-info = { workspace = true }
 parity-scale-codec = { workspace = true }
 polkadot-parachain-primitives = { workspace = true }
+polkadot-runtime-common = { workspace = true }
 smallvec = { workspace = true }
 sp-api = { workspace = true }
 sp-arithmetic = { workspace = true }
@@ -287,6 +290,7 @@
 sp-storage = { workspace = true }
 sp-transaction-pool = { workspace = true }
 sp-version = { workspace = true }
+staging-parachain-info = { workspace = true }
 staging-xcm = { workspace = true }
 staging-xcm-builder = { workspace = true }
 staging-xcm-executor = { workspace = true }
modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
--- a/runtime/opal/src/lib.rs
+++ b/runtime/opal/src/lib.rs
@@ -67,8 +67,15 @@
 
 impl_common_runtime_apis!();
 
+// CheckInherents is included in consensus hook
+#[cfg(not(feature = "lookahead"))]
 cumulus_pallet_parachain_system::register_validate_block!(
 	Runtime = Runtime,
 	BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
 	CheckInherents = CheckInherents,
 );
+#[cfg(feature = "lookahead")]
+cumulus_pallet_parachain_system::register_validate_block!(
+	Runtime = Runtime,
+	BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
+);
modifiedruntime/quartz/Cargo.tomldiffbeforeafterboth
--- a/runtime/quartz/Cargo.toml
+++ b/runtime/quartz/Cargo.toml
@@ -58,6 +58,7 @@
 	'pallet-unique/runtime-benchmarks',
 	'pallet-utility/runtime-benchmarks',
 	'pallet-xcm/runtime-benchmarks',
+	'polkadot-runtime-common/runtime-benchmarks',
 	'sp-runtime/runtime-benchmarks',
 	'staging-xcm-builder/runtime-benchmarks',
 ]
@@ -126,7 +127,7 @@
 	'pallet-treasury/std',
 	'pallet-unique/std',
 	'pallet-utility/std',
-	'parachain-info/std',
+	'polkadot-runtime-common/std',
 	'serde',
 	'sp-api/std',
 	'sp-block-builder/std',
@@ -139,6 +140,7 @@
 	'sp-std/std',
 	'sp-transaction-pool/std',
 	'sp-version/std',
+	'staging-parachain-info/std',
 	'staging-xcm-builder/std',
 	'staging-xcm-executor/std',
 	'staging-xcm/std',
@@ -210,18 +212,19 @@
 	'pallet-unique/try-runtime',
 	'pallet-utility/try-runtime',
 	'pallet-xcm/try-runtime',
-	'parachain-info/try-runtime',
+	'polkadot-runtime-common/try-runtime',
+	'staging-parachain-info/try-runtime',
 ]
 
 app-promotion = []
 collator-selection = []
+fast-inflation = []
 foreign-assets = []
 gov-test-timings = []
 governance = []
 preimage = []
 refungible = []
 session-test-timings = []
-fast-inflation = []
 
 ################################################################################
 # local dependencies
@@ -257,9 +260,9 @@
 pallet-treasury = { workspace = true }
 pallet-utility = { workspace = true }
 pallet-xcm = { workspace = true }
-parachain-info = { workspace = true }
 parity-scale-codec = { workspace = true }
 polkadot-parachain-primitives = { workspace = true }
+polkadot-runtime-common = { workspace = true }
 smallvec = { workspace = true }
 sp-api = { workspace = true }
 sp-arithmetic = { workspace = true }
@@ -275,6 +278,7 @@
 sp-storage = { workspace = true }
 sp-transaction-pool = { workspace = true }
 sp-version = { workspace = true }
+staging-parachain-info = { workspace = true }
 staging-xcm = { workspace = true }
 staging-xcm-builder = { workspace = true }
 staging-xcm-executor = { workspace = true }
modifiedruntime/unique/Cargo.tomldiffbeforeafterboth
--- a/runtime/unique/Cargo.toml
+++ b/runtime/unique/Cargo.toml
@@ -55,6 +55,7 @@
 	'pallet-unique/runtime-benchmarks',
 	'pallet-utility/runtime-benchmarks',
 	'pallet-xcm/runtime-benchmarks',
+	'polkadot-runtime-common/runtime-benchmarks',
 	'sp-runtime/runtime-benchmarks',
 	'staging-xcm-builder/runtime-benchmarks',
 	'up-data-structs/runtime-benchmarks',
@@ -124,7 +125,7 @@
 	'pallet-treasury/std',
 	'pallet-unique/std',
 	'pallet-utility/std',
-	'parachain-info/std',
+	'polkadot-runtime-common/std',
 	'sp-api/std',
 	'sp-block-builder/std',
 	'sp-core/std',
@@ -136,6 +137,7 @@
 	'sp-std/std',
 	'sp-transaction-pool/std',
 	'sp-version/std',
+	'staging-parachain-info/std',
 	'staging-xcm-builder/std',
 	'staging-xcm-executor/std',
 	'staging-xcm/std',
@@ -212,19 +214,20 @@
 	'pallet-unique/try-runtime',
 	'pallet-utility/try-runtime',
 	'pallet-xcm/try-runtime',
-	'parachain-info/try-runtime',
+	'polkadot-runtime-common/try-runtime',
+	'staging-parachain-info/try-runtime',
 ]
-unique-runtime = ['app-promotion', 'foreign-assets', 'refungible', 'governance', 'preimage']
+unique-runtime = ['app-promotion', 'foreign-assets', 'governance', 'preimage', 'refungible']
 
 app-promotion = []
 collator-selection = []
+fast-inflation = []
 foreign-assets = []
 gov-test-timings = []
 governance = []
 preimage = []
 refungible = []
 session-test-timings = []
-fast-inflation = []
 
 ################################################################################
 # local dependencies
@@ -260,9 +263,9 @@
 pallet-treasury = { workspace = true }
 pallet-utility = { workspace = true }
 pallet-xcm = { workspace = true }
-parachain-info = { workspace = true }
 parity-scale-codec = { workspace = true }
 polkadot-parachain-primitives = { workspace = true }
+polkadot-runtime-common = { workspace = true }
 smallvec = { workspace = true }
 sp-api = { workspace = true }
 sp-arithmetic = { workspace = true }
@@ -278,6 +281,7 @@
 sp-storage = { workspace = true }
 sp-transaction-pool = { workspace = true }
 sp-version = { workspace = true }
+staging-parachain-info = { workspace = true }
 staging-xcm = { workspace = true }
 staging-xcm-builder = { workspace = true }
 staging-xcm-executor = { workspace = true }