git.delta.rocks / unique-network / refs/commits / a7384514d3de

difftreelog

Merge branch 'develop' into tests/vesting

Max Andreev2022-12-08parents: #465cfef #378b7f3.patch.diff
in: master

144 files changed

modified.docker/Dockerfile-try-runtimediffbeforeafterboth
--- a/.docker/Dockerfile-try-runtime
+++ b/.docker/Dockerfile-try-runtime
@@ -46,4 +46,4 @@
     echo "Fork from: $REPLICA_FROM\n" && \
     cargo build --features=try-runtime,${NETWORK}-runtime --release
 
-CMD cargo run --features=try-runtime,${NETWORK}-runtime --release -- try-runtime --no-spec-check-panic on-runtime-upgrade live --uri $REPLICA_FROM
+CMD cargo run --features=try-runtime,${NETWORK}-runtime --release -- try-runtime -ltry-runtime::cli=debug --no-spec-check-panic on-runtime-upgrade live --uri $REPLICA_FROM
added.docker/additional/Dockerfile-polkadotdiffbeforeafterboth
--- /dev/null
+++ b/.docker/additional/Dockerfile-polkadot
@@ -0,0 +1,45 @@
+# ===== Rust builder =====
+FROM ubuntu:20.04 as rust-builder
+LABEL maintainer="Unique.Network"
+
+ARG RUST_TOOLCHAIN=nightly-2022-10-09
+
+ENV CARGO_HOME="/cargo-home"
+ENV PATH="/cargo-home/bin:$PATH"
+ENV TZ=UTC
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+RUN apt-get update && \
+    apt-get install -y curl cmake pkg-config libssl-dev git clang llvm libudev-dev protobuf-compiler && \
+    apt-get clean && \
+    rm -r /var/lib/apt/lists/*
+
+RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain none
+
+RUN rustup toolchain uninstall $(rustup toolchain list) && \
+    rustup toolchain install $RUST_TOOLCHAIN && \
+    rustup default $RUST_TOOLCHAIN && \
+    rustup target list --installed && \
+    rustup show
+RUN rustup target add wasm32-unknown-unknown --toolchain $RUST_TOOLCHAIN
+
+RUN mkdir /unique_parachain
+WORKDIR /unique_parachain
+
+# ===== BUILD POLKADOT =====
+FROM rust-builder as builder-polkadot-bin
+
+ARG POLKADOT_BUILD_BRANCH=release-v0.9.33
+
+WORKDIR /unique_parachain
+
+RUN git clone -b $POLKADOT_BUILD_BRANCH --depth 1 https://github.com/paritytech/polkadot.git && \
+    cd polkadot && \
+    cargo build --release
+
+# ===== BIN ======
+
+FROM ubuntu:20.04 as builder-polkadot
+
+COPY --from=builder-polkadot-bin /unique_parachain/polkadot/target/release/polkadot /unique_parachain/polkadot/target/release/polkadot
+COPY --from=builder-polkadot-bin /unique_parachain/polkadot/target/release/wbuild/westend-runtime/westend_runtime.compact.compressed.wasm /unique_parachain/polkadot/target/release/wbuild/westend-runtime/westend_runtime.compact.compressed.wasm
modified.docker/docker-compose.tmp-node.j2diffbeforeafterboth
--- a/.docker/docker-compose.tmp-node.j2
+++ b/.docker/docker-compose.tmp-node.j2
@@ -23,10 +23,12 @@
          read_only: true
     expose:
       - 9944
+      - 9945
       - 9933
       - 9844
     ports:
       - 127.0.0.1:9944:9944
+      - 127.0.0.1:9945:9945
       - 127.0.0.1:9933:9933
       - 127.0.0.1:9844:9844
     logging:
modified.docker/forkless-config/launch-config-forkless-data.j2diffbeforeafterboth
--- a/.docker/forkless-config/launch-config-forkless-data.j2
+++ b/.docker/forkless-config/launch-config-forkless-data.j2
@@ -107,7 +107,11 @@
                         "--rpc-cors=all",
                         "--unsafe-rpc-external",
                         "--unsafe-ws-external",
-                        "-lxcm=trace,parity_ws::handler=debug,jsonrpsee_core=trace,jsonrpsee-core=trace,jsonrpsee_ws_server=debug"
+                        "-lxcm=trace,parity_ws::handler=debug,jsonrpsee_core=trace,jsonrpsee-core=trace,jsonrpsee_ws_server=debug",
+                        "--",
+                        "--port=31335",
+                        "--ws-port=9745",
+                        "--rpc-port=9734"
                     ]
                 },
                 {
modified.docker/forkless-config/launch-config-forkless-nodata.j2diffbeforeafterboth
--- a/.docker/forkless-config/launch-config-forkless-nodata.j2
+++ b/.docker/forkless-config/launch-config-forkless-nodata.j2
@@ -102,7 +102,11 @@
                         "--unsafe-rpc-external",
                         "--unsafe-ws-external",
                         "-lxcm=trace,parity_ws::handler=debug,jsonrpsee_core=trace,jsonrpsee-core=trace,jsonrpsee_ws_server=debug",
-                        "--ws-max-connections=1000"
+                        "--ws-max-connections=1000",
+                        "--",
+                        "--port=31335",
+                        "--ws-port=9745",
+                        "--rpc-port=9734"
                     ]
                 },
                 {
@@ -115,7 +119,11 @@
                         "--unsafe-rpc-external",
                         "--unsafe-ws-external",
                         "-lxcm=trace,parity_ws::handler=debug,jsonrpsee_core=trace,jsonrpsee-core=trace,jsonrpsee_ws_server=debug",
-                        "--ws-max-connections=1000"
+                        "--ws-max-connections=1000",
+                        "--",
+                        "--port=31337",
+                        "--ws-port=9747",
+                        "--rpc-port=9737"                        
                     ]
                 }
             ]
modified.docker/forkless-config/launch-config-node-update-only-v3.j2diffbeforeafterboth
--- a/.docker/forkless-config/launch-config-node-update-only-v3.j2
+++ b/.docker/forkless-config/launch-config-node-update-only-v3.j2
@@ -102,7 +102,11 @@
                         "--unsafe-rpc-external",
                         "--unsafe-ws-external",
                         "-lxcm=trace,parity_ws::handler=debug,jsonrpsee_core=trace,jsonrpsee-core=trace,jsonrpsee_ws_server=debug",
-                        "--ws-max-connections=1000"
+                        "--ws-max-connections=1000",
+                        "--",
+                        "--port=31335",
+                        "--ws-port=9745",
+                        "--rpc-port=9734"
                     ]
                 },
                 {
modified.github/workflows/codestyle.ymldiffbeforeafterboth
--- a/.github/workflows/codestyle.yml
+++ b/.github/workflows/codestyle.yml
@@ -11,7 +11,11 @@
   rustfmt:
     runs-on: [ self-hosted-ci ]
     steps:
+      - name: Clean Workspace
+        uses: AutoModality/action-clean@v1.1.0
       - uses: actions/checkout@v3
+        with:
+          ref: ${{ github.head_ref }}            
       - name: Install latest nightly
         uses: actions-rs/toolchain@v1
         with:
@@ -28,7 +32,11 @@
   yarn_eslint:
     runs-on: [ self-hosted-ci ]
     steps:
+      - name: Clean Workspace
+        uses: AutoModality/action-clean@v1.1.0
       - uses: actions/checkout@v3
+        with:
+          ref: ${{ github.head_ref }}            
       - uses: actions/setup-node@v3
         with:
           node-version: 16
modified.github/workflows/node-only-update.ymldiffbeforeafterboth
--- a/.github/workflows/node-only-update.yml
+++ b/.github/workflows/node-only-update.yml
@@ -80,7 +80,7 @@
             REPO_URL=${{ github.server_url }}/${{ github.repository }}.git
             RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}
             POLKADOT_BUILD_BRANCH=${{ env.POLKADOT_BUILD_BRANCH }}
-            POLKADOT_LAUNCH_BRANCH=${{ env.POLKADOT_LAUNCH_BRANCH }}            
+            POLKADOT_LAUNCH_BRANCH=${{ env.POLKADOT_LAUNCH_BRANCH }}
             POLKADOT_MAINNET_BRANCH=${{ env.POLKADOT_MAINNET_BRANCH }}
             MAINNET_TAG=${{ matrix.mainnet_tag }}
             MAINNET_BRANCH=${{ matrix.mainnet_branch }}
@@ -160,56 +160,35 @@
           ref: ${{ matrix.mainnet_branch }}  #Checking out head commit
           path: ${{ matrix.mainnet_branch }}
 
-      - name: Run tests before Node Parachain upgrade
+      - name: Run Parallel tests before Node Parachain upgrade
         working-directory: ${{ matrix.mainnet_branch }}/tests
+        if: success() || failure()
         run: |
           yarn install
           yarn add mochawesome
           node scripts/readyness.js
           echo "Ready to start tests"
           yarn polkadot-types
-          NOW=$(date +%s) && yarn test --reporter mochawesome --reporter-options reportFilename=test-before-${NOW}
+          NOW=$(date +%s) && yarn testParallel --reporter mochawesome --reporter-options reportFilename=test-parallel-${NOW}
         env:
           RPC_URL: http://127.0.0.1:9933/
-
-      - name: Upload Test Report Before Node upgrade
-        uses: phoenix-actions/test-reporting@v8
-        id: test-report-before
-        if: success() || failure()    # run this step even if previous step failed
-        with:
-          name: Tests before node upgrade ${{ matrix.network }}            # Name of the check run which will be created
-          path: ${{ matrix.mainnet_branch }}/tests/mochawesome-report/test-before-*.json    # Path to test results
-          reporter: mochawesome-json
-          fail-on-error: 'false'
 
-      # TODO uncomment thease steps after the merge
-      #- name: Run Parallel tests before Node Parachain upgrade
-      #  working-directory: ${{ matrix.mainnet_branch }}/tests
-      #  run: |
-      #    yarn install
-      #    yarn add mochawesome
-      #    echo "Ready to start tests"
-      #    yarn polkadot-types
-      #    NOW=$(date +%s) && yarn testParallel --reporter mochawesome --reporter-options reportFilename=test-parallel-${NOW}
-      #  env:
-      #    RPC_URL: http://127.0.0.1:9933/
-
-      #- name: Upload Parallel Test Report Before Node upgrade
-      #  uses: phoenix-actions/test-reporting@v8
-      #  id: test-parallel-report-before
-      #  if: success() || failure()    # run this step even if previous step failed
-      #  with:
-      #    name: Tests before node upgrade ${{ matrix.network }}            # Name of the check run which will be created
-      #    path: ${{ matrix.mainnet_branch }}/tests/mochawesome-report/test-parallel-*.json    # Path to test results
-      #    reporter: mochawesome-json
-      #    fail-on-error: 'false'
+      # - name: Upload Parallel Test Report Before Node upgrade
+      #   uses: phoenix-actions/test-reporting@v8
+      #   id: test-parallel-report-before
+      #   if: success() || failure()    # run this step even if previous step failed
+      #   with:
+      #     name: Tests before node upgrade ${{ matrix.network }}            # Name of the check run which will be created
+      #     path: ${{ matrix.mainnet_branch }}/tests/mochawesome-report/test-parallel-*.json    # Path to test results
+      #     reporter: mochawesome-json
+      #     fail-on-error: 'false'
 
-      # - name: Run Sequential tests before Node Parachain upgrade
-      #   if: success() || failure()
-      #   working-directory: ${{ matrix.mainnet_branch }}/tests
-      #   run: NOW=$(date +%s) && yarn testSequential --reporter mochawesome --reporter-options reportFilename=test-sequential-${NOW}
-      #   env:
-      #     RPC_URL: http://127.0.0.1:9933/
+      - name: Run Sequential tests before Node Parachain upgrade
+        if: success() || failure()
+        working-directory: ${{ matrix.mainnet_branch }}/tests
+        run: NOW=$(date +%s) && yarn testSequential --reporter mochawesome --reporter-options reportFilename=test-sequential-${NOW}
+        env:
+          RPC_URL: http://127.0.0.1:9933/
 
       # - name: Upload Sequential Test Report Before Node upgrade
       #   uses: phoenix-actions/test-reporting@v8
@@ -220,7 +199,7 @@
       #     path: ${{ matrix.mainnet_branch }}/tests/mochawesome-report/test-sequential-*.json    # Path to test results
       #     reporter: mochawesome-json
       #     fail-on-error: 'false'
-     
+
       - name: Send SIGUSR1 to polkadot-launch process
         if: success() || failure()
         run: |
@@ -228,24 +207,37 @@
           ContainerID=$(docker ps -aqf "name=node-parachain")
           PID=$(docker exec node-parachain pidof 'polkadot-launch')
           sleep 30s
-          echo -e "Show logs of node-parachain container.\n"
-          docker logs ${ContainerID}
           echo -e "\n"
           echo -e "Restart polkadot-launch process: $PID\n"
           docker exec node-parachain kill -SIGUSR1 ${PID}
           echo "SIGUSR1 sent to Polkadot-launch PID: $PID"
+          sleep 60s
+          echo -e "Show logs of node-parachain container.\n"          
           docker logs ${ContainerID}
-      
+
       - name: Get chain logs in case of docker image crashed after Polkadot Launch restart
         if: failure()                   # run this step only at failure
         run: |
-          docker exec node-parachain cat /polkadot-launch/9944.log
-          docker exec node-parachain cat /polkadot-launch/9945.log
-          docker exec node-parachain cat /polkadot-launch/alice.log
-          docker exec node-parachain cat /polkadot-launch/eve.log
-          docker exec node-parachain cat /polkadot-launch/dave.log
-          docker exec node-parachain cat /polkadot-launch/charlie.log             
+          docker exec node-parachain tail -n 1000 /polkadot-launch/9944.log
+          docker exec node-parachain tail -n 1000 /polkadot-launch/9945.log
+          docker exec node-parachain tail -n 1000 /polkadot-launch/alice.log
+
+      - name: copy chain log files from container to the host
+        if: success() || failure()    # run this step even if previous step failed
+        run: |
+          mkdir -p /tmp/node-only-update
+          docker cp node-parachain:/polkadot-launch/9944.log /tmp/node-only-update/
+          docker cp node-parachain:/polkadot-launch/9945.log /tmp/node-only-update/
+          docker cp node-parachain:/polkadot-launch/alice.log /tmp/node-only-update/
 
+      - name: Upload chain log files
+        if: success() || failure()
+        uses: actions/upload-artifact@v3
+        with:
+          name: node-only-update-chain-logs
+          path: /tmp/node-only-update/
+          if-no-files-found: warn
+
       - name: Check if docker logs consist messages related to testing of Node Parachain Upgrade.
         if: success()
         run: |
@@ -290,43 +282,20 @@
           echo "Halting script"
           exit 0
         shell: bash
-        
-      ## TODO: Remove next two blocks before switch to Parrallel & Sequental tests. Uncoment commented blocks.
-      - name: Run tests after Node Parachain upgrade
+
+      - name: Run Parallel tests after Node Parachain upgrade
         working-directory: ${{ matrix.mainnet_branch }}/tests
+        if: success() || failure()    # run this step even if previous step failed
         run: |
           yarn install
           yarn add mochawesome
           node scripts/readyness.js
           echo "Ready to start tests"
           yarn polkadot-types
-          NOW=$(date +%s) && yarn test --reporter mochawesome --reporter-options reportFilename=test-after-${NOW}
+          NOW=$(date +%s) && yarn testParallel --reporter mochawesome --reporter-options reportFilename=test-parallel-${NOW}
         env:
           RPC_URL: http://127.0.0.1:9933/
 
-      - name: Test Report After Node upgrade
-        uses: phoenix-actions/test-reporting@v8
-        id: test-report-after
-        if: success() || failure()    # run this step even if previous step failed
-        with:
-          name: Tests after node upgrade ${{ matrix.network }}            # Name of the check run which will be created
-          path: ${{ matrix.mainnet_branch }}/tests/mochawesome-report/test-after-*.json    # Path to test results
-          reporter: mochawesome-json
-          fail-on-error: 'false'
-
-      # TODO uncomment thease steps after the merge
-      #- name: Run Parallel tests after Node Parachain upgrade
-      #  working-directory: ${{ matrix.mainnet_branch }}/tests
-      #  run: |
-      #    yarn install
-      #    yarn add mochawesome
-      #    node scripts/readyness.js
-      #    echo "Ready to start tests"
-      #    yarn polkadot-types
-      #    NOW=$(date +%s) && yarn testParallel --reporter mochawesome --reporter-options reportFilename=test-parallel-${NOW}
-      #  env:
-      #    RPC_URL: http://127.0.0.1:9933/
-
       #- name: Test Report Parallel After Node upgrade
       #  uses: phoenix-actions/test-reporting@v8
       #  id: test-report-parallel-after
@@ -336,14 +305,14 @@
       #    path: ${{ matrix.mainnet_branch }}/tests/mochawesome-report/test-parallel-*.json    # Path to test results
       #    reporter: mochawesome-json
       #    fail-on-error: 'false'
-      
-      #- name: Run Sequential tests after Node Parachain upgrade
-      #  if: success() || failure()
-      #  working-directory: ${{ matrix.mainnet_branch }}/tests
-      #  run: NOW=$(date +%s) && yarn testSequential --reporter mochawesome --reporter-options reportFilename=test-sequential-${NOW}
-      #  env:
-      #    RPC_URL: http://127.0.0.1:9933/
 
+      - name: Run Sequential tests after Node Parachain upgrade
+        if: success() || failure()
+        working-directory: ${{ matrix.mainnet_branch }}/tests
+        run: NOW=$(date +%s) && yarn testSequential --reporter mochawesome --reporter-options reportFilename=test-sequential-${NOW}
+        env:
+          RPC_URL: http://127.0.0.1:9933/
+
       #- name: Upload Sequential Test Report After Node upgrade
       #  uses: phoenix-actions/test-reporting@v8
       #  id: test-sequential-report-after
@@ -353,7 +322,6 @@
       #    path: ${{ matrix.mainnet_branch }}/tests/mochawesome-report/test-sequential-*.json    # Path to test results
       #    reporter: mochawesome-json
       #    fail-on-error: 'false'
-
 
       - name: Stop running containers
         if: always()                   # run this step always
modified.maintain/scripts/generate_abi.shdiffbeforeafterboth
--- a/.maintain/scripts/generate_abi.sh
+++ b/.maintain/scripts/generate_abi.sh
@@ -4,6 +4,7 @@
 dir=$PWD
 
 tmp=$(mktemp -d)
+echo "Tmp file: $tmp/input.sol"
 cd $tmp
 cp $dir/$INPUT input.sol
 solcjs --abi -p input.sol
modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -75,9 +75,9 @@
 
 [[package]]
 name = "aho-corasick"
-version = "0.7.19"
+version = "0.7.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
+checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
 dependencies = [
  "memchr",
 ]
@@ -137,9 +137,9 @@
 
 [[package]]
 name = "array-bytes"
-version = "4.1.0"
+version = "4.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a913633b0c922e6b745072795f50d90ebea78ba31a57e2ac8c2fc7b50950949"
+checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6"
 
 [[package]]
 name = "arrayref"
@@ -196,30 +196,30 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28"
 dependencies = [
- "concurrent-queue",
+ "concurrent-queue 1.2.4",
  "event-listener",
  "futures-core",
 ]
 
 [[package]]
 name = "async-executor"
-version = "1.4.1"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965"
+checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b"
 dependencies = [
+ "async-lock",
  "async-task",
- "concurrent-queue",
+ "concurrent-queue 2.0.0",
  "fastrand",
  "futures-lite",
- "once_cell",
  "slab",
 ]
 
 [[package]]
 name = "async-global-executor"
-version = "2.3.0"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0da5b41ee986eed3f524c380e6d64965aea573882a8907682ad100f7859305ca"
+checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776"
 dependencies = [
  "async-channel",
  "async-executor",
@@ -232,16 +232,16 @@
 
 [[package]]
 name = "async-io"
-version = "1.9.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7"
+checksum = "e8121296a9f05be7f34aa4196b1747243b3b62e048bb7906f644f3fbfc490cf7"
 dependencies = [
+ "async-lock",
  "autocfg",
- "concurrent-queue",
+ "concurrent-queue 1.2.4",
  "futures-lite",
  "libc",
  "log",
- "once_cell",
  "parking",
  "polling",
  "slab",
@@ -340,9 +340,9 @@
 
 [[package]]
 name = "asynchronous-codec"
-version = "0.6.0"
+version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0de5164e5edbf51c45fb8c2d9664ae1c095cce1b265ecf7569093c0d66ef690"
+checksum = "06a0daa378f5fd10634e44b0a29b2a87b890657658e072a30d6f26e57ddee182"
 dependencies = [
  "bytes",
  "futures-sink",
@@ -595,16 +595,16 @@
  "funty 2.0.0",
  "radium 0.7.0",
  "tap",
- "wyz 0.5.0",
+ "wyz 0.5.1",
 ]
 
 [[package]]
 name = "blake2"
-version = "0.10.4"
+version = "0.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388"
+checksum = "b12e5fd123190ce1c2e559308a94c9bacad77907d4c6005d9e58fe1a0689e55e"
 dependencies = [
- "digest 0.10.5",
+ "digest 0.10.6",
 ]
 
 [[package]]
@@ -614,7 +614,7 @@
 checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
 dependencies = [
  "arrayvec 0.4.12",
- "constant_time_eq",
+ "constant_time_eq 0.1.5",
 ]
 
 [[package]]
@@ -625,7 +625,7 @@
 dependencies = [
  "arrayref",
  "arrayvec 0.7.2",
- "constant_time_eq",
+ "constant_time_eq 0.1.5",
 ]
 
 [[package]]
@@ -636,21 +636,21 @@
 dependencies = [
  "arrayref",
  "arrayvec 0.7.2",
- "constant_time_eq",
+ "constant_time_eq 0.1.5",
 ]
 
 [[package]]
 name = "blake3"
-version = "1.3.1"
+version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f"
+checksum = "895adc16c8b3273fbbc32685a7d55227705eda08c01e77704020f3491924b44b"
 dependencies = [
  "arrayref",
  "arrayvec 0.7.2",
  "cc",
  "cfg-if 1.0.0",
- "constant_time_eq",
- "digest 0.10.5",
+ "constant_time_eq 0.2.4",
+ "digest 0.10.6",
 ]
 
 [[package]]
@@ -769,9 +769,9 @@
 
 [[package]]
 name = "byte-slice-cast"
-version = "1.2.1"
+version = "1.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87c5fdd0166095e1d463fc6cc01aa8ce547ad77a4e84d42eb6762b084e28067e"
+checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c"
 
 [[package]]
 name = "byte-tools"
@@ -787,9 +787,9 @@
 
 [[package]]
 name = "bytes"
-version = "1.2.1"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
+checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
 
 [[package]]
 name = "bzip2-sys"
@@ -841,9 +841,9 @@
 
 [[package]]
 name = "cc"
-version = "1.0.73"
+version = "1.0.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
+checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
 dependencies = [
  "jobserver",
 ]
@@ -911,9 +911,9 @@
 
 [[package]]
 name = "chrono"
-version = "0.4.22"
+version = "0.4.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
+checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
 dependencies = [
  "iana-time-zone",
  "js-sys",
@@ -973,7 +973,7 @@
 dependencies = [
  "glob",
  "libc",
- "libloading 0.7.3",
+ "libloading 0.7.4",
 ]
 
 [[package]]
@@ -1017,9 +1017,9 @@
 
 [[package]]
 name = "cmake"
-version = "0.1.48"
+version = "0.1.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a"
+checksum = "db34956e100b30725f2eb215f90d4871051239535632f84fea3bc92722c66b7c"
 dependencies = [
  "cc",
 ]
@@ -1048,9 +1048,9 @@
 
 [[package]]
 name = "comfy-table"
-version = "6.1.1"
+version = "6.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b3d16bb3da60be2f7c7acfc438f2ae6f3496897ce68c291d0509bb67b4e248e"
+checksum = "e621e7e86c46fd8a14c32c6ae3cb95656621b4743a27d0cffedb831d46e7ad21"
 dependencies = [
  "strum",
  "strum_macros",
@@ -1058,22 +1058,21 @@
 ]
 
 [[package]]
-name = "concat-idents"
-version = "1.1.3"
+name = "concurrent-queue"
+version = "1.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b6f90860248d75014b7b103db8fee4f291c07bfb41306cdf77a0a5ab7a10d2f"
+checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c"
 dependencies = [
- "quote",
- "syn",
+ "cache-padded",
 ]
 
 [[package]]
 name = "concurrent-queue"
-version = "1.2.4"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c"
+checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b"
 dependencies = [
- "cache-padded",
+ "crossbeam-utils",
 ]
 
 [[package]]
@@ -1102,6 +1101,12 @@
 checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
 
 [[package]]
+name = "constant_time_eq"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279"
+
+[[package]]
 name = "convert_case"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1152,18 +1157,18 @@
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.88.1"
+version = "0.88.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44409ccf2d0f663920cab563d2b79fcd6b2e9a2bcc6e929fef76c8f82ad6c17a"
+checksum = "52056f6d0584484b57fa6c1a65c1fcb15f3780d8b6a758426d9e3084169b2ddd"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.88.1"
+version = "0.88.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98de2018ad96eb97f621f7d6b900a0cc661aec8d02ea4a50e56ecb48e5a2fcaf"
+checksum = "18fed94c8770dc25d01154c3ffa64ed0b3ba9d583736f305fed7beebe5d9cf74"
 dependencies = [
  "arrayvec 0.7.2",
  "bumpalo",
@@ -1181,33 +1186,33 @@
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.88.1"
+version = "0.88.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5287ce36e6c4758fbaf298bd1a8697ad97a4f2375a3d1b61142ea538db4877e5"
+checksum = "1c451b81faf237d11c7e4f3165eeb6bac61112762c5cfe7b4c0fb7241474358f"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.88.1"
+version = "0.88.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2855c24219e2f08827f3f4ffb2da92e134ae8d8ecc185b11ec8f9878cf5f588e"
+checksum = "e7c940133198426d26128f08be2b40b0bd117b84771fd36798969c4d712d81fc"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.88.1"
+version = "0.88.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b65673279d75d34bf11af9660ae2dbd1c22e6d28f163f5c72f4e1dc56d56103"
+checksum = "87a0f1b2fdc18776956370cf8d9b009ded3f855350c480c1c52142510961f352"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.88.1"
+version = "0.88.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed2b3d7a4751163f6c4a349205ab1b7d9c00eecf19dcea48592ef1f7688eefc"
+checksum = "34897538b36b216cc8dd324e73263596d51b8cf610da6498322838b2546baf8a"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -1217,15 +1222,15 @@
 
 [[package]]
 name = "cranelift-isle"
-version = "0.88.1"
+version = "0.88.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be64cecea9d90105fc6a2ba2d003e98c867c1d6c4c86cc878f97ad9fb916293"
+checksum = "1b2629a569fae540f16a76b70afcc87ad7decb38dc28fa6c648ac73b51e78470"
 
 [[package]]
 name = "cranelift-native"
-version = "0.88.1"
+version = "0.88.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4a03a6ac1b063e416ca4b93f6247978c991475e8271465340caa6f92f3c16a4"
+checksum = "20937dab4e14d3e225c5adfc9c7106bafd4ac669bdb43027b911ff794c6fb318"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -1234,9 +1239,9 @@
 
 [[package]]
 name = "cranelift-wasm"
-version = "0.88.1"
+version = "0.88.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c699873f7b30bc5f20dd03a796b4183e073a46616c91704792ec35e45d13f913"
+checksum = "80fc2288957a94fd342a015811479de1837850924166d1f1856d8406e6f3609b"
 dependencies = [
  "cranelift-codegen",
  "cranelift-entity",
@@ -1280,22 +1285,22 @@
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.11"
+version = "0.9.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348"
+checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
 dependencies = [
  "autocfg",
  "cfg-if 1.0.0",
  "crossbeam-utils",
- "memoffset",
+ "memoffset 0.7.1",
  "scopeguard",
 ]
 
 [[package]]
 name = "crossbeam-queue"
-version = "0.3.6"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7"
+checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add"
 dependencies = [
  "cfg-if 1.0.0",
  "crossbeam-utils",
@@ -1303,9 +1308,9 @@
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.12"
+version = "0.8.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
+checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
 dependencies = [
  "cfg-if 1.0.0",
 ]
@@ -1872,9 +1877,9 @@
 
 [[package]]
 name = "cxx"
-version = "1.0.80"
+version = "1.0.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a"
+checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453"
 dependencies = [
  "cc",
  "cxxbridge-flags",
@@ -1884,9 +1889,9 @@
 
 [[package]]
 name = "cxx-build"
-version = "1.0.80"
+version = "1.0.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827"
+checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0"
 dependencies = [
  "cc",
  "codespan-reporting",
@@ -1899,15 +1904,15 @@
 
 [[package]]
 name = "cxxbridge-flags"
-version = "1.0.80"
+version = "1.0.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a"
+checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71"
 
 [[package]]
 name = "cxxbridge-macro"
-version = "1.0.80"
+version = "1.0.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7"
+checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1993,9 +1998,9 @@
 
 [[package]]
 name = "digest"
-version = "0.10.5"
+version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c"
+checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
 dependencies = [
  "block-buffer 0.10.3",
  "crypto-common",
@@ -2216,9 +2221,9 @@
 
 [[package]]
 name = "env_logger"
-version = "0.9.1"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272"
+checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
 dependencies = [
  "atty",
  "humantime",
@@ -2332,9 +2337,8 @@
 
 [[package]]
 name = "evm-coder"
-version = "0.1.4"
+version = "0.1.5"
 dependencies = [
- "concat-idents",
  "ethereum",
  "evm-coder-procedural",
  "evm-core",
@@ -2352,7 +2356,7 @@
 
 [[package]]
 name = "evm-coder-procedural"
-version = "0.2.1"
+version = "0.2.2"
 dependencies = [
  "Inflector",
  "hex",
@@ -2479,7 +2483,7 @@
 [[package]]
 name = "fc-consensus"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
  "async-trait",
  "fc-db",
@@ -2498,14 +2502,16 @@
 [[package]]
 name = "fc-db"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
  "fp-storage",
  "kvdb-rocksdb",
+ "log",
  "parity-db",
  "parity-scale-codec 3.2.1",
  "parking_lot 0.12.1",
  "sc-client-db",
+ "sp-blockchain",
  "sp-core",
  "sp-database",
  "sp-runtime",
@@ -2514,7 +2520,7 @@
 [[package]]
 name = "fc-mapping-sync"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
  "fc-db",
  "fp-consensus",
@@ -2531,13 +2537,15 @@
 [[package]]
 name = "fc-rpc"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
  "ethereum",
  "ethereum-types",
  "evm",
  "fc-db",
  "fc-rpc-core",
+ "fp-ethereum",
+ "fp-evm",
  "fp-rpc",
  "fp-storage",
  "futures 0.3.25",
@@ -2545,12 +2553,11 @@
  "jsonrpsee",
  "libsecp256k1",
  "log",
- "lru 0.7.8",
+ "lru 0.8.1",
  "parity-scale-codec 3.2.1",
  "prometheus",
  "rand 0.8.5",
  "rlp",
- "rustc-hex",
  "sc-client-api",
  "sc-network",
  "sc-network-common",
@@ -2573,7 +2580,7 @@
 [[package]]
 name = "fc-rpc-core"
 version = "1.1.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
  "ethereum",
  "ethereum-types",
@@ -2713,7 +2720,7 @@
 [[package]]
 name = "fp-consensus"
 version = "2.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
  "ethereum",
  "parity-scale-codec 3.2.1",
@@ -2723,9 +2730,24 @@
 ]
 
 [[package]]
+name = "fp-ethereum"
+version = "1.0.0-dev"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
+dependencies = [
+ "ethereum",
+ "ethereum-types",
+ "fp-evm",
+ "frame-support",
+ "num_enum",
+ "parity-scale-codec 3.2.1",
+ "sp-core",
+ "sp-std",
+]
+
+[[package]]
 name = "fp-evm"
 version = "3.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
  "evm",
  "frame-support",
@@ -2739,7 +2761,7 @@
 [[package]]
 name = "fp-evm-mapping"
 version = "0.1.0"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
  "frame-support",
  "sp-core",
@@ -2748,7 +2770,7 @@
 [[package]]
 name = "fp-rpc"
 version = "3.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
  "ethereum",
  "ethereum-types",
@@ -2765,7 +2787,7 @@
 [[package]]
 name = "fp-self-contained"
 version = "1.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
  "ethereum",
  "frame-support",
@@ -2773,17 +2795,16 @@
  "parity-util-mem",
  "scale-info",
  "serde",
- "sp-debug-derive",
- "sp-io",
  "sp-runtime",
 ]
 
 [[package]]
 name = "fp-storage"
 version = "2.0.0"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
  "parity-scale-codec 3.2.1",
+ "serde",
 ]
 
 [[package]]
@@ -3040,9 +3061,9 @@
 
 [[package]]
 name = "fs-err"
-version = "2.8.1"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64db3e262960f0662f43a6366788d5f10f7f244b8f7d7d987f560baf5ded5c50"
+checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541"
 
 [[package]]
 name = "fs-swap"
@@ -3512,9 +3533,9 @@
 
 [[package]]
 name = "hyper"
-version = "0.14.20"
+version = "0.14.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac"
+checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -3536,9 +3557,9 @@
 
 [[package]]
 name = "hyper-rustls"
-version = "0.23.0"
+version = "0.23.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac"
+checksum = "59df7c4e19c950e6e0e868dcc0a300b09a9b88e9ec55bd879ca819087a77355d"
 dependencies = [
  "http",
  "hyper",
@@ -3551,9 +3572,9 @@
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.51"
+version = "0.1.53"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed"
+checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
@@ -3662,9 +3683,9 @@
 
 [[package]]
 name = "indexmap"
-version = "1.9.1"
+version = "1.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
+checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
 dependencies = [
  "autocfg",
  "hashbrown",
@@ -3706,9 +3727,19 @@
 
 [[package]]
 name = "io-lifetimes"
-version = "0.7.4"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074"
+
+[[package]]
+name = "io-lifetimes"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6e481ccbe3dea62107216d0d1138bb8ad8e5e5c43009a098bd1990272c497b0"
+checksum = "a7d367024b3f3414d8e01f437f704f41a9f64ab36f9067fa73e526ad4c763c87"
+dependencies = [
+ "libc",
+ "windows-sys 0.42.0",
+]
 
 [[package]]
 name = "ip_network"
@@ -3718,9 +3749,9 @@
 
 [[package]]
 name = "ipconfig"
-version = "0.3.0"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98"
+checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be"
 dependencies = [
  "socket2",
  "widestring",
@@ -3730,9 +3761,9 @@
 
 [[package]]
 name = "ipnet"
-version = "2.5.0"
+version = "2.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
+checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745"
 
 [[package]]
 name = "itertools"
@@ -3925,9 +3956,12 @@
 
 [[package]]
 name = "keccak"
-version = "0.1.2"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838"
+checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768"
+dependencies = [
+ "cpufeatures",
+]
 
 [[package]]
 name = "kusama-runtime"
@@ -4113,9 +4147,9 @@
 
 [[package]]
 name = "libloading"
-version = "0.7.3"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
 dependencies = [
  "cfg-if 1.0.0",
  "winapi",
@@ -4123,9 +4157,9 @@
 
 [[package]]
 name = "libm"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "292a948cd991e376cf75541fe5b97a1081d713c618b4f1b9500f8844e49eb565"
+checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
 
 [[package]]
 name = "libp2p"
@@ -4757,6 +4791,12 @@
 checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d"
 
 [[package]]
+name = "linux-raw-sys"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb68f22743a3fb35785f1e7f844ca5a3de2dde5bd0c0ef5b372065814699b121"
+
+[[package]]
 name = "lock_api"
 version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4880,18 +4920,18 @@
 
 [[package]]
 name = "memfd"
-version = "0.6.1"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "480b5a5de855d11ff13195950bdc8b98b5e942ef47afc447f6615cdcc4e15d80"
+checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb"
 dependencies = [
- "rustix",
+ "rustix 0.36.2",
 ]
 
 [[package]]
 name = "memmap2"
-version = "0.5.7"
+version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498"
+checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc"
 dependencies = [
  "libc",
 ]
@@ -4906,6 +4946,15 @@
 ]
 
 [[package]]
+name = "memoffset"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
 name = "memory-db"
 version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5020,7 +5069,7 @@
  "blake2s_simd",
  "blake3",
  "core2",
- "digest 0.10.5",
+ "digest 0.10.6",
  "multihash-derive",
  "sha2 0.10.6",
  "sha3",
@@ -5291,15 +5340,36 @@
 
 [[package]]
 name = "num_cpus"
-version = "1.13.1"
+version = "1.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
+checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
 dependencies = [
  "hermit-abi",
  "libc",
 ]
 
 [[package]]
+name = "num_enum"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "num_threads"
 version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5322,9 +5392,9 @@
 
 [[package]]
 name = "once_cell"
-version = "1.15.0"
+version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
 
 [[package]]
 name = "opal-runtime"
@@ -5577,9 +5647,9 @@
 
 [[package]]
 name = "os_str_bytes"
-version = "6.3.0"
+version = "6.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
+checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
 
 [[package]]
 name = "owning_ref"
@@ -5724,7 +5794,7 @@
 [[package]]
 name = "pallet-base-fee"
 version = "1.0.0"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
  "fp-evm",
  "frame-support",
@@ -5831,7 +5901,7 @@
 
 [[package]]
 name = "pallet-common"
-version = "0.1.11"
+version = "0.1.12"
 dependencies = [
  "ethereum",
  "evm-coder",
@@ -5940,12 +6010,13 @@
 [[package]]
 name = "pallet-ethereum"
 version = "4.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
  "ethereum",
  "ethereum-types",
  "evm",
  "fp-consensus",
+ "fp-ethereum",
  "fp-evm",
  "fp-evm-mapping",
  "fp-rpc",
@@ -5953,14 +6024,12 @@
  "fp-storage",
  "frame-support",
  "frame-system",
- "log",
  "pallet-evm",
  "pallet-timestamp",
  "parity-scale-codec 3.2.1",
  "rlp",
  "scale-info",
  "serde",
- "sha3",
  "sp-io",
  "sp-runtime",
  "sp-std",
@@ -5969,8 +6038,9 @@
 [[package]]
 name = "pallet-evm"
 version = "6.0.0-dev"
-source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30#65930cb2982258bee67b73a1f017711f6f4aa0a4"
+source = "git+https://github.com/uniquenetwork/frontier?branch=unique-polkadot-v0.9.30-2#6fce4a7f9c3591f4090dd1db39fe71f6562804d0"
 dependencies = [
+ "environmental",
  "evm",
  "fp-evm",
  "fp-evm-mapping",
@@ -5986,7 +6056,6 @@
  "rlp",
  "scale-info",
  "serde",
- "sha3",
  "sp-core",
  "sp-io",
  "sp-runtime",
@@ -7163,9 +7232,9 @@
 
 [[package]]
 name = "pest"
-version = "2.4.0"
+version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbc7bc69c062e492337d74d59b120c274fd3d261b6bf6d3207d499b4b379c41a"
+checksum = "a528564cc62c19a7acac4d81e01f39e53e25e17b934878f4c6d25cc2836e62f8"
 dependencies = [
  "thiserror",
  "ucd-trie",
@@ -7173,9 +7242,9 @@
 
 [[package]]
 name = "pest_derive"
-version = "2.4.0"
+version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60b75706b9642ebcb34dab3bc7750f811609a0eb1dd8b88c2d15bf628c1c65b2"
+checksum = "d5fd9bc6500181952d34bd0b2b0163a54d794227b498be0b7afa7698d0a7b18f"
 dependencies = [
  "pest",
  "pest_generator",
@@ -7183,9 +7252,9 @@
 
 [[package]]
 name = "pest_generator"
-version = "2.4.0"
+version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4f9272122f5979a6511a749af9db9bfc810393f63119970d7085fed1c4ea0db"
+checksum = "d2610d5ac5156217b4ff8e46ddcef7cdf44b273da2ac5bca2ecbfa86a330e7c4"
 dependencies = [
  "pest",
  "pest_meta",
@@ -7196,9 +7265,9 @@
 
 [[package]]
 name = "pest_meta"
-version = "2.4.0"
+version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8717927f9b79515e565a64fe46c38b8cd0427e64c40680b14a7365ab09ac8d"
+checksum = "824749bf7e21dd66b36fbe26b3f45c713879cccd4a009a917ab8e045ca8246fe"
 dependencies = [
  "once_cell",
  "pest",
@@ -8556,9 +8625,19 @@
 
 [[package]]
 name = "ppv-lite86"
-version = "0.2.16"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "prettyplease"
+version = "0.1.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
+checksum = "c142c0e46b57171fe0c528bee8c5b7569e80f0c17e377cd0e30ea57dbc11bb51"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
 
 [[package]]
 name = "primitive-types"
@@ -8682,12 +8761,12 @@
 
 [[package]]
 name = "prost"
-version = "0.11.0"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "399c3c31cdec40583bb68f0b18403400d01ec4289c383aa047560439952c4dd7"
+checksum = "a0841812012b2d4a6145fae9a6af1534873c32aa67fff26bd09f8fa42c83f95a"
 dependencies = [
  "bytes",
- "prost-derive 0.11.0",
+ "prost-derive 0.11.2",
 ]
 
 [[package]]
@@ -8714,9 +8793,9 @@
 
 [[package]]
 name = "prost-build"
-version = "0.11.1"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f835c582e6bd972ba8347313300219fed5bfa52caf175298d860b61ff6069bb"
+checksum = "1d8b442418ea0822409d9e7d047cbf1e7e9e1760b172bf9982cf29d517c93511"
 dependencies = [
  "bytes",
  "heck",
@@ -8725,9 +8804,11 @@
  "log",
  "multimap",
  "petgraph",
- "prost 0.11.0",
- "prost-types 0.11.1",
+ "prettyplease",
+ "prost 0.11.2",
+ "prost-types 0.11.2",
  "regex",
+ "syn",
  "tempfile",
  "which",
 ]
@@ -8760,9 +8841,9 @@
 
 [[package]]
 name = "prost-derive"
-version = "0.11.0"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7345d5f0e08c0536d7ac7229952590239e77abf0a0100a1b1d890add6ea96364"
+checksum = "164ae68b6587001ca506d3bf7f1000bfa248d0e1217b618108fba4ec1d0cc306"
 dependencies = [
  "anyhow",
  "itertools",
@@ -8783,12 +8864,12 @@
 
 [[package]]
 name = "prost-types"
-version = "0.11.1"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dfaa718ad76a44b3415e6c4d53b17c8f99160dcb3a99b10470fce8ad43f6e3e"
+checksum = "747761bc3dc48f9a34553bf65605cf6cb6288ba219f3450b4275dbd81539551a"
 dependencies = [
  "bytes",
- "prost 0.11.0",
+ "prost 0.11.2",
 ]
 
 [[package]]
@@ -9039,11 +9120,10 @@
 
 [[package]]
 name = "rayon"
-version = "1.5.3"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
+checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b"
 dependencies = [
- "autocfg",
  "crossbeam-deque",
  "either",
  "rayon-core",
@@ -9051,9 +9131,9 @@
 
 [[package]]
 name = "rayon-core"
-version = "1.9.3"
+version = "1.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
+checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
 dependencies = [
  "crossbeam-channel",
  "crossbeam-deque",
@@ -9096,18 +9176,18 @@
 
 [[package]]
 name = "ref-cast"
-version = "1.0.12"
+version = "1.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12a733f1746c929b4913fe48f8697fcf9c55e3304ba251a79ffb41adfeaf49c2"
+checksum = "53b15debb4f9d60d767cd8ca9ef7abb2452922f3214671ff052defc7f3502c44"
 dependencies = [
  "ref-cast-impl",
 ]
 
 [[package]]
 name = "ref-cast-impl"
-version = "1.0.12"
+version = "1.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5887de4a01acafd221861463be6113e6e87275e79804e56779f4cdc131c60368"
+checksum = "abfa8511e9e94fd3de6585a3d3cd00e01ed556dc9814829280af0e8dc72a8f36"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -9128,9 +9208,9 @@
 
 [[package]]
 name = "regex"
-version = "1.6.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
+checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -9148,9 +9228,9 @@
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.27"
+version = "0.6.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
+checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
 
 [[package]]
 name = "remote-externalities"
@@ -9426,19 +9506,33 @@
 
 [[package]]
 name = "rustix"
-version = "0.35.12"
+version = "0.35.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "985947f9b6423159c4726323f373be0a21bdb514c5af06a849cb3d2dce2d01e8"
+checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9"
 dependencies = [
  "bitflags",
  "errno",
- "io-lifetimes",
+ "io-lifetimes 0.7.5",
  "libc",
- "linux-raw-sys",
- "windows-sys 0.36.1",
+ "linux-raw-sys 0.0.46",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
+name = "rustix"
+version = "0.36.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "203974af07ea769452490ee8de3e5947971efc3a090dca8a779dd432d3fa46a7"
+dependencies = [
+ "bitflags",
+ "errno",
+ "io-lifetimes 1.0.1",
+ "libc",
+ "linux-raw-sys 0.1.2",
+ "windows-sys 0.42.0",
+]
+
+[[package]]
 name = "rustls"
 version = "0.20.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -9976,7 +10070,7 @@
  "once_cell",
  "parity-scale-codec 3.2.1",
  "parity-wasm 0.45.0",
- "rustix",
+ "rustix 0.35.13",
  "sc-allocator",
  "sc-executor-common",
  "sp-runtime-interface",
@@ -10135,8 +10229,8 @@
  "futures 0.3.25",
  "libp2p",
  "log",
- "prost 0.11.0",
- "prost-build 0.11.1",
+ "prost 0.11.2",
+ "prost-build 0.11.2",
  "sc-client-api",
  "sc-network-common",
  "sp-blockchain",
@@ -10612,9 +10706,9 @@
 
 [[package]]
 name = "scale-info"
-version = "2.2.0"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "333af15b02563b8182cd863f925bd31ef8fa86a0e095d30c091956057d436153"
+checksum = "88d8a765117b237ef233705cc2cc4c6a27fccd46eea6ef0c8c6dae5f3ef407f8"
 dependencies = [
  "bitvec 1.0.1",
  "cfg-if 1.0.0",
@@ -10626,9 +10720,9 @@
 
 [[package]]
 name = "scale-info-derive"
-version = "2.2.0"
+version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53f56acbd0743d29ffa08f911ab5397def774ad01bab3786804cf6ee057fb5e1"
+checksum = "cdcd47b380d8c4541044e341dcd9475f55ba37ddc50c908d945fc036a8642496"
 dependencies = [
  "proc-macro-crate",
  "proc-macro2",
@@ -10804,9 +10898,9 @@
 
 [[package]]
 name = "serde_json"
-version = "1.0.87"
+version = "1.0.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"
+checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
 dependencies = [
  "itoa",
  "ryu",
@@ -10843,7 +10937,7 @@
 dependencies = [
  "cfg-if 1.0.0",
  "cpufeatures",
- "digest 0.10.5",
+ "digest 0.10.6",
 ]
 
 [[package]]
@@ -10879,7 +10973,7 @@
 dependencies = [
  "cfg-if 1.0.0",
  "cpufeatures",
- "digest 0.10.5",
+ "digest 0.10.6",
 ]
 
 [[package]]
@@ -10888,7 +10982,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9"
 dependencies = [
- "digest 0.10.5",
+ "digest 0.10.6",
  "keccak",
 ]
 
@@ -10956,9 +11050,9 @@
 
 [[package]]
 name = "similar"
-version = "2.2.0"
+version = "2.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62ac7f900db32bf3fd12e0117dd3dc4da74bc52ebaac97f39668446d89694803"
+checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf"
 dependencies = [
  "bstr",
  "unicode-segmentation",
@@ -11018,9 +11112,9 @@
 
 [[package]]
 name = "snap"
-version = "1.0.5"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451"
+checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831"
 
 [[package]]
 name = "snow"
@@ -11318,7 +11412,7 @@
 dependencies = [
  "blake2",
  "byteorder",
- "digest 0.10.5",
+ "digest 0.10.6",
  "sha2 0.10.6",
  "sha3",
  "sp-std",
@@ -11816,9 +11910,9 @@
 
 [[package]]
 name = "ss58-registry"
-version = "1.33.0"
+version = "1.35.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ab7554f8a8b6f8d71cd5a8e6536ef116e2ce0504cf97ebf16311d58065dc8a6"
+checksum = "fa0813c10b9dbdc842c2305f949f724c64866e4ef4d09c9151e96f6a2106773c"
 dependencies = [
  "Inflector",
  "num-format",
@@ -12141,9 +12235,9 @@
 
 [[package]]
 name = "target-lexicon"
-version = "0.12.4"
+version = "0.12.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1"
+checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d"
 
 [[package]]
 name = "tempfile"
@@ -12368,9 +12462,9 @@
 
 [[package]]
 name = "tokio"
-version = "1.21.2"
+version = "1.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099"
+checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3"
 dependencies = [
  "autocfg",
  "bytes",
@@ -12694,7 +12788,7 @@
 checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
 dependencies = [
  "cfg-if 1.0.0",
- "digest 0.10.5",
+ "digest 0.10.6",
  "rand 0.8.5",
  "static_assertions",
 ]
@@ -13340,9 +13434,9 @@
 
 [[package]]
 name = "wasmtime"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1f511c4917c83d04da68333921107db75747c4e11a2f654a8e909cc5e0520dc"
+checksum = "4ad5af6ba38311282f2a21670d96e78266e8c8e2f38cbcd52c254df6ccbc7731"
 dependencies = [
  "anyhow",
  "bincode",
@@ -13368,18 +13462,18 @@
 
 [[package]]
 name = "wasmtime-asm-macros"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39bf3debfe744bf19dd3732990ce6f8c0ced7439e2370ba4e1d8f5a3660a3178"
+checksum = "45de63ddfc8b9223d1adc8f7b2ee5f35d1f6d112833934ad7ea66e4f4339e597"
 dependencies = [
  "cfg-if 1.0.0",
 ]
 
 [[package]]
 name = "wasmtime-cache"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ece42fa4676a263f7558cdaaf5a71c2592bebcbac22a0580e33cf3406c103da2"
+checksum = "bcd849399d17d2270141cfe47fa0d91ee52d5f8ea9b98cf7ddde0d53e5f79882"
 dependencies = [
  "anyhow",
  "base64",
@@ -13387,7 +13481,7 @@
  "directories-next",
  "file-per-thread-logger",
  "log",
- "rustix",
+ "rustix 0.35.13",
  "serde",
  "sha2 0.9.9",
  "toml",
@@ -13397,9 +13491,9 @@
 
 [[package]]
 name = "wasmtime-cranelift"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "058217e28644b012bdcdf0e445f58d496d78c2e0b6a6dd93558e701591dad705"
+checksum = "4bd91339b742ff20bfed4532a27b73c86b5bcbfedd6bea2dcdf2d64471e1b5c6"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -13418,9 +13512,9 @@
 
 [[package]]
 name = "wasmtime-environ"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7af06848df28b7661471d9a80d30a973e0f401f2e3ed5396ad7e225ed217047"
+checksum = "ebb881c61f4f627b5d45c54e629724974f8a8890d455bcbe634330cc27309644"
 dependencies = [
  "anyhow",
  "cranelift-entity",
@@ -13437,9 +13531,9 @@
 
 [[package]]
 name = "wasmtime-jit"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9028fb63a54185b3c192b7500ef8039c7bb8d7f62bfc9e7c258483a33a3d13bb"
+checksum = "1985c628011fe26adf5e23a5301bdc79b245e0e338f14bb58b39e4e25e4d8681"
 dependencies = [
  "addr2line",
  "anyhow",
@@ -13450,7 +13544,7 @@
  "log",
  "object",
  "rustc-demangle",
- "rustix",
+ "rustix 0.35.13",
  "serde",
  "target-lexicon",
  "thiserror",
@@ -13462,20 +13556,20 @@
 
 [[package]]
 name = "wasmtime-jit-debug"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25e82d4ef93296785de7efca92f7679dc67fe68a13b625a5ecc8d7503b377a37"
+checksum = "f671b588486f5ccec8c5a3dba6b4c07eac2e66ab8c60e6f4e53717c77f709731"
 dependencies = [
  "object",
  "once_cell",
- "rustix",
+ "rustix 0.35.13",
 ]
 
 [[package]]
 name = "wasmtime-runtime"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f0e9bea7d517d114fe66b930b2124ee086516ee93eeebfd97f75f366c5b0553"
+checksum = "ee8f92ad4b61736339c29361da85769ebc200f184361959d1792832e592a1afd"
 dependencies = [
  "anyhow",
  "cc",
@@ -13485,10 +13579,10 @@
  "log",
  "mach",
  "memfd",
- "memoffset",
+ "memoffset 0.6.5",
  "paste",
  "rand 0.8.5",
- "rustix",
+ "rustix 0.35.13",
  "thiserror",
  "wasmtime-asm-macros",
  "wasmtime-environ",
@@ -13498,9 +13592,9 @@
 
 [[package]]
 name = "wasmtime-types"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69b83e93ed41b8fdc936244cfd5e455480cf1eca1fd60c78a0040038b4ce5075"
+checksum = "d23d61cb4c46e837b431196dd06abb11731541021916d03476a178b54dc07aeb"
 dependencies = [
  "cranelift-entity",
  "serde",
@@ -13841,9 +13935,9 @@
 
 [[package]]
 name = "winreg"
-version = "0.7.0"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
+checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
 dependencies = [
  "winapi",
 ]
@@ -13856,9 +13950,9 @@
 
 [[package]]
 name = "wyz"
-version = "0.5.0"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e"
+checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
 dependencies = [
  "tap",
 ]
modifiedclient/rpc/Cargo.tomldiffbeforeafterboth
--- a/client/rpc/Cargo.toml
+++ b/client/rpc/Cargo.toml
@@ -19,4 +19,4 @@
 sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-rpc = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
modifiedcrates/evm-coder/CHANGELOG.mddiffbeforeafterboth
--- a/crates/evm-coder/CHANGELOG.md
+++ b/crates/evm-coder/CHANGELOG.md
@@ -3,6 +3,10 @@
 All notable changes to this project will be documented in this file.
 
 <!-- bureaucrate goes here -->
+## [v0.1.5] - 2022-11-30
+
+### Added
+- Derive macro to support structures and enums.
 
 ## [v0.1.4] - 2022-11-02
 
modifiedcrates/evm-coder/Cargo.tomldiffbeforeafterboth
--- a/crates/evm-coder/Cargo.toml
+++ b/crates/evm-coder/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "evm-coder"
-version = "0.1.4"
+version = "0.1.5"
 license = "GPLv3"
 edition = "2021"
 
@@ -19,14 +19,13 @@
 # We have tuple-heavy code in solidity.rs
 impl-trait-for-tuples = "0.2.2"
 
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 
 [dev-dependencies]
 # We want to assert some large binary blobs equality in tests
 hex = "0.4.3"
 hex-literal = "0.3.4"
 similar-asserts = "1.4.2"
-concat-idents = "1.1.3"
 trybuild = "1.0"
 
 [features]
modifiedcrates/evm-coder/procedural/Cargo.tomldiffbeforeafterboth
--- a/crates/evm-coder/procedural/Cargo.toml
+++ b/crates/evm-coder/procedural/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "evm-coder-procedural"
-version = "0.2.1"
+version = "0.2.2"
 license = "GPLv3"
 edition = "2021"
 
addedcrates/evm-coder/procedural/src/abi_derive/derive_enum.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/procedural/src/abi_derive/derive_enum.rs
@@ -0,0 +1,211 @@
+use quote::quote;
+
+pub fn impl_solidity_option<'a>(
+	name: &proc_macro2::Ident,
+	enum_options: impl Iterator<Item = &'a syn::Ident>,
+) -> proc_macro2::TokenStream {
+	let enum_options = enum_options.map(|opt| {
+		let s = name.to_string() + "." + opt.to_string().as_str();
+		let as_string = proc_macro2::Literal::string(s.as_str());
+		quote!(#name::#opt => #as_string,)
+	});
+	quote!(
+		#[cfg(feature = "stubgen")]
+		impl ::evm_coder::solidity::SolidityEnum for #name {
+			fn solidity_option(&self) -> &str {
+				match self {
+					#(#enum_options)*
+				}
+			}
+		}
+	)
+}
+
+pub fn impl_enum_from_u8<'a>(
+	name: &proc_macro2::Ident,
+	enum_options: impl Iterator<Item = &'a syn::Ident>,
+) -> proc_macro2::TokenStream {
+	let error_str = format!("Value not convertible into enum \"{name}\"");
+	let error_str = proc_macro2::Literal::string(&error_str);
+	let enum_options = enum_options.enumerate().map(|(i, opt)| {
+		let n = proc_macro2::Literal::u8_suffixed(i as u8);
+		quote! {#n => Ok(#name::#opt),}
+	});
+
+	quote!(
+		impl TryFrom<u8> for #name {
+			type Error = &'static str;
+
+			fn try_from(value: u8) -> ::core::result::Result<Self, Self::Error> {
+				const err: &'static str = #error_str;
+				match value {
+					#(#enum_options)*
+					_ => Err(err)
+				}
+			}
+		}
+	)
+}
+
+pub fn impl_enum_abi_type(name: &syn::Ident) -> proc_macro2::TokenStream {
+	quote! {
+		impl ::evm_coder::abi::AbiType for #name {
+			const SIGNATURE: ::evm_coder::custom_signature::SignatureUnit = <u8 as ::evm_coder::abi::AbiType>::SIGNATURE;
+
+			fn is_dynamic() -> bool {
+				<u8 as ::evm_coder::abi::AbiType>::is_dynamic()
+			}
+			fn size() -> usize {
+				<u8 as ::evm_coder::abi::AbiType>::size()
+			}
+		}
+	}
+}
+
+pub fn impl_enum_abi_read(name: &syn::Ident) -> proc_macro2::TokenStream {
+	quote!(
+		impl ::evm_coder::abi::AbiRead for #name {
+			fn abi_read(reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Self> {
+				Ok(
+					<u8 as ::evm_coder::abi::AbiRead>::abi_read(reader)?
+						.try_into()?
+				)
+			}
+		}
+	)
+}
+
+pub fn impl_enum_abi_write(name: &syn::Ident) -> proc_macro2::TokenStream {
+	quote!(
+		impl ::evm_coder::abi::AbiWrite for #name {
+			fn abi_write(&self, writer: &mut ::evm_coder::abi::AbiWriter) {
+				::evm_coder::abi::AbiWrite::abi_write(&(*self as u8), writer);
+			}
+		}
+	)
+}
+
+pub fn impl_enum_solidity_type_name(name: &syn::Ident) -> proc_macro2::TokenStream {
+	quote!(
+		#[cfg(feature = "stubgen")]
+		impl ::evm_coder::solidity::SolidityTypeName for #name {
+			fn solidity_name(
+				writer: &mut impl ::core::fmt::Write,
+				tc: &::evm_coder::solidity::TypeCollector,
+			) -> ::core::fmt::Result {
+				write!(writer, "{}", tc.collect_struct::<Self>())
+			}
+
+			fn is_simple() -> bool {
+				true
+			}
+
+			fn solidity_default(
+				writer: &mut impl ::core::fmt::Write,
+				tc: &::evm_coder::solidity::TypeCollector,
+			) -> ::core::fmt::Result {
+				write!(writer, "{}", <#name as ::evm_coder::solidity::SolidityEnum>::solidity_option(&<#name>::default()))
+			}
+		}
+	)
+}
+
+pub fn impl_enum_solidity_struct_collect<'a>(
+	name: &syn::Ident,
+	enum_options: impl Iterator<Item = &'a syn::Ident>,
+	option_count: usize,
+	enum_options_docs: impl Iterator<Item = syn::Result<Vec<proc_macro2::TokenStream>>>,
+	docs: &[proc_macro2::TokenStream],
+) -> proc_macro2::TokenStream {
+	let string_name = name.to_string();
+	let enum_options = enum_options
+		.zip(enum_options_docs)
+		.enumerate()
+		.map(|(i, (opt, doc))| {
+			let opt = proc_macro2::Literal::string(opt.to_string().as_str());
+			let doc = doc.expect("Doc parsing error");
+			let comma = if i != option_count - 1 { "," } else { "" };
+			quote! {
+				#(#doc)*
+				writeln!(str, "\t{}{}", #opt, #comma).expect("Enum format option");
+			}
+		});
+
+	quote!(
+		#[cfg(feature = "stubgen")]
+		impl ::evm_coder::solidity::StructCollect for #name {
+			fn name() -> String {
+				#string_name.into()
+			}
+
+			fn declaration() -> String {
+				use std::fmt::Write;
+
+				let mut str = String::new();
+				#(#docs)*
+				writeln!(str, "enum {} {{", <Self as ::evm_coder::solidity::StructCollect>::name()).unwrap();
+				#(#enum_options)*
+				writeln!(str, "}}").unwrap();
+				str
+			}
+		}
+	)
+}
+
+pub fn check_and_count_options(de: &syn::DataEnum) -> syn::Result<usize> {
+	let mut count = 0;
+	for v in de.variants.iter() {
+		if !v.fields.is_empty() {
+			return Err(syn::Error::new(
+				v.ident.span(),
+				"Enumeration parameters should not have fields",
+			));
+		} else if v.discriminant.is_some() {
+			return Err(syn::Error::new(
+				v.ident.span(),
+				"Enumeration options should not have an explicit specified value",
+			));
+		} else {
+			count += 1;
+		}
+	}
+
+	Ok(count)
+}
+
+pub fn check_repr_u8(name: &syn::Ident, attrs: &[syn::Attribute]) -> syn::Result<()> {
+	let mut has_repr = false;
+	for attr in attrs.iter() {
+		if attr.path.is_ident("repr") {
+			has_repr = true;
+			let meta = attr.parse_meta()?;
+			check_meta_u8(&meta)?;
+		}
+	}
+
+	if !has_repr {
+		return Err(syn::Error::new(name.span(), "Enum is not \"repr(u8)\""));
+	}
+
+	Ok(())
+}
+
+fn check_meta_u8(meta: &syn::Meta) -> Result<(), syn::Error> {
+	if let syn::Meta::List(p) = meta {
+		for nm in p.nested.iter() {
+			if let syn::NestedMeta::Meta(syn::Meta::Path(p)) = nm {
+				if !p.is_ident("u8") {
+					return Err(syn::Error::new(
+						p.segments
+							.first()
+							.expect("repr segments are empty")
+							.ident
+							.span(),
+						"Enum is not \"repr(u8)\"",
+					));
+				}
+			}
+		}
+	}
+	Ok(())
+}
addedcrates/evm-coder/procedural/src/abi_derive/derive_struct.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/procedural/src/abi_derive/derive_struct.rs
@@ -0,0 +1,260 @@
+use super::extract_docs;
+use quote::quote;
+
+pub fn tuple_type<'a>(
+	field_types: impl Iterator<Item = &'a syn::Type> + Clone,
+) -> proc_macro2::TokenStream {
+	let field_types = field_types.map(|ty| quote!(#ty,));
+	quote! {(#(#field_types)*)}
+}
+
+pub fn tuple_ref_type<'a>(
+	field_types: impl Iterator<Item = &'a syn::Type> + Clone,
+) -> proc_macro2::TokenStream {
+	let field_types = field_types.map(|ty| quote!(&#ty,));
+	quote! {(#(#field_types)*)}
+}
+
+pub fn tuple_data_as_ref(
+	is_named_fields: bool,
+	field_names: impl Iterator<Item = syn::Ident> + Clone,
+) -> proc_macro2::TokenStream {
+	let field_names = field_names.enumerate().map(|(i, field)| {
+		if is_named_fields {
+			quote!(&self.#field,)
+		} else {
+			let field = proc_macro2::Literal::usize_unsuffixed(i);
+			quote!(&self.#field,)
+		}
+	});
+	quote! {(#(#field_names)*)}
+}
+
+pub fn tuple_names(
+	is_named_fields: bool,
+	field_names: impl Iterator<Item = syn::Ident> + Clone,
+) -> proc_macro2::TokenStream {
+	let field_names = field_names.enumerate().map(|(i, field)| {
+		if is_named_fields {
+			quote!(#field,)
+		} else {
+			let field = proc_macro2::Ident::new(
+				format!("field{}", i).as_str(),
+				proc_macro2::Span::call_site(),
+			);
+			quote!(#field,)
+		}
+	});
+	quote! {(#(#field_names)*)}
+}
+
+pub fn struct_from_tuple(
+	name: &syn::Ident,
+	is_named_fields: bool,
+	field_names: impl Iterator<Item = syn::Ident> + Clone,
+) -> proc_macro2::TokenStream {
+	let field_names = field_names.enumerate().map(|(i, field)| {
+		if is_named_fields {
+			quote!(#field,)
+		} else {
+			let field = proc_macro2::Ident::new(
+				format!("field{}", i).as_str(),
+				proc_macro2::Span::call_site(),
+			);
+			quote!(#field,)
+		}
+	});
+
+	if is_named_fields {
+		quote! {#name {#(#field_names)*}}
+	} else {
+		quote! {#name (#(#field_names)*)}
+	}
+}
+
+pub fn map_field_to_name(field: (usize, &syn::Field)) -> syn::Ident {
+	match field.1.ident.as_ref() {
+		Some(name) => name.clone(),
+		None => {
+			let mut name = "field".to_string();
+			name.push_str(field.0.to_string().as_str());
+			syn::Ident::new(name.as_str(), proc_macro2::Span::call_site())
+		}
+	}
+}
+
+pub fn map_field_to_type(field: &syn::Field) -> &syn::Type {
+	&field.ty
+}
+
+pub fn map_field_to_doc(field: &syn::Field) -> syn::Result<Vec<proc_macro2::TokenStream>> {
+	extract_docs(&field.attrs, true)
+}
+
+pub fn impl_can_be_placed_in_vec(ident: &syn::Ident) -> proc_macro2::TokenStream {
+	quote! {
+		impl ::evm_coder::sealed::CanBePlacedInVec for #ident {}
+	}
+}
+
+pub fn impl_struct_abi_type(
+	name: &syn::Ident,
+	tuple_type: proc_macro2::TokenStream,
+) -> proc_macro2::TokenStream {
+	quote! {
+		impl ::evm_coder::abi::AbiType for #name {
+			const SIGNATURE: ::evm_coder::custom_signature::SignatureUnit = <#tuple_type as ::evm_coder::abi::AbiType>::SIGNATURE;
+			fn is_dynamic() -> bool {
+				<#tuple_type as ::evm_coder::abi::AbiType>::is_dynamic()
+			}
+			fn size() -> usize {
+				<#tuple_type as ::evm_coder::abi::AbiType>::size()
+			}
+		}
+	}
+}
+
+pub fn impl_struct_abi_read(
+	name: &syn::Ident,
+	tuple_type: proc_macro2::TokenStream,
+	tuple_names: proc_macro2::TokenStream,
+	struct_from_tuple: proc_macro2::TokenStream,
+) -> proc_macro2::TokenStream {
+	quote!(
+		impl ::evm_coder::abi::AbiRead for #name {
+			fn abi_read(reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Self> {
+				let #tuple_names = <#tuple_type as ::evm_coder::abi::AbiRead>::abi_read(reader)?;
+				Ok(#struct_from_tuple)
+			}
+		}
+	)
+}
+
+pub fn impl_struct_abi_write(
+	name: &syn::Ident,
+	_is_named_fields: bool,
+	tuple_type: proc_macro2::TokenStream,
+	tuple_data: proc_macro2::TokenStream,
+) -> proc_macro2::TokenStream {
+	quote!(
+		impl ::evm_coder::abi::AbiWrite for #name {
+			fn abi_write(&self, writer: &mut ::evm_coder::abi::AbiWriter) {
+				<#tuple_type as ::evm_coder::abi::AbiWrite>::abi_write(&#tuple_data, writer)
+			}
+		}
+	)
+}
+
+pub fn impl_struct_solidity_type<'a>(
+	name: &syn::Ident,
+	field_types: impl Iterator<Item = &'a syn::Type> + Clone,
+	params_count: usize,
+) -> proc_macro2::TokenStream {
+	let len = proc_macro2::Literal::usize_suffixed(params_count);
+	quote! {
+		#[cfg(feature = "stubgen")]
+		impl ::evm_coder::solidity::SolidityType for #name {
+			fn names(tc: &::evm_coder::solidity::TypeCollector) -> Vec<String> {
+				let mut collected =
+					Vec::with_capacity(<Self as ::evm_coder::solidity::SolidityType>::len());
+				#({
+					let mut out = String::new();
+					<#field_types as ::evm_coder::solidity::SolidityTypeName>::solidity_name(&mut out, tc)
+						.expect("no fmt error");
+					collected.push(out);
+				})*
+				collected
+			}
+
+			fn len() -> usize {
+				#len
+			}
+		}
+	}
+}
+
+pub fn impl_struct_solidity_type_name<'a>(
+	name: &syn::Ident,
+	field_types: impl Iterator<Item = &'a syn::Type> + Clone,
+	params_count: usize,
+) -> proc_macro2::TokenStream {
+	let arg_dafaults = field_types.enumerate().map(|(i, ty)| {
+		let mut defult_value = quote!(<#ty as ::evm_coder::solidity::SolidityTypeName
+			>::solidity_default(writer, tc)?;);
+		let last_item = params_count - 1;
+		if i != last_item {
+			defult_value.extend(quote! {write!(writer, ",")?;})
+		}
+		defult_value
+	});
+
+	quote! {
+		#[cfg(feature = "stubgen")]
+		impl ::evm_coder::solidity::SolidityTypeName for #name {
+			fn solidity_name(
+				writer: &mut impl ::core::fmt::Write,
+				tc: &::evm_coder::solidity::TypeCollector,
+			) -> ::core::fmt::Result {
+				write!(writer, "{}", tc.collect_struct::<Self>())
+			}
+
+			fn is_simple() -> bool {
+				false
+			}
+
+			fn solidity_default(
+				writer: &mut impl ::core::fmt::Write,
+				tc: &::evm_coder::solidity::TypeCollector,
+			) -> ::core::fmt::Result {
+				write!(writer, "{}(", tc.collect_struct::<Self>())?;
+
+				#(#arg_dafaults)*
+
+				write!(writer, ")")
+			}
+		}
+	}
+}
+
+pub fn impl_struct_solidity_struct_collect<'a>(
+	name: &syn::Ident,
+	field_names: impl Iterator<Item = proc_macro2::Ident> + Clone,
+	field_types: impl Iterator<Item = &'a syn::Type> + Clone,
+	field_docs: impl Iterator<Item = syn::Result<Vec<proc_macro2::TokenStream>>> + Clone,
+	docs: &[proc_macro2::TokenStream],
+) -> syn::Result<proc_macro2::TokenStream> {
+	let string_name = name.to_string();
+	let name_type = field_names
+		.into_iter()
+		.zip(field_types)
+		.zip(field_docs)
+		.map(|((name, ty), doc)| {
+			let field_docs = doc.expect("Doc parse error");
+			let name = format!("{}", name);
+			quote!(
+				#(#field_docs)*
+				write!(str, "\t{} ", <#ty as ::evm_coder::solidity::StructCollect>::name()).unwrap();
+				writeln!(str, "{};", #name).unwrap();
+			)
+		});
+
+	Ok(quote! {
+		#[cfg(feature = "stubgen")]
+		impl ::evm_coder::solidity::StructCollect for #name {
+			fn name() -> String {
+				#string_name.into()
+			}
+
+			fn declaration() -> String {
+				use std::fmt::Write;
+
+				let mut str = String::new();
+				#(#docs)*
+				writeln!(str, "struct {} {{", Self::name()).unwrap();
+				#(#name_type)*
+				writeln!(str, "}}").unwrap();
+				str
+			}
+		}
+	})
+}
addedcrates/evm-coder/procedural/src/abi_derive/mod.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/procedural/src/abi_derive/mod.rs
@@ -0,0 +1,145 @@
+mod derive_enum;
+mod derive_struct;
+
+use quote::quote;
+use derive_struct::*;
+use derive_enum::*;
+
+pub(crate) fn impl_abi_macro(ast: &syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
+	let name = &ast.ident;
+	match &ast.data {
+		syn::Data::Struct(ds) => expand_struct(ds, ast),
+		syn::Data::Enum(de) => expand_enum(de, ast),
+		syn::Data::Union(_) => Err(syn::Error::new(name.span(), "Unions not supported")),
+	}
+}
+
+fn expand_struct(
+	ds: &syn::DataStruct,
+	ast: &syn::DeriveInput,
+) -> syn::Result<proc_macro2::TokenStream> {
+	let name = &ast.ident;
+	let docs = extract_docs(&ast.attrs, false)?;
+	let (is_named_fields, field_names, field_types, field_docs, params_count) = match ds.fields {
+		syn::Fields::Named(ref fields) => Ok((
+			true,
+			fields.named.iter().enumerate().map(map_field_to_name),
+			fields.named.iter().map(map_field_to_type),
+			fields.named.iter().map(map_field_to_doc),
+			fields.named.len(),
+		)),
+		syn::Fields::Unnamed(ref fields) => Ok((
+			false,
+			fields.unnamed.iter().enumerate().map(map_field_to_name),
+			fields.unnamed.iter().map(map_field_to_type),
+			fields.unnamed.iter().map(map_field_to_doc),
+			fields.unnamed.len(),
+		)),
+		syn::Fields::Unit => Err(syn::Error::new(name.span(), "Unit structs not supported")),
+	}?;
+
+	if params_count == 0 {
+		return Err(syn::Error::new(name.span(), "Empty structs not supported"));
+	};
+
+	let tuple_type = tuple_type(field_types.clone());
+	let tuple_ref_type = tuple_ref_type(field_types.clone());
+	let tuple_data = tuple_data_as_ref(is_named_fields, field_names.clone());
+	let tuple_names = tuple_names(is_named_fields, field_names.clone());
+	let struct_from_tuple = struct_from_tuple(name, is_named_fields, field_names.clone());
+
+	let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name);
+	let abi_type = impl_struct_abi_type(name, tuple_type.clone());
+	let abi_read = impl_struct_abi_read(name, tuple_type, tuple_names, struct_from_tuple);
+	let abi_write = impl_struct_abi_write(name, is_named_fields, tuple_ref_type, tuple_data);
+	let solidity_type = impl_struct_solidity_type(name, field_types.clone(), params_count);
+	let solidity_type_name =
+		impl_struct_solidity_type_name(name, field_types.clone(), params_count);
+	let solidity_struct_collect =
+		impl_struct_solidity_struct_collect(name, field_names, field_types, field_docs, &docs)?;
+
+	Ok(quote! {
+		#can_be_plcaed_in_vec
+		#abi_type
+		#abi_read
+		#abi_write
+		#solidity_type
+		#solidity_type_name
+		#solidity_struct_collect
+	})
+}
+
+fn expand_enum(
+	de: &syn::DataEnum,
+	ast: &syn::DeriveInput,
+) -> syn::Result<proc_macro2::TokenStream> {
+	let name = &ast.ident;
+	check_repr_u8(name, &ast.attrs)?;
+	let docs = extract_docs(&ast.attrs, false)?;
+	let option_count = check_and_count_options(de)?;
+	let enum_options = de.variants.iter().map(|v| &v.ident);
+	let enum_options_docs = de.variants.iter().map(|v| extract_docs(&v.attrs, true));
+
+	let from = impl_enum_from_u8(name, enum_options.clone());
+	let solidity_option = impl_solidity_option(name, enum_options.clone());
+	let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name);
+	let abi_type = impl_enum_abi_type(name);
+	let abi_read = impl_enum_abi_read(name);
+	let abi_write = impl_enum_abi_write(name);
+	let solidity_type_name = impl_enum_solidity_type_name(name);
+	let solidity_struct_collect = impl_enum_solidity_struct_collect(
+		name,
+		enum_options,
+		option_count,
+		enum_options_docs,
+		&docs,
+	);
+
+	Ok(quote! {
+		#from
+		#solidity_option
+		#can_be_plcaed_in_vec
+		#abi_type
+		#abi_read
+		#abi_write
+		#solidity_type_name
+		#solidity_struct_collect
+	})
+}
+
+fn extract_docs(
+	attrs: &[syn::Attribute],
+	is_field_doc: bool,
+) -> syn::Result<Vec<proc_macro2::TokenStream>> {
+	attrs
+		.iter()
+		.filter_map(|attr| {
+			if let Some(ps) = attr.path.segments.first() {
+				if ps.ident == "doc" {
+					let meta = match attr.parse_meta() {
+						Ok(meta) => meta,
+						Err(e) => return Some(Err(e)),
+					};
+					match meta {
+						syn::Meta::NameValue(mnv) => match &mnv.lit {
+							syn::Lit::Str(ls) => return Some(Ok(ls.value())),
+							_ => unreachable!(),
+						},
+						_ => unreachable!(),
+					}
+				}
+			}
+			None
+		})
+		.enumerate()
+		.map(|(i, doc)| {
+			let doc = doc?;
+			let doc = doc.trim();
+			let dev = if i == 0 { " @dev" } else { "" };
+			let tab = if is_field_doc { "\t" } else { "" };
+			Ok(quote! {
+				writeln!(str, "{}///{} {}", #tab, #dev, #doc).unwrap();
+			})
+		})
+		.collect()
+}
modifiedcrates/evm-coder/procedural/src/lib.rsdiffbeforeafterboth
--- a/crates/evm-coder/procedural/src/lib.rs
+++ b/crates/evm-coder/procedural/src/lib.rs
@@ -25,6 +25,7 @@
 	parse_macro_input, spanned::Spanned,
 };
 
+mod abi_derive;
 mod solidity_interface;
 mod to_log;
 
@@ -242,3 +243,13 @@
 	}
 	.into()
 }
+
+#[proc_macro_derive(AbiCoder)]
+pub fn abi_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+	let ast = syn::parse(input).unwrap();
+	let ts = match abi_derive::impl_abi_macro(&ast) {
+		Ok(e) => e,
+		Err(e) => e.to_compile_error(),
+	};
+	ts.into()
+}
modifiedcrates/evm-coder/procedural/src/solidity_interface.rsdiffbeforeafterboth
--- a/crates/evm-coder/procedural/src/solidity_interface.rs
+++ b/crates/evm-coder/procedural/src/solidity_interface.rs
@@ -404,7 +404,11 @@
 		let name = &self.name;
 		let ty = &self.ty;
 		quote! {
-			#name: <#ty>::abi_read(reader)?
+			#name: {
+				let value = <#ty as ::evm_coder::abi::AbiRead>::abi_read(reader)?;
+				if !is_dynamic {reader.bytes_read(<#ty as ::evm_coder::abi::AbiType>::size())};
+				value
+			}
 		}
 	}
 
@@ -630,17 +634,18 @@
 		let pascal_name = &self.pascal_name;
 		let screaming_name = &self.screaming_name;
 		if self.has_normal_args {
-			let parsers = self
-				.args
-				.iter()
-				.filter(|a| !a.is_special())
-				.map(|a| a.expand_parse());
+			let args_iter = self.args.iter().filter(|a| !a.is_special());
+			let arg_type = args_iter.clone().map(|a| &a.ty);
+			let parsers = args_iter.map(|a| a.expand_parse());
 			quote! {
-				Self::#screaming_name => return Ok(Some(Self::#pascal_name {
-					#(
-						#parsers,
-					)*
-				}))
+				Self::#screaming_name => {
+					let is_dynamic = false #(|| <#arg_type as ::evm_coder::abi::AbiType>::is_dynamic())*;
+					return Ok(Some(Self::#pascal_name {
+						#(
+							#parsers,
+						)*
+					}))
+				}
 			}
 		} else {
 			quote! { Self::#screaming_name => return Ok(Some(Self::#pascal_name)) }
modifiedcrates/evm-coder/src/abi/impls.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/abi/impls.rs
+++ b/crates/evm-coder/src/abi/impls.rs
@@ -1,8 +1,8 @@
 use crate::{
+	custom_signature::SignatureUnit,
 	execution::{Result, ResultWithPostInfo, WithPostDispatchInfo},
+	make_signature, sealed,
 	types::*,
-	make_signature,
-	custom_signature::SignatureUnit,
 };
 use super::{traits::*, ABI_ALIGNMENT, AbiReader, AbiWriter};
 use primitive_types::{U256, H160};
@@ -10,12 +10,12 @@
 #[cfg(not(feature = "std"))]
 use alloc::vec::Vec;
 
-macro_rules! impl_abi_readable {
-	($ty:ty, $method:ident, $dynamic:literal) => {
+macro_rules! impl_abi_type {
+	($ty:ty, $name:ident, $dynamic:literal) => {
 		impl sealed::CanBePlacedInVec for $ty {}
 
 		impl AbiType for $ty {
-			const SIGNATURE: SignatureUnit = make_signature!(new fixed(stringify!($ty)));
+			const SIGNATURE: SignatureUnit = make_signature!(new fixed(stringify!($name)));
 
 			fn is_dynamic() -> bool {
 				$dynamic
@@ -25,7 +25,11 @@
 				ABI_ALIGNMENT
 			}
 		}
+	};
+}
 
+macro_rules! impl_abi_readable {
+	($ty:ty, $method:ident) => {
 		impl AbiRead for $ty {
 			fn abi_read(reader: &mut AbiReader) -> Result<$ty> {
 				reader.$method()
@@ -34,79 +38,93 @@
 	};
 }
 
-impl_abi_readable!(uint32, uint32, false);
-impl_abi_readable!(uint64, uint64, false);
-impl_abi_readable!(uint128, uint128, false);
-impl_abi_readable!(uint256, uint256, false);
-impl_abi_readable!(bytes4, bytes4, false);
-impl_abi_readable!(address, address, false);
-impl_abi_readable!(string, string, true);
+macro_rules! impl_abi_writeable {
+	($ty:ty, $method:ident) => {
+		impl AbiWrite for $ty {
+			fn abi_write(&self, writer: &mut AbiWriter) {
+				writer.$method(&self)
+			}
+		}
+	};
+}
 
-impl sealed::CanBePlacedInVec for bool {}
+macro_rules! impl_abi {
+	($ty:ty, $method:ident, $dynamic:literal) => {
+		impl_abi_type!($ty, $method, $dynamic);
+		impl_abi_readable!($ty, $method);
+		impl_abi_writeable!($ty, $method);
+	};
+}
 
-impl AbiType for bool {
-	const SIGNATURE: SignatureUnit = make_signature!(new fixed("bool"));
+impl_abi!(bool, bool, false);
+impl_abi!(u8, uint8, false);
+impl_abi!(u32, uint32, false);
+impl_abi!(u64, uint64, false);
+impl_abi!(u128, uint128, false);
+impl_abi!(U256, uint256, false);
+impl_abi!(H160, address, false);
+impl_abi!(string, string, true);
 
-	fn is_dynamic() -> bool {
-		false
-	}
-	fn size() -> usize {
-		ABI_ALIGNMENT
+impl_abi_writeable!(&str, string);
+
+impl_abi_type!(bytes, bytes, true);
+
+impl AbiRead for bytes {
+	fn abi_read(reader: &mut AbiReader) -> Result<bytes> {
+		Ok(bytes(reader.bytes()?))
 	}
 }
-impl AbiRead for bool {
-	fn abi_read(reader: &mut AbiReader) -> Result<bool> {
-		reader.bool()
+
+impl AbiWrite for bytes {
+	fn abi_write(&self, writer: &mut AbiWriter) {
+		writer.bytes(self.0.as_slice())
 	}
 }
-
-impl AbiType for uint8 {
-	const SIGNATURE: SignatureUnit = make_signature!(new fixed("uint8"));
 
-	fn is_dynamic() -> bool {
-		false
-	}
-	fn size() -> usize {
-		ABI_ALIGNMENT
+impl_abi_type!(bytes4, bytes4, false);
+impl AbiRead for bytes4 {
+	fn abi_read(reader: &mut AbiReader) -> Result<bytes4> {
+		reader.bytes4()
 	}
 }
-impl AbiRead for uint8 {
-	fn abi_read(reader: &mut AbiReader) -> Result<uint8> {
-		reader.uint8()
+
+impl<T: AbiWrite> AbiWrite for &T {
+	fn abi_write(&self, writer: &mut AbiWriter) {
+		T::abi_write(self, writer);
 	}
 }
 
-impl AbiType for bytes {
-	const SIGNATURE: SignatureUnit = make_signature!(new fixed("bytes"));
+impl<T: AbiType> AbiType for &T {
+	const SIGNATURE: SignatureUnit = T::SIGNATURE;
 
 	fn is_dynamic() -> bool {
-		true
+		T::is_dynamic()
 	}
+
 	fn size() -> usize {
-		ABI_ALIGNMENT
-	}
-}
-impl AbiRead for bytes {
-	fn abi_read(reader: &mut AbiReader) -> Result<bytes> {
-		Ok(bytes(reader.bytes()?))
+		T::size()
 	}
 }
 
-impl<R: AbiRead + sealed::CanBePlacedInVec> AbiRead for Vec<R> {
-	fn abi_read(reader: &mut AbiReader) -> Result<Vec<R>> {
+impl<T: AbiType + AbiRead + sealed::CanBePlacedInVec> AbiRead for Vec<T> {
+	fn abi_read(reader: &mut AbiReader) -> Result<Vec<T>> {
 		let mut sub = reader.subresult(None)?;
 		let size = sub.uint32()? as usize;
 		sub.subresult_offset = sub.offset;
+		let is_dynamic = <T as AbiType>::is_dynamic();
 		let mut out = Vec::with_capacity(size);
 		for _ in 0..size {
-			out.push(<R>::abi_read(&mut sub)?);
+			out.push(<T as AbiRead>::abi_read(&mut sub)?);
+			if !is_dynamic {
+				sub.bytes_read(<T as AbiType>::size());
+			};
 		}
 		Ok(out)
 	}
 }
 
-impl<R: AbiType> AbiType for Vec<R> {
-	const SIGNATURE: SignatureUnit = make_signature!(new nameof(R::SIGNATURE) fixed("[]"));
+impl<T: AbiType> AbiType for Vec<T> {
+	const SIGNATURE: SignatureUnit = make_signature!(new nameof(T::SIGNATURE) fixed("[]"));
 
 	fn is_dynamic() -> bool {
 		true
@@ -114,42 +132,6 @@
 
 	fn size() -> usize {
 		ABI_ALIGNMENT
-	}
-}
-
-impl sealed::CanBePlacedInVec for EthCrossAccount {}
-
-impl AbiType for EthCrossAccount {
-	const SIGNATURE: SignatureUnit = make_signature!(new fixed("(address,uint256)"));
-
-	fn is_dynamic() -> bool {
-		address::is_dynamic() || uint256::is_dynamic()
-	}
-
-	fn size() -> usize {
-		<address as AbiType>::size() + <uint256 as AbiType>::size()
-	}
-}
-
-impl AbiRead for EthCrossAccount {
-	fn abi_read(reader: &mut AbiReader) -> Result<EthCrossAccount> {
-		let size = if !EthCrossAccount::is_dynamic() {
-			Some(<EthCrossAccount as AbiType>::size())
-		} else {
-			None
-		};
-		let mut subresult = reader.subresult(size)?;
-		let eth = <address>::abi_read(&mut subresult)?;
-		let sub = <uint256>::abi_read(&mut subresult)?;
-
-		Ok(EthCrossAccount { eth, sub })
-	}
-}
-
-impl AbiWrite for EthCrossAccount {
-	fn abi_write(&self, writer: &mut AbiWriter) {
-		self.eth.abi_write(writer);
-		self.sub.abi_write(writer);
 	}
 }
 
@@ -188,36 +170,6 @@
 	}
 }
 
-macro_rules! impl_abi_writeable {
-	($ty:ty, $method:ident) => {
-		impl AbiWrite for $ty {
-			fn abi_write(&self, writer: &mut AbiWriter) {
-				writer.$method(&self)
-			}
-		}
-	};
-}
-
-impl_abi_writeable!(u8, uint8);
-impl_abi_writeable!(u32, uint32);
-impl_abi_writeable!(u128, uint128);
-impl_abi_writeable!(U256, uint256);
-impl_abi_writeable!(H160, address);
-impl_abi_writeable!(bool, bool);
-impl_abi_writeable!(&str, string);
-
-impl AbiWrite for string {
-	fn abi_write(&self, writer: &mut AbiWriter) {
-		writer.string(self)
-	}
-}
-
-impl AbiWrite for bytes {
-	fn abi_write(&self, writer: &mut AbiWriter) {
-		writer.bytes(self.0.as_slice())
-	}
-}
-
 impl<T: AbiWrite + AbiType> AbiWrite for Vec<T> {
 	fn abi_write(&self, writer: &mut AbiWriter) {
 		let is_dynamic = T::is_dynamic();
@@ -295,14 +247,19 @@
 
 		impl<$($ident),+> AbiRead for ($($ident,)+)
 		where
-			$($ident: AbiRead,)+
-			($($ident,)+): AbiType,
+			Self: AbiType,
+			$($ident: AbiRead + AbiType,)+
 		{
 			fn abi_read(reader: &mut AbiReader) -> Result<($($ident,)+)> {
-				let size = if !<($($ident,)+)>::is_dynamic() { Some(<($($ident,)+)>::size()) } else { None };
+				let is_dynamic = <Self>::is_dynamic();
+				let size = if !is_dynamic { Some(<Self>::size()) } else { None };
 				let mut subresult = reader.subresult(size)?;
 				Ok((
-					$(<$ident>::abi_read(&mut subresult)?,)+
+					$({
+						let value = <$ident>::abi_read(&mut subresult)?;
+						if !is_dynamic {subresult.bytes_read(<$ident as AbiType>::size())};
+						value
+					},)+
 				))
 			}
 		}
@@ -310,11 +267,11 @@
 		#[allow(non_snake_case)]
 		impl<$($ident),+> AbiWrite for ($($ident,)+)
 		where
-			$($ident: AbiWrite,)+
+			$($ident: AbiWrite + AbiType,)+
 		{
 			fn abi_write(&self, writer: &mut AbiWriter) {
 				let ($($ident,)+) = self;
-				if writer.is_dynamic {
+				if <Self as AbiType>::is_dynamic() {
 					let mut sub = AbiWriter::new();
 					$($ident.abi_write(&mut sub);)+
 					writer.write_subresult(sub);
modifiedcrates/evm-coder/src/abi/mod.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/abi/mod.rs
+++ b/crates/evm-coder/src/abi/mod.rs
@@ -75,19 +75,19 @@
 		buf: &[u8],
 		offset: usize,
 		pad_start: usize,
-		pad_size: usize,
+		pad_end: usize,
 		block_start: usize,
-		block_size: usize,
+		block_end: usize,
 	) -> Result<[u8; S]> {
 		if buf.len() - offset < ABI_ALIGNMENT {
 			return Err(Error::Error(ExitError::OutOfOffset));
 		}
 		let mut block = [0; S];
-		let is_pad_zeroed = buf[pad_start..pad_size].iter().all(|&v| v == 0);
+		let is_pad_zeroed = buf[pad_start..pad_end].iter().all(|&v| v == 0);
 		if !is_pad_zeroed {
 			return Err(Error::Error(ExitError::InvalidRange));
 		}
-		block.copy_from_slice(&buf[block_start..block_size]);
+		block.copy_from_slice(&buf[block_start..block_end]);
 		Ok(block)
 	}
 
@@ -186,11 +186,10 @@
 
 	/// Slice recursive buffer, advance one word for buffer offset
 	/// If `size` is [`None`] then [`Self::offset`] and [`Self::subresult_offset`] evals from [`Self::buf`].
-	fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {
+	pub fn subresult(&mut self, size: Option<usize>) -> Result<AbiReader<'i>> {
 		let subresult_offset = self.subresult_offset;
 		let offset = if let Some(size) = size {
 			self.offset += size;
-			self.subresult_offset += size;
 			0
 		} else {
 			self.uint32()? as usize
@@ -208,6 +207,11 @@
 		})
 	}
 
+	/// Notify about readed data portion.
+	pub fn bytes_read(&mut self, size: usize) {
+		self.subresult_offset += size;
+	}
+
 	/// Is this parser reached end of buffer?
 	pub fn is_finished(&self) -> bool {
 		self.buf.len() == self.offset
@@ -277,6 +281,11 @@
 		self.write_padleft(&u32::to_be_bytes(*value))
 	}
 
+	/// Write [`u64`] to end of buffer
+	pub fn uint64(&mut self, value: &u64) {
+		self.write_padleft(&u64::to_be_bytes(*value))
+	}
+
 	/// Write [`u128`] to end of buffer
 	pub fn uint128(&mut self, value: &u128) {
 		self.write_padleft(&u128::to_be_bytes(*value))
modifiedcrates/evm-coder/src/abi/test.rsdiffbeforeafterboth
before · crates/evm-coder/src/abi/test.rs
1use crate::{2	abi::{AbiRead, AbiWrite},3	types::*,4};56use super::{AbiReader, AbiWriter};7use hex_literal::hex;8use primitive_types::{H160, U256};9use concat_idents::concat_idents;1011macro_rules! test_impl {12    ($name:ident, $type:ty, $function_identifier:expr, $decoded_data:expr, $encoded_data:expr) => {13        concat_idents!(test_name = encode_decode_, $name {14            #[test]15            fn test_name() {16                let function_identifier: u32 = $function_identifier;17                let decoded_data = $decoded_data;18                let encoded_data = $encoded_data;1920                let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();21                assert_eq!(call, u32::to_be_bytes(function_identifier));22                let data = <$type>::abi_read(&mut decoder).unwrap();23                assert_eq!(data, decoded_data);2425                let mut writer = AbiWriter::new_call(function_identifier);26                decoded_data.abi_write(&mut writer);27                let ed = writer.finish();28                similar_asserts::assert_eq!(encoded_data, ed.as_slice());29            }30        });31    };32}3334macro_rules! test_impl_uint {35	($type:ident) => {36		test_impl!(37			$type,38			$type,39			0xdeadbeef,40			255 as $type,41			&hex!(42				"43                    deadbeef44                    00000000000000000000000000000000000000000000000000000000000000ff45                "46			)47		);48	};49}5051test_impl_uint!(uint8);52test_impl_uint!(uint32);53test_impl_uint!(uint128);5455test_impl!(56	uint256,57	uint256,58	0xdeadbeef,59	U256([255, 0, 0, 0]),60	&hex!(61		"62            deadbeef63            00000000000000000000000000000000000000000000000000000000000000ff64        "65	)66);6768test_impl!(69    vec_tuple_address_uint256,70    Vec<(address, uint256)>,71    0x1ACF2D55,72    vec![73        (74            H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),75            U256([10, 0, 0, 0]),76        ),77        (78            H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),79            U256([20, 0, 0, 0]),80        ),81        (82            H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),83            U256([30, 0, 0, 0]),84        ),85    ],86    &hex!(87        "88            1ACF2D5589            0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]90            0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]9192            0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address93            000000000000000000000000000000000000000000000000000000000000000A // uint2569495            000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address96            0000000000000000000000000000000000000000000000000000000000000014 // uint2569798            0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address99            000000000000000000000000000000000000000000000000000000000000001E // uint256100        "101    )102);103104test_impl!(105    vec_tuple_uint256_string,106    Vec<(uint256, string)>,107    0xdeadbeef,108    vec![109        (1.into(), "Test URI 0".to_string()),110        (11.into(), "Test URI 1".to_string()),111        (12.into(), "Test URI 2".to_string()),112    ],113    &hex!(114        "115            deadbeef116            0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]117            0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]118119            0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem120            00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem121            0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem122123            0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60124            0000000000000000000000000000000000000000000000000000000000000040 // offset of string125            000000000000000000000000000000000000000000000000000000000000000a // size of string126            5465737420555249203000000000000000000000000000000000000000000000 // string127128            000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0129            0000000000000000000000000000000000000000000000000000000000000040 // offset of string130            000000000000000000000000000000000000000000000000000000000000000a // size of string131            5465737420555249203100000000000000000000000000000000000000000000 // string132133            000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160134            0000000000000000000000000000000000000000000000000000000000000040 // offset of string135            000000000000000000000000000000000000000000000000000000000000000a // size of string136            5465737420555249203200000000000000000000000000000000000000000000 // string137        "138    )139);140141#[test]142fn dynamic_after_static() {143	let mut encoder = AbiWriter::new();144	encoder.bool(&true);145	encoder.string("test");146	let encoded = encoder.finish();147148	let mut encoder = AbiWriter::new();149	encoder.bool(&true);150	// Offset to subresult151	encoder.uint32(&(32 * 2));152	// Len of "test"153	encoder.uint32(&4);154	encoder.write_padright(&[b't', b'e', b's', b't']);155	let alternative_encoded = encoder.finish();156157	assert_eq!(encoded, alternative_encoded);158159	let mut decoder = AbiReader::new(&encoded);160	assert!(decoder.bool().unwrap());161	assert_eq!(decoder.string().unwrap(), "test");162}163164#[test]165fn mint_sample() {166	let (call, mut decoder) = AbiReader::new_call(&hex!(167		"168            50bb4e7f169            000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374170            0000000000000000000000000000000000000000000000000000000000000001171            0000000000000000000000000000000000000000000000000000000000000060172            0000000000000000000000000000000000000000000000000000000000000008173            5465737420555249000000000000000000000000000000000000000000000000174        "175	))176	.unwrap();177	assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));178	assert_eq!(179		format!("{:?}", decoder.address().unwrap()),180		"0xad2c0954693c2b5404b7e50967d3481bea432374"181	);182	assert_eq!(decoder.uint32().unwrap(), 1);183	assert_eq!(decoder.string().unwrap(), "Test URI");184}185186#[test]187fn parse_vec_with_dynamic_type() {188	let decoded_data = (189		0x36543006,190		vec![191			(1.into(), "Test URI 0".to_string()),192			(11.into(), "Test URI 1".to_string()),193			(12.into(), "Test URI 2".to_string()),194		],195	);196197	let encoded_data = &hex!(198        "199            36543006200            00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address201            0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]202            0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]203204            0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem205            00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem206            0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem207208            0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60209            0000000000000000000000000000000000000000000000000000000000000040 // offset of string210            000000000000000000000000000000000000000000000000000000000000000a // size of string211            5465737420555249203000000000000000000000000000000000000000000000 // string212213            000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0214            0000000000000000000000000000000000000000000000000000000000000040 // offset of string215            000000000000000000000000000000000000000000000000000000000000000a // size of string216            5465737420555249203100000000000000000000000000000000000000000000 // string217218            000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160219            0000000000000000000000000000000000000000000000000000000000000040 // offset of string220            000000000000000000000000000000000000000000000000000000000000000a // size of string221            5465737420555249203200000000000000000000000000000000000000000000 // string222        "223    );224225	let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();226	assert_eq!(call, u32::to_be_bytes(decoded_data.0));227	let address = decoder.address().unwrap();228	let data = <Vec<(uint256, string)>>::abi_read(&mut decoder).unwrap();229	assert_eq!(data, decoded_data.1);230231	let mut writer = AbiWriter::new_call(decoded_data.0);232	address.abi_write(&mut writer);233	decoded_data.1.abi_write(&mut writer);234	let ed = writer.finish();235	similar_asserts::assert_eq!(encoded_data, ed.as_slice());236}237238test_impl!(239	vec_tuple_string_bytes,240	Vec<(string, bytes)>,241	0xdeadbeef,242	vec![243		(244			"Test URI 0".to_string(),245			bytes(vec![246				0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,247				0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,248				0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,249				0x11, 0x11, 0x11, 0x11, 0x11, 0x11250			])251		),252		(253			"Test URI 1".to_string(),254			bytes(vec![255				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,256				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,257				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,258				0x22, 0x22, 0x22, 0x22, 0x22259			])260		),261		("Test URI 2".to_string(), bytes(vec![0x33, 0x33])),262	],263	&hex!(264		"265            deadbeef266            0000000000000000000000000000000000000000000000000000000000000020267            0000000000000000000000000000000000000000000000000000000000000003268            269            0000000000000000000000000000000000000000000000000000000000000060270            0000000000000000000000000000000000000000000000000000000000000140271            0000000000000000000000000000000000000000000000000000000000000220272273            0000000000000000000000000000000000000000000000000000000000000040274            0000000000000000000000000000000000000000000000000000000000000080275            000000000000000000000000000000000000000000000000000000000000000a276            5465737420555249203000000000000000000000000000000000000000000000277            0000000000000000000000000000000000000000000000000000000000000030278            1111111111111111111111111111111111111111111111111111111111111111279            1111111111111111111111111111111100000000000000000000000000000000280281            0000000000000000000000000000000000000000000000000000000000000040282            0000000000000000000000000000000000000000000000000000000000000080283            000000000000000000000000000000000000000000000000000000000000000a284            5465737420555249203100000000000000000000000000000000000000000000285            000000000000000000000000000000000000000000000000000000000000002f286            2222222222222222222222222222222222222222222222222222222222222222287            2222222222222222222222222222220000000000000000000000000000000000288289            0000000000000000000000000000000000000000000000000000000000000040290            0000000000000000000000000000000000000000000000000000000000000080291            000000000000000000000000000000000000000000000000000000000000000a292            5465737420555249203200000000000000000000000000000000000000000000293            0000000000000000000000000000000000000000000000000000000000000002294            3333000000000000000000000000000000000000000000000000000000000000295        "296	)297);
after · crates/evm-coder/src/abi/test.rs
1use crate::{2	abi::{AbiRead, AbiWrite},3	types::*,4};56use super::{AbiReader, AbiWriter};7use hex_literal::hex;8use primitive_types::{H160, U256};910fn test_impl<T>(function_identifier: u32, decoded_data: T, encoded_data: &[u8])11where12	T: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug,13{14	let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();15	assert_eq!(call, u32::to_be_bytes(function_identifier));16	let data = <T>::abi_read(&mut decoder).unwrap();17	assert_eq!(data, decoded_data);1819	let mut writer = AbiWriter::new_call(function_identifier);20	decoded_data.abi_write(&mut writer);21	let ed = writer.finish();22	similar_asserts::assert_eq!(encoded_data, ed.as_slice());23}2425macro_rules! test_impl_uint {26	($type:ident) => {27		test_impl::<$type>(28			0xdeadbeef,29			255 as $type,30			&hex!(31				"32                    deadbeef33                    00000000000000000000000000000000000000000000000000000000000000ff34                "35			),36		);37	};38}3940#[test]41fn encode_decode_uint8() {42	test_impl_uint!(uint8);43}4445#[test]46fn encode_decode_uint32() {47	test_impl_uint!(uint32);48}4950#[test]51fn encode_decode_uint128() {52	test_impl_uint!(uint128);53}5455#[test]56fn encode_decode_uint256() {57	test_impl::<uint256>(58		0xdeadbeef,59		U256([255, 0, 0, 0]),60		&hex!(61			"62                deadbeef63                00000000000000000000000000000000000000000000000000000000000000ff64            "65		),66	);67}6869#[test]70fn encode_decode_string() {71	test_impl::<String>(72		0xdeadbeef,73		"some string".to_string(),74		&hex!(75			"76                deadbeef77                000000000000000000000000000000000000000000000000000000000000002078                000000000000000000000000000000000000000000000000000000000000000b79                736f6d6520737472696e6700000000000000000000000000000000000000000080            "81		),82	);83}8485#[test]86fn encode_decode_tuple_string() {87	test_impl::<(String,)>(88		0xdeadbeef,89		("some string".to_string(),),90		&hex!(91			"92                deadbeef93                000000000000000000000000000000000000000000000000000000000000002094                000000000000000000000000000000000000000000000000000000000000002095                000000000000000000000000000000000000000000000000000000000000000b96                736f6d6520737472696e6700000000000000000000000000000000000000000097            "98		),99	);100}101102#[test]103fn encode_decode_vec_tuple_address_uint256() {104	test_impl::<Vec<(address, uint256)>>(105        0x1ACF2D55,106        vec![107            (108                H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),109                U256([10, 0, 0, 0]),110            ),111            (112                H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),113                U256([20, 0, 0, 0]),114            ),115            (116                H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),117                U256([30, 0, 0, 0]),118            ),119        ],120        &hex!(121            "122                1ACF2D55123                0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]124                0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]125126                0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address127                000000000000000000000000000000000000000000000000000000000000000A // uint256128129                000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address130                0000000000000000000000000000000000000000000000000000000000000014 // uint256131132                0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address133                000000000000000000000000000000000000000000000000000000000000001E // uint256134            "135        )136    );137}138139#[test]140fn encode_decode_vec_tuple_uint256_string() {141	test_impl::<Vec<(uint256, string)>>(142        0xdeadbeef,143        vec![144            (1.into(), "Test URI 0".to_string()),145            (11.into(), "Test URI 1".to_string()),146            (12.into(), "Test URI 2".to_string()),147        ],148        &hex!(149            "150                deadbeef151                0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]152                0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]153154                0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem155                00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem156                0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem157158                0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60159                0000000000000000000000000000000000000000000000000000000000000040 // offset of string160                000000000000000000000000000000000000000000000000000000000000000a // size of string161                5465737420555249203000000000000000000000000000000000000000000000 // string162163                000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0164                0000000000000000000000000000000000000000000000000000000000000040 // offset of string165                000000000000000000000000000000000000000000000000000000000000000a // size of string166                5465737420555249203100000000000000000000000000000000000000000000 // string167168                000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160169                0000000000000000000000000000000000000000000000000000000000000040 // offset of string170                000000000000000000000000000000000000000000000000000000000000000a // size of string171                5465737420555249203200000000000000000000000000000000000000000000 // string172            "173        )174    );175}176177#[test]178fn dynamic_after_static() {179	let mut encoder = AbiWriter::new();180	encoder.bool(&true);181	encoder.string("test");182	let encoded = encoder.finish();183184	let mut encoder = AbiWriter::new();185	encoder.bool(&true);186	// Offset to subresult187	encoder.uint32(&(32 * 2));188	// Len of "test"189	encoder.uint32(&4);190	encoder.write_padright(&[b't', b'e', b's', b't']);191	let alternative_encoded = encoder.finish();192193	assert_eq!(encoded, alternative_encoded);194195	let mut decoder = AbiReader::new(&encoded);196	assert!(decoder.bool().unwrap());197	assert_eq!(decoder.string().unwrap(), "test");198}199200#[test]201fn mint_sample() {202	let (call, mut decoder) = AbiReader::new_call(&hex!(203		"204            50bb4e7f205            000000000000000000000000ad2c0954693c2b5404b7e50967d3481bea432374206            0000000000000000000000000000000000000000000000000000000000000001207            0000000000000000000000000000000000000000000000000000000000000060208            0000000000000000000000000000000000000000000000000000000000000008209            5465737420555249000000000000000000000000000000000000000000000000210        "211	))212	.unwrap();213	assert_eq!(call, u32::to_be_bytes(0x50bb4e7f));214	assert_eq!(215		format!("{:?}", decoder.address().unwrap()),216		"0xad2c0954693c2b5404b7e50967d3481bea432374"217	);218	assert_eq!(decoder.uint32().unwrap(), 1);219	assert_eq!(decoder.string().unwrap(), "Test URI");220}221222#[test]223fn parse_vec_with_dynamic_type() {224	let decoded_data = (225		0x36543006,226		vec![227			(1.into(), "Test URI 0".to_string()),228			(11.into(), "Test URI 1".to_string()),229			(12.into(), "Test URI 2".to_string()),230		],231	);232233	let encoded_data = &hex!(234        "235            36543006236            00000000000000000000000053744e6da587ba10b32a2554d2efdcd985bc27a3 // address237            0000000000000000000000000000000000000000000000000000000000000040 // offset of (uint256, string)[]238            0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]239240            0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem241            00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem242            0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem243244            0000000000000000000000000000000000000000000000000000000000000001 // first token id?   					#60245            0000000000000000000000000000000000000000000000000000000000000040 // offset of string246            000000000000000000000000000000000000000000000000000000000000000a // size of string247            5465737420555249203000000000000000000000000000000000000000000000 // string248249            000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11?			#e0250            0000000000000000000000000000000000000000000000000000000000000040 // offset of string251            000000000000000000000000000000000000000000000000000000000000000a // size of string252            5465737420555249203100000000000000000000000000000000000000000000 // string253254            000000000000000000000000000000000000000000000000000000000000000c // third token id?  Why ==12?			#160255            0000000000000000000000000000000000000000000000000000000000000040 // offset of string256            000000000000000000000000000000000000000000000000000000000000000a // size of string257            5465737420555249203200000000000000000000000000000000000000000000 // string258        "259    );260261	let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();262	assert_eq!(call, u32::to_be_bytes(decoded_data.0));263	let address = decoder.address().unwrap();264	let data = <Vec<(uint256, string)>>::abi_read(&mut decoder).unwrap();265	assert_eq!(data, decoded_data.1);266267	let mut writer = AbiWriter::new_call(decoded_data.0);268	address.abi_write(&mut writer);269	decoded_data.1.abi_write(&mut writer);270	let ed = writer.finish();271	similar_asserts::assert_eq!(encoded_data, ed.as_slice());272}273274#[test]275fn encode_decode_vec_tuple_string_bytes() {276	test_impl::<Vec<(string, bytes)>>(277		0xdeadbeef,278		vec![279			(280				"Test URI 0".to_string(),281				bytes(vec![282					0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,283					0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,284					0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,285					0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,286				]),287			),288			(289				"Test URI 1".to_string(),290				bytes(vec![291					0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,292					0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,293					0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,294					0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,295				]),296			),297			("Test URI 2".to_string(), bytes(vec![0x33, 0x33])),298		],299		&hex!(300			"301                deadbeef302                0000000000000000000000000000000000000000000000000000000000000020303                0000000000000000000000000000000000000000000000000000000000000003304305                0000000000000000000000000000000000000000000000000000000000000060306                0000000000000000000000000000000000000000000000000000000000000140307                0000000000000000000000000000000000000000000000000000000000000220308309                0000000000000000000000000000000000000000000000000000000000000040310                0000000000000000000000000000000000000000000000000000000000000080311                000000000000000000000000000000000000000000000000000000000000000a312                5465737420555249203000000000000000000000000000000000000000000000313                0000000000000000000000000000000000000000000000000000000000000030314                1111111111111111111111111111111111111111111111111111111111111111315                1111111111111111111111111111111100000000000000000000000000000000316317                0000000000000000000000000000000000000000000000000000000000000040318                0000000000000000000000000000000000000000000000000000000000000080319                000000000000000000000000000000000000000000000000000000000000000a320                5465737420555249203100000000000000000000000000000000000000000000321                000000000000000000000000000000000000000000000000000000000000002f322                2222222222222222222222222222222222222222222222222222222222222222323                2222222222222222222222222222220000000000000000000000000000000000324325                0000000000000000000000000000000000000000000000000000000000000040326                0000000000000000000000000000000000000000000000000000000000000080327                000000000000000000000000000000000000000000000000000000000000000a328                5465737420555249203200000000000000000000000000000000000000000000329                0000000000000000000000000000000000000000000000000000000000000002330                3333000000000000000000000000000000000000000000000000000000000000331            "332		),333	);334}335336#[test]337// #[ignore = "reason"]338fn encode_decode_tuple0_tuple1_uint8_tuple1_string_bytes_tuple1_uint8_bytes() {339	let int = 0xff;340	let by = bytes(vec![0x11, 0x22, 0x33]);341	let string = "some string".to_string();342343	test_impl::<((u8,), (String, bytes), (u8, bytes))>(344		0xdeadbeef,345		((int,), (string.clone(), by.clone()), (int, by)),346		&hex!(347			"348                deadbeef349                0000000000000000000000000000000000000000000000000000000000000020350                00000000000000000000000000000000000000000000000000000000000000ff351                0000000000000000000000000000000000000000000000000000000000000060352                0000000000000000000000000000000000000000000000000000000000000120353                0000000000000000000000000000000000000000000000000000000000000040354                0000000000000000000000000000000000000000000000000000000000000080355                000000000000000000000000000000000000000000000000000000000000000b356                736f6d6520737472696e67000000000000000000000000000000000000000000357                0000000000000000000000000000000000000000000000000000000000000003358                1122330000000000000000000000000000000000000000000000000000000000359                00000000000000000000000000000000000000000000000000000000000000ff360                0000000000000000000000000000000000000000000000000000000000000040361                0000000000000000000000000000000000000000000000000000000000000003362                1122330000000000000000000000000000000000000000000000000000000000363            "364		),365	);366}367368#[test]369fn encode_decode_tuple0_tuple1_uint8_tuple1_uint8_uint8_tuple1_uint8_uint8() {370	test_impl::<((u8,), (u8, u8), (u8, u8))>(371		0xdeadbeef,372		((43,), (44, 45), (46, 47)),373		&hex!(374			"375                deadbeef376                000000000000000000000000000000000000000000000000000000000000002b377                000000000000000000000000000000000000000000000000000000000000002c378                000000000000000000000000000000000000000000000000000000000000002d379                000000000000000000000000000000000000000000000000000000000000002e380                000000000000000000000000000000000000000000000000000000000000002f381            "382		),383	);384}385386#[test]387fn encode_decode_tuple0_tuple1_uint8_tuple1_uint8() {388	test_impl::<((u8,), (u8,))>(389		0xdeadbeef,390		((43,), (44,)),391		&hex!(392			"393                deadbeef394                000000000000000000000000000000000000000000000000000000000000002b395                000000000000000000000000000000000000000000000000000000000000002c396            "397		),398	);399}400401#[test]402fn encode_decode_tuple0_tuple1_uint8_uint8() {403	test_impl::<((u8, u8),)>(404		0xdeadbeef,405		((43, 44),),406		&hex!(407			"408                deadbeef409                000000000000000000000000000000000000000000000000000000000000002b410                000000000000000000000000000000000000000000000000000000000000002c411            "412		),413	);414}415416#[test]417fn encode_decode_tuple_uint8_uint8() {418	test_impl::<(u8, u8)>(419		0xdeadbeef,420		(43, 44),421		&hex!(422			"423                deadbeef424                000000000000000000000000000000000000000000000000000000000000002b425                000000000000000000000000000000000000000000000000000000000000002c426            "427		),428	);429}430431#[test]432fn encode_decode_tuple0_tuple1_uint8_uint8_tuple1_uint8_uint8_and_uint8() {433	test_impl::<((u8, u8), (u8, u8), u8)>(434		0xdeadbeef,435		((10, 11), (12, 13), 14),436		&hex!(437			"438                deadbeef439                000000000000000000000000000000000000000000000000000000000000000a440                000000000000000000000000000000000000000000000000000000000000000b441                000000000000000000000000000000000000000000000000000000000000000c442                000000000000000000000000000000000000000000000000000000000000000d443                000000000000000000000000000000000000000000000000000000000000000e444            "445		),446	);447}448449#[test]450fn encode_decode_tuple0_tuple1_string() {451	test_impl::<((String,),)>(452		0xdeadbeef,453		(("some string".to_string(),),),454		&hex!(455			"456                deadbeef457                0000000000000000000000000000000000000000000000000000000000000020458                0000000000000000000000000000000000000000000000000000000000000020459                0000000000000000000000000000000000000000000000000000000000000020460                000000000000000000000000000000000000000000000000000000000000000b461                736f6d6520737472696e67000000000000000000000000000000000000000000462            "463		),464	);465}466467#[test]468fn encode_decode_tuple0_tuple1_uint8_string() {469	test_impl::<((u8, String),)>(470		0xdeadbeef,471		((0xff, "some string".to_string()),),472		&hex!(473			"474                deadbeef475                0000000000000000000000000000000000000000000000000000000000000020476                0000000000000000000000000000000000000000000000000000000000000020477                00000000000000000000000000000000000000000000000000000000000000ff478                0000000000000000000000000000000000000000000000000000000000000040479                000000000000000000000000000000000000000000000000000000000000000b480                736f6d6520737472696e67000000000000000000000000000000000000000000481            "482		),483	);484}485486#[test]487fn encode_decode_tuple0_tuple1_string_bytes() {488	test_impl::<((String, bytes),)>(489		0xdeadbeef,490		(("some string".to_string(), bytes(vec![1, 2, 3])),),491		&hex!(492			"493                deadbeef494                0000000000000000000000000000000000000000000000000000000000000020495                0000000000000000000000000000000000000000000000000000000000000020496                0000000000000000000000000000000000000000000000000000000000000040497                0000000000000000000000000000000000000000000000000000000000000080498                000000000000000000000000000000000000000000000000000000000000000b499                736f6d6520737472696e67000000000000000000000000000000000000000000500                0000000000000000000000000000000000000000000000000000000000000003501                0102030000000000000000000000000000000000000000000000000000000000502            "503		),504	);505}506507#[test]508fn encode_decode_tuple0_tuple1_uint8_tuple1_string() {509	test_impl::<((u8,), (String,))>(510		0xdeadbeef,511		((0xff,), ("some string".to_string(),)),512		&hex!(513			"514                deadbeef515                0000000000000000000000000000000000000000000000000000000000000020516                00000000000000000000000000000000000000000000000000000000000000ff517                0000000000000000000000000000000000000000000000000000000000000040518                0000000000000000000000000000000000000000000000000000000000000020519                000000000000000000000000000000000000000000000000000000000000000b520                736f6d6520737472696e67000000000000000000000000000000000000000000521            "522		),523	);524}525526#[test]527fn parse_multiple_params() {528	let encoded_data = hex!(529		"530            deadbeef531            000000000000000000000000000000000000000000000000000000000000000a532            000000000000000000000000000000000000000000000000000000000000000b533        "534	);535	let (_, mut decoder) = AbiReader::new_call(&encoded_data).unwrap();536	let p1 = <u8>::abi_read(&mut decoder).unwrap();537	let p2 = <u8>::abi_read(&mut decoder).unwrap();538	assert_eq!(p1, 0x0a);539	assert_eq!(p2, 0x0b);540}
modifiedcrates/evm-coder/src/abi/traits.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/abi/traits.rs
+++ b/crates/evm-coder/src/abi/traits.rs
@@ -22,12 +22,6 @@
 	fn size() -> usize;
 }
 
-/// Sealed traits.
-pub mod sealed {
-	/// Not all types can be placed in vec, i.e `Vec<u8>` is restricted, `bytes` should be used instead
-	pub trait CanBePlacedInVec {}
-}
-
 /// [`AbiReader`] implements reading of many types.
 pub trait AbiRead {
 	/// Read item from current position, advanding decoder
@@ -47,11 +41,5 @@
 		let mut writer = AbiWriter::new();
 		self.abi_write(&mut writer);
 		Ok(writer.into())
-	}
-}
-
-impl<T: AbiWrite> AbiWrite for &T {
-	fn abi_write(&self, writer: &mut AbiWriter) {
-		T::abi_write(self, writer);
 	}
 }
modifiedcrates/evm-coder/src/lib.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -93,6 +93,7 @@
 pub use evm_coder_procedural::solidity;
 /// See [`solidity_interface`]
 pub use evm_coder_procedural::weight;
+pub use evm_coder_procedural::AbiCoder;
 pub use sha3_const;
 
 /// Derives [`ToLog`] for enum
@@ -111,6 +112,15 @@
 #[cfg(feature = "stubgen")]
 pub mod solidity;
 
+/// Sealed traits.
+pub mod sealed {
+	/// Not every type should be directly placed in vec.
+	/// Vec encoding is not memory efficient, as every item will be padded
+	/// to 32 bytes.
+	/// Instead you should use specialized types (`bytes` in case of `Vec<u8>`)
+	pub trait CanBePlacedInVec {}
+}
+
 /// Solidity type definitions (aliases from solidity name to rust type)
 /// To be used in [`solidity_interface`] definitions, to make sure there is no
 /// type conflict between Rust code and generated definitions
@@ -119,7 +129,6 @@
 
 	#[cfg(not(feature = "std"))]
 	use alloc::{vec::Vec};
-	use pallet_evm::account::CrossAccountId;
 	use primitive_types::{U256, H160, H256};
 
 	pub type address = H160;
@@ -137,7 +146,7 @@
 	#[cfg(feature = "std")]
 	pub type string = ::std::string::String;
 
-	#[derive(Default, Debug, PartialEq)]
+	#[derive(Default, Debug, PartialEq, Eq, Clone)]
 	pub struct bytes(pub Vec<u8>);
 
 	/// Solidity doesn't have `void` type, however we have special implementation
@@ -185,73 +194,7 @@
 		#[must_use]
 		pub fn is_empty(&self) -> bool {
 			self.len() == 0
-		}
-	}
-
-	#[derive(Debug, Default)]
-	pub struct EthCrossAccount {
-		pub(crate) eth: address,
-		pub(crate) sub: uint256,
-	}
-
-	impl EthCrossAccount {
-		pub fn from_sub_cross_account<T>(cross_account_id: &T::CrossAccountId) -> Self
-		where
-			T: pallet_evm::account::Config,
-			T::AccountId: AsRef<[u8; 32]>,
-		{
-			if cross_account_id.is_canonical_substrate() {
-				Self {
-					eth: Default::default(),
-					sub: convert_cross_account_to_uint256::<T>(cross_account_id),
-				}
-			} else {
-				Self {
-					eth: *cross_account_id.as_eth(),
-					sub: Default::default(),
-				}
-			}
 		}
-
-		pub fn into_sub_cross_account<T>(&self) -> crate::execution::Result<T::CrossAccountId>
-		where
-			T: pallet_evm::account::Config,
-			T::AccountId: From<[u8; 32]>,
-		{
-			if self.eth == Default::default() && self.sub == Default::default() {
-				Err("All fields of cross account is zeroed".into())
-			} else if self.eth == Default::default() {
-				Ok(convert_uint256_to_cross_account::<T>(self.sub))
-			} else if self.sub == Default::default() {
-				Ok(T::CrossAccountId::from_eth(self.eth))
-			} else {
-				Err("All fields of cross account is non zeroed".into())
-			}
-		}
-	}
-
-	/// Convert `CrossAccountId` to `uint256`.
-	pub fn convert_cross_account_to_uint256<T: pallet_evm::account::Config>(
-		from: &T::CrossAccountId,
-	) -> uint256
-	where
-		T::AccountId: AsRef<[u8; 32]>,
-	{
-		let slice = from.as_sub().as_ref();
-		uint256::from_big_endian(slice)
-	}
-
-	/// Convert `uint256` to `CrossAccountId`.
-	pub fn convert_uint256_to_cross_account<T: pallet_evm::account::Config>(
-		from: uint256,
-	) -> T::CrossAccountId
-	where
-		T::AccountId: From<[u8; 32]>,
-	{
-		let mut new_admin_arr = [0_u8; 32];
-		from.to_big_endian(&mut new_admin_arr);
-		let account_id = T::AccountId::from(new_admin_arr);
-		T::CrossAccountId::from_sub(account_id)
 	}
 
 	#[derive(Debug, Default)]
deletedcrates/evm-coder/src/solidity.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/solidity.rs
+++ /dev/null
@@ -1,702 +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/>.
-
-//! Implementation detail of [`crate::solidity_interface`] macro code-generation.
-//! You should not rely on any public item from this module, as it is only intended to be used
-//! by procedural macro, API and output format may be changed at any time.
-//!
-//! Purpose of this module is to receive solidity contract definition in module-specified
-//! format, and then output string, representing interface of this contract in solidity language
-
-#[cfg(not(feature = "std"))]
-use alloc::{string::String, vec::Vec, collections::BTreeMap, format};
-#[cfg(feature = "std")]
-use std::collections::BTreeMap;
-use core::{
-	fmt::{self, Write},
-	marker::PhantomData,
-	cell::{Cell, RefCell},
-	cmp::Reverse,
-};
-use impl_trait_for_tuples::impl_for_tuples;
-use crate::{types::*, custom_signature::SignatureUnit};
-
-#[derive(Default)]
-pub struct TypeCollector {
-	/// Code => id
-	/// id ordering is required to perform topo-sort on the resulting data
-	structs: RefCell<BTreeMap<string, usize>>,
-	anonymous: RefCell<BTreeMap<Vec<string>, usize>>,
-	id: Cell<usize>,
-}
-impl TypeCollector {
-	pub fn new() -> Self {
-		Self::default()
-	}
-	pub fn collect(&self, item: string) {
-		let id = self.next_id();
-		self.structs.borrow_mut().insert(item, id);
-	}
-	pub fn next_id(&self) -> usize {
-		let v = self.id.get();
-		self.id.set(v + 1);
-		v
-	}
-	pub fn collect_tuple<T: SolidityTupleType>(&self) -> String {
-		let names = T::names(self);
-		if let Some(id) = self.anonymous.borrow().get(&names).cloned() {
-			return format!("Tuple{}", id);
-		}
-		let id = self.next_id();
-		let mut str = String::new();
-		writeln!(str, "/// @dev anonymous struct").unwrap();
-		writeln!(str, "struct Tuple{} {{", id).unwrap();
-		for (i, name) in names.iter().enumerate() {
-			writeln!(str, "\t{} field_{};", name, i).unwrap();
-		}
-		writeln!(str, "}}").unwrap();
-		self.collect(str);
-		self.anonymous.borrow_mut().insert(names, id);
-		format!("Tuple{}", id)
-	}
-	pub fn collect_struct<T: StructCollect>(&self) -> String {
-		self.collect(<T as StructCollect>::declaration());
-		<T as StructCollect>::name()
-	}
-	pub fn finish(self) -> Vec<string> {
-		let mut data = self.structs.into_inner().into_iter().collect::<Vec<_>>();
-		data.sort_by_key(|(_, id)| Reverse(*id));
-		data.into_iter().map(|(code, _)| code).collect()
-	}
-}
-
-pub trait StructCollect: 'static {
-	/// Structure name.
-	fn name() -> String;
-	/// Structure declaration.
-	fn declaration() -> String;
-}
-
-pub trait SolidityTypeName: 'static {
-	fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
-	/// "simple" types are stored inline, no `memory` modifier should be used in solidity
-	fn is_simple() -> bool;
-	fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
-	/// Specialization
-	fn is_void() -> bool {
-		false
-	}
-}
-macro_rules! solidity_type_name {
-    ($($ty:ty => $name:literal $simple:literal = $default:literal),* $(,)?) => {
-        $(
-            impl SolidityTypeName for $ty {
-                fn solidity_name(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {
-                    write!(writer, $name)
-                }
-				fn is_simple() -> bool {
-					$simple
-				}
-				fn solidity_default(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {
-					write!(writer, $default)
-				}
-            }
-        )*
-    };
-}
-
-solidity_type_name! {
-	uint8 => "uint8" true = "0",
-	uint32 => "uint32" true = "0",
-	uint64 => "uint64" true = "0",
-	uint128 => "uint128" true = "0",
-	uint256 => "uint256" true = "0",
-	bytes4 => "bytes4" true = "bytes4(0)",
-	address => "address" true = "0x0000000000000000000000000000000000000000",
-	string => "string" false = "\"\"",
-	bytes => "bytes" false = "hex\"\"",
-	bool => "bool" true = "false",
-}
-impl SolidityTypeName for void {
-	fn solidity_name(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
-		Ok(())
-	}
-	fn is_simple() -> bool {
-		true
-	}
-	fn solidity_default(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
-		Ok(())
-	}
-	fn is_void() -> bool {
-		true
-	}
-}
-
-mod sealed {
-	/// Not every type should be directly placed in vec.
-	/// Vec encoding is not memory efficient, as every item will be padded
-	/// to 32 bytes.
-	/// Instead you should use specialized types (`bytes` in case of `Vec<u8>`)
-	pub trait CanBePlacedInVec {}
-}
-
-impl sealed::CanBePlacedInVec for uint256 {}
-impl sealed::CanBePlacedInVec for string {}
-impl sealed::CanBePlacedInVec for address {}
-impl sealed::CanBePlacedInVec for EthCrossAccount {}
-impl sealed::CanBePlacedInVec for Property {}
-
-impl<T: SolidityTypeName + sealed::CanBePlacedInVec> SolidityTypeName for Vec<T> {
-	fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		T::solidity_name(writer, tc)?;
-		write!(writer, "[]")
-	}
-	fn is_simple() -> bool {
-		false
-	}
-	fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		write!(writer, "new ")?;
-		T::solidity_name(writer, tc)?;
-		write!(writer, "[](0)")
-	}
-}
-
-impl SolidityTupleType for EthCrossAccount {
-	fn names(tc: &TypeCollector) -> Vec<string> {
-		let mut collected = Vec::with_capacity(Self::len());
-		{
-			let mut out = string::new();
-			address::solidity_name(&mut out, tc).expect("no fmt error");
-			collected.push(out);
-		}
-		{
-			let mut out = string::new();
-			uint256::solidity_name(&mut out, tc).expect("no fmt error");
-			collected.push(out);
-		}
-		collected
-	}
-
-	fn len() -> usize {
-		2
-	}
-}
-
-impl SolidityTypeName for EthCrossAccount {
-	fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		write!(writer, "{}", tc.collect_struct::<Self>())
-	}
-
-	fn is_simple() -> bool {
-		false
-	}
-
-	fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		write!(writer, "{}(", tc.collect_struct::<Self>())?;
-		address::solidity_default(writer, tc)?;
-		write!(writer, ",")?;
-		uint256::solidity_default(writer, tc)?;
-		write!(writer, ")")
-	}
-}
-
-impl StructCollect for EthCrossAccount {
-	fn name() -> String {
-		"EthCrossAccount".into()
-	}
-
-	fn declaration() -> String {
-		let mut str = String::new();
-		writeln!(str, "/// @dev Cross account struct").unwrap();
-		writeln!(str, "struct {} {{", Self::name()).unwrap();
-		writeln!(str, "\taddress eth;").unwrap();
-		writeln!(str, "\tuint256 sub;").unwrap();
-		writeln!(str, "}}").unwrap();
-		str
-	}
-}
-
-impl StructCollect for Property {
-	fn name() -> String {
-		"Property".into()
-	}
-
-	fn declaration() -> String {
-		let mut str = String::new();
-		writeln!(str, "/// @dev Property struct").unwrap();
-		writeln!(str, "struct {} {{", Self::name()).unwrap();
-		writeln!(str, "\tstring key;").unwrap();
-		writeln!(str, "\tbytes value;").unwrap();
-		writeln!(str, "}}").unwrap();
-		str
-	}
-}
-
-impl SolidityTypeName for Property {
-	fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		write!(writer, "{}", tc.collect_struct::<Self>())
-	}
-
-	fn is_simple() -> bool {
-		false
-	}
-
-	fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		write!(writer, "{}(", tc.collect_struct::<Self>())?;
-		address::solidity_default(writer, tc)?;
-		write!(writer, ",")?;
-		uint256::solidity_default(writer, tc)?;
-		write!(writer, ")")
-	}
-}
-
-impl SolidityTupleType for Property {
-	fn names(tc: &TypeCollector) -> Vec<string> {
-		let mut collected = Vec::with_capacity(Self::len());
-		{
-			let mut out = string::new();
-			string::solidity_name(&mut out, tc).expect("no fmt error");
-			collected.push(out);
-		}
-		{
-			let mut out = string::new();
-			bytes::solidity_name(&mut out, tc).expect("no fmt error");
-			collected.push(out);
-		}
-		collected
-	}
-
-	fn len() -> usize {
-		2
-	}
-}
-
-pub trait SolidityTupleType {
-	fn names(tc: &TypeCollector) -> Vec<String>;
-	fn len() -> usize;
-}
-
-macro_rules! count {
-    () => (0usize);
-    ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
-}
-
-macro_rules! impl_tuples {
-	($($ident:ident)+) => {
-		impl<$($ident),+> sealed::CanBePlacedInVec for ($($ident,)+) {}
-		impl<$($ident: SolidityTypeName + 'static),+> SolidityTupleType for ($($ident,)+) {
-			fn names(tc: &TypeCollector) -> Vec<string> {
-				let mut collected = Vec::with_capacity(Self::len());
-				$({
-					let mut out = string::new();
-					$ident::solidity_name(&mut out, tc).expect("no fmt error");
-					collected.push(out);
-				})*;
-				collected
-			}
-
-			fn len() -> usize {
-				count!($($ident)*)
-			}
-		}
-		impl<$($ident: SolidityTypeName + 'static),+> SolidityTypeName for ($($ident,)+) {
-			fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-				write!(writer, "{}", tc.collect_tuple::<Self>())
-			}
-			fn is_simple() -> bool {
-				false
-			}
-			#[allow(unused_assignments)]
-			fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-				write!(writer, "{}(", tc.collect_tuple::<Self>())?;
-				let mut first = true;
-				$(
-					if !first {
-						write!(writer, ",")?;
-					} else {
-						first = false;
-					}
-					<$ident>::solidity_default(writer, tc)?;
-				)*
-				write!(writer, ")")
-			}
-		}
-	};
-}
-
-impl_tuples! {A}
-impl_tuples! {A B}
-impl_tuples! {A B C}
-impl_tuples! {A B C D}
-impl_tuples! {A B C D E}
-impl_tuples! {A B C D E F}
-impl_tuples! {A B C D E F G}
-impl_tuples! {A B C D E F G H}
-impl_tuples! {A B C D E F G H I}
-impl_tuples! {A B C D E F G H I J}
-
-pub trait SolidityArguments {
-	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
-	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result;
-	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
-	fn is_empty(&self) -> bool {
-		self.len() == 0
-	}
-	fn len(&self) -> usize;
-}
-
-#[derive(Default)]
-pub struct UnnamedArgument<T>(PhantomData<*const T>);
-
-impl<T: SolidityTypeName> SolidityArguments for UnnamedArgument<T> {
-	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		if !T::is_void() {
-			T::solidity_name(writer, tc)?;
-			if !T::is_simple() {
-				write!(writer, " memory")?;
-			}
-			Ok(())
-		} else {
-			Ok(())
-		}
-	}
-	fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {
-		Ok(())
-	}
-	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		T::solidity_default(writer, tc)
-	}
-	fn len(&self) -> usize {
-		if T::is_void() {
-			0
-		} else {
-			1
-		}
-	}
-}
-
-pub struct NamedArgument<T>(&'static str, PhantomData<*const T>);
-
-impl<T> NamedArgument<T> {
-	pub fn new(name: &'static str) -> Self {
-		Self(name, Default::default())
-	}
-}
-
-impl<T: SolidityTypeName> SolidityArguments for NamedArgument<T> {
-	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		if !T::is_void() {
-			T::solidity_name(writer, tc)?;
-			if !T::is_simple() {
-				write!(writer, " memory")?;
-			}
-			write!(writer, " {}", self.0)
-		} else {
-			Ok(())
-		}
-	}
-	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {
-		writeln!(writer, "\t{prefix}\t{};", self.0)
-	}
-	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		T::solidity_default(writer, tc)
-	}
-	fn len(&self) -> usize {
-		if T::is_void() {
-			0
-		} else {
-			1
-		}
-	}
-}
-
-pub struct SolidityEventArgument<T>(pub bool, &'static str, PhantomData<*const T>);
-
-impl<T> SolidityEventArgument<T> {
-	pub fn new(indexed: bool, name: &'static str) -> Self {
-		Self(indexed, name, Default::default())
-	}
-}
-
-impl<T: SolidityTypeName> SolidityArguments for SolidityEventArgument<T> {
-	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		if !T::is_void() {
-			T::solidity_name(writer, tc)?;
-			if self.0 {
-				write!(writer, " indexed")?;
-			}
-			write!(writer, " {}", self.1)
-		} else {
-			Ok(())
-		}
-	}
-	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {
-		writeln!(writer, "\t{prefix}\t{};", self.1)
-	}
-	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		T::solidity_default(writer, tc)
-	}
-	fn len(&self) -> usize {
-		if T::is_void() {
-			0
-		} else {
-			1
-		}
-	}
-}
-
-impl SolidityArguments for () {
-	fn solidity_name(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
-		Ok(())
-	}
-	fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {
-		Ok(())
-	}
-	fn solidity_default(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
-		Ok(())
-	}
-	fn len(&self) -> usize {
-		0
-	}
-}
-
-#[impl_for_tuples(1, 12)]
-impl SolidityArguments for Tuple {
-	for_tuples!( where #( Tuple: SolidityArguments ),* );
-
-	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		let mut first = true;
-		for_tuples!( #(
-            if !Tuple.is_empty() {
-                if !first {
-                    write!(writer, ", ")?;
-                }
-                first = false;
-                Tuple.solidity_name(writer, tc)?;
-            }
-        )* );
-		Ok(())
-	}
-	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {
-		for_tuples!( #(
-            Tuple.solidity_get(prefix, writer)?;
-        )* );
-		Ok(())
-	}
-	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
-		if self.is_empty() {
-			Ok(())
-		} else if self.len() == 1 {
-			for_tuples!( #(
-				Tuple.solidity_default(writer, tc)?;
-			)* );
-			Ok(())
-		} else {
-			write!(writer, "(")?;
-			let mut first = true;
-			for_tuples!( #(
-				if !Tuple.is_empty() {
-					if !first {
-						write!(writer, ", ")?;
-					}
-					first = false;
-					Tuple.solidity_default(writer, tc)?;
-				}
-			)* );
-			write!(writer, ")")?;
-			Ok(())
-		}
-	}
-	fn len(&self) -> usize {
-		for_tuples!( #( Tuple.len() )+* )
-	}
-}
-
-pub trait SolidityFunctions {
-	fn solidity_name(
-		&self,
-		is_impl: bool,
-		writer: &mut impl fmt::Write,
-		tc: &TypeCollector,
-	) -> fmt::Result;
-}
-
-pub enum SolidityMutability {
-	Pure,
-	View,
-	Mutable,
-}
-pub struct SolidityFunction<A, R> {
-	pub docs: &'static [&'static str],
-	pub selector: u32,
-	pub hide: bool,
-	pub custom_signature: SignatureUnit,
-	pub name: &'static str,
-	pub args: A,
-	pub result: R,
-	pub mutability: SolidityMutability,
-	pub is_payable: bool,
-}
-impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {
-	fn solidity_name(
-		&self,
-		is_impl: bool,
-		writer: &mut impl fmt::Write,
-		tc: &TypeCollector,
-	) -> fmt::Result {
-		let hide_comment = self.hide.then(|| "// ").unwrap_or("");
-		for doc in self.docs {
-			writeln!(writer, "\t{hide_comment}///{}", doc)?;
-		}
-		writeln!(
-			writer,
-			"\t{hide_comment}/// @dev EVM selector for this function is: 0x{:0>8x},",
-			self.selector
-		)?;
-		writeln!(
-			writer,
-			"\t{hide_comment}///  or in textual repr: {}",
-			self.custom_signature.as_str().expect("bad utf-8")
-		)?;
-		write!(writer, "\t{hide_comment}function {}(", self.name)?;
-		self.args.solidity_name(writer, tc)?;
-		write!(writer, ")")?;
-		if is_impl {
-			write!(writer, " public")?;
-		} else {
-			write!(writer, " external")?;
-		}
-		match &self.mutability {
-			SolidityMutability::Pure => write!(writer, " pure")?,
-			SolidityMutability::View => write!(writer, " view")?,
-			SolidityMutability::Mutable => {}
-		}
-		if self.is_payable {
-			write!(writer, " payable")?;
-		}
-		if !self.result.is_empty() {
-			write!(writer, " returns (")?;
-			self.result.solidity_name(writer, tc)?;
-			write!(writer, ")")?;
-		}
-		if is_impl {
-			writeln!(writer, " {{")?;
-			writeln!(writer, "\t{hide_comment}\trequire(false, stub_error);")?;
-			self.args.solidity_get(hide_comment, writer)?;
-			match &self.mutability {
-				SolidityMutability::Pure => {}
-				SolidityMutability::View => writeln!(writer, "\t{hide_comment}\tdummy;")?,
-				SolidityMutability::Mutable => writeln!(writer, "\t{hide_comment}\tdummy = 0;")?,
-			}
-			if !self.result.is_empty() {
-				write!(writer, "\t{hide_comment}\treturn ")?;
-				self.result.solidity_default(writer, tc)?;
-				writeln!(writer, ";")?;
-			}
-			writeln!(writer, "\t{hide_comment}}}")?;
-		} else {
-			writeln!(writer, ";")?;
-		}
-		if self.hide {
-			writeln!(writer, "// FORMATTING: FORCE NEWLINE")?;
-		}
-		Ok(())
-	}
-}
-
-#[impl_for_tuples(0, 48)]
-impl SolidityFunctions for Tuple {
-	for_tuples!( where #( Tuple: SolidityFunctions ),* );
-
-	fn solidity_name(
-		&self,
-		is_impl: bool,
-		writer: &mut impl fmt::Write,
-		tc: &TypeCollector,
-	) -> fmt::Result {
-		let mut first = false;
-		for_tuples!( #(
-            Tuple.solidity_name(is_impl, writer, tc)?;
-        )* );
-		Ok(())
-	}
-}
-
-pub struct SolidityInterface<F: SolidityFunctions> {
-	pub docs: &'static [&'static str],
-	pub selector: bytes4,
-	pub name: &'static str,
-	pub is: &'static [&'static str],
-	pub functions: F,
-}
-
-impl<F: SolidityFunctions> SolidityInterface<F> {
-	pub fn format(
-		&self,
-		is_impl: bool,
-		out: &mut impl fmt::Write,
-		tc: &TypeCollector,
-	) -> fmt::Result {
-		const ZERO_BYTES: [u8; 4] = [0; 4];
-		for doc in self.docs {
-			writeln!(out, "///{}", doc)?;
-		}
-		if self.selector != ZERO_BYTES {
-			writeln!(
-				out,
-				"/// @dev the ERC-165 identifier for this interface is 0x{:0>8x}",
-				u32::from_be_bytes(self.selector)
-			)?;
-		}
-		if is_impl {
-			write!(out, "contract ")?;
-		} else {
-			write!(out, "interface ")?;
-		}
-		write!(out, "{}", self.name)?;
-		if !self.is.is_empty() {
-			write!(out, " is")?;
-			for (i, n) in self.is.iter().enumerate() {
-				if i != 0 {
-					write!(out, ",")?;
-				}
-				write!(out, " {}", n)?;
-			}
-		}
-		writeln!(out, " {{")?;
-		self.functions.solidity_name(is_impl, out, tc)?;
-		writeln!(out, "}}")?;
-		Ok(())
-	}
-}
-
-pub struct SolidityEvent<A> {
-	pub name: &'static str,
-	pub args: A,
-}
-
-impl<A: SolidityArguments> SolidityFunctions for SolidityEvent<A> {
-	fn solidity_name(
-		&self,
-		_is_impl: bool,
-		writer: &mut impl fmt::Write,
-		tc: &TypeCollector,
-	) -> fmt::Result {
-		write!(writer, "\tevent {}(", self.name)?;
-		self.args.solidity_name(writer, tc)?;
-		writeln!(writer, ");")
-	}
-}
addedcrates/evm-coder/src/solidity/impls.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/src/solidity/impls.rs
@@ -0,0 +1,190 @@
+use super::{TypeCollector, SolidityTypeName, SolidityType, StructCollect};
+use crate::{sealed, types::*};
+use core::fmt;
+use primitive_types::{U256, H160};
+
+macro_rules! solidity_type_name {
+    ($($ty:ty => $name:literal $simple:literal = $default:literal),* $(,)?) => {
+        $(
+            impl SolidityTypeName for $ty {
+                fn solidity_name(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {
+                    write!(writer, $name)
+                }
+				fn is_simple() -> bool {
+					$simple
+				}
+				fn solidity_default(writer: &mut impl core::fmt::Write, _tc: &TypeCollector) -> core::fmt::Result {
+					write!(writer, $default)
+				}
+            }
+
+			impl StructCollect for $ty {
+				fn name() -> String {
+					$name.to_string()
+				}
+
+				fn declaration() -> String {
+					String::default()
+				}
+			}
+        )*
+    };
+}
+
+solidity_type_name! {
+	u8 => "uint8" true = "0",
+	u32 => "uint32" true = "0",
+	u64 => "uint64" true = "0",
+	u128 => "uint128" true = "0",
+	U256 => "uint256" true = "0",
+	bytes4 => "bytes4" true = "bytes4(0)",
+	H160 => "address" true = "0x0000000000000000000000000000000000000000",
+	string => "string" false = "\"\"",
+	bytes => "bytes" false = "hex\"\"",
+	bool => "bool" true = "false",
+}
+
+impl SolidityTypeName for void {
+	fn solidity_name(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
+		Ok(())
+	}
+	fn is_simple() -> bool {
+		true
+	}
+	fn solidity_default(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
+		Ok(())
+	}
+	fn is_void() -> bool {
+		true
+	}
+}
+
+impl<T: SolidityTypeName + sealed::CanBePlacedInVec> SolidityTypeName for Vec<T> {
+	fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		T::solidity_name(writer, tc)?;
+		write!(writer, "[]")
+	}
+	fn is_simple() -> bool {
+		false
+	}
+	fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		write!(writer, "new ")?;
+		T::solidity_name(writer, tc)?;
+		write!(writer, "[](0)")
+	}
+}
+
+macro_rules! count {
+    () => (0usize);
+    ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
+}
+
+macro_rules! impl_tuples {
+	($($ident:ident)+) => {
+		impl<$($ident: SolidityTypeName + 'static),+> SolidityType for ($($ident,)+) {
+			fn names(tc: &TypeCollector) -> Vec<string> {
+				let mut collected = Vec::with_capacity(Self::len());
+				$({
+					let mut out = string::new();
+					$ident::solidity_name(&mut out, tc).expect("no fmt error");
+					collected.push(out);
+				})*;
+				collected
+			}
+
+			fn len() -> usize {
+				count!($($ident)*)
+			}
+		}
+		impl<$($ident: SolidityTypeName + 'static),+> SolidityTypeName for ($($ident,)+) {
+			fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+				write!(writer, "{}", tc.collect_tuple::<Self>())
+			}
+			fn is_simple() -> bool {
+				false
+			}
+			#[allow(unused_assignments)]
+			fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+				write!(writer, "{}(", tc.collect_tuple::<Self>())?;
+				let mut first = true;
+				$(
+					if !first {
+						write!(writer, ",")?;
+					} else {
+						first = false;
+					}
+					<$ident>::solidity_default(writer, tc)?;
+				)*
+				write!(writer, ")")
+			}
+		}
+	};
+}
+
+impl_tuples! {A}
+impl_tuples! {A B}
+impl_tuples! {A B C}
+impl_tuples! {A B C D}
+impl_tuples! {A B C D E}
+impl_tuples! {A B C D E F}
+impl_tuples! {A B C D E F G}
+impl_tuples! {A B C D E F G H}
+impl_tuples! {A B C D E F G H I}
+impl_tuples! {A B C D E F G H I J}
+
+impl StructCollect for Property {
+	fn name() -> String {
+		"Property".into()
+	}
+
+	fn declaration() -> String {
+		use std::fmt::Write;
+
+		let mut str = String::new();
+		writeln!(str, "/// @dev Property struct").unwrap();
+		writeln!(str, "struct {} {{", Self::name()).unwrap();
+		writeln!(str, "\tstring key;").unwrap();
+		writeln!(str, "\tbytes value;").unwrap();
+		writeln!(str, "}}").unwrap();
+		str
+	}
+}
+
+impl SolidityTypeName for Property {
+	fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		write!(writer, "{}", tc.collect_struct::<Self>())
+	}
+
+	fn is_simple() -> bool {
+		false
+	}
+
+	fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		write!(writer, "{}(", tc.collect_struct::<Self>())?;
+		address::solidity_default(writer, tc)?;
+		write!(writer, ",")?;
+		uint256::solidity_default(writer, tc)?;
+		write!(writer, ")")
+	}
+}
+
+impl SolidityType for Property {
+	fn names(tc: &TypeCollector) -> Vec<string> {
+		let mut collected = Vec::with_capacity(Self::len());
+		{
+			let mut out = string::new();
+			string::solidity_name(&mut out, tc).expect("no fmt error");
+			collected.push(out);
+		}
+		{
+			let mut out = string::new();
+			bytes::solidity_name(&mut out, tc).expect("no fmt error");
+			collected.push(out);
+		}
+		collected
+	}
+
+	fn len() -> usize {
+		2
+	}
+}
addedcrates/evm-coder/src/solidity/mod.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/src/solidity/mod.rs
@@ -0,0 +1,421 @@
+// 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/>.
+
+//! Implementation detail of [`crate::solidity_interface`] macro code-generation.
+//! You should not rely on any public item from this module, as it is only intended to be used
+//! by procedural macro, API and output format may be changed at any time.
+//!
+//! Purpose of this module is to receive solidity contract definition in module-specified
+//! format, and then output string, representing interface of this contract in solidity language
+
+mod traits;
+pub use traits::*;
+mod impls;
+
+#[cfg(not(feature = "std"))]
+use alloc::{string::String, vec::Vec, collections::BTreeMap, format};
+#[cfg(feature = "std")]
+use std::collections::BTreeMap;
+use core::{
+	fmt::{self, Write},
+	marker::PhantomData,
+	cell::{Cell, RefCell},
+	cmp::Reverse,
+};
+use impl_trait_for_tuples::impl_for_tuples;
+use crate::{types::*, custom_signature::SignatureUnit};
+
+#[derive(Default)]
+pub struct TypeCollector {
+	/// Code => id
+	/// id ordering is required to perform topo-sort on the resulting data
+	structs: RefCell<BTreeMap<string, usize>>,
+	anonymous: RefCell<BTreeMap<Vec<string>, usize>>,
+	id: Cell<usize>,
+}
+impl TypeCollector {
+	pub fn new() -> Self {
+		Self::default()
+	}
+	pub fn collect(&self, item: string) {
+		let id = self.next_id();
+		self.structs.borrow_mut().insert(item, id);
+	}
+	pub fn next_id(&self) -> usize {
+		let v = self.id.get();
+		self.id.set(v + 1);
+		v
+	}
+	pub fn collect_tuple<T: SolidityType>(&self) -> String {
+		let names = T::names(self);
+		if let Some(id) = self.anonymous.borrow().get(&names).cloned() {
+			return format!("Tuple{}", id);
+		}
+		let id = self.next_id();
+		let mut str = String::new();
+		writeln!(str, "/// @dev anonymous struct").unwrap();
+		writeln!(str, "struct Tuple{} {{", id).unwrap();
+		for (i, name) in names.iter().enumerate() {
+			writeln!(str, "\t{} field_{};", name, i).unwrap();
+		}
+		writeln!(str, "}}").unwrap();
+		self.collect(str);
+		self.anonymous.borrow_mut().insert(names, id);
+		format!("Tuple{}", id)
+	}
+	pub fn collect_struct<T: StructCollect>(&self) -> String {
+		self.collect(<T as StructCollect>::declaration());
+		<T as StructCollect>::name()
+	}
+	pub fn finish(self) -> Vec<string> {
+		let mut data = self.structs.into_inner().into_iter().collect::<Vec<_>>();
+		data.sort_by_key(|(_, id)| Reverse(*id));
+		data.into_iter().map(|(code, _)| code).collect()
+	}
+}
+#[derive(Default)]
+pub struct UnnamedArgument<T>(PhantomData<*const T>);
+
+impl<T: SolidityTypeName> SolidityArguments for UnnamedArgument<T> {
+	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		if !T::is_void() {
+			T::solidity_name(writer, tc)?;
+			if !T::is_simple() {
+				write!(writer, " memory")?;
+			}
+			Ok(())
+		} else {
+			Ok(())
+		}
+	}
+	fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {
+		Ok(())
+	}
+	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		T::solidity_default(writer, tc)
+	}
+	fn len(&self) -> usize {
+		if T::is_void() {
+			0
+		} else {
+			1
+		}
+	}
+}
+
+pub struct NamedArgument<T>(&'static str, PhantomData<*const T>);
+
+impl<T> NamedArgument<T> {
+	pub fn new(name: &'static str) -> Self {
+		Self(name, Default::default())
+	}
+}
+
+impl<T: SolidityTypeName> SolidityArguments for NamedArgument<T> {
+	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		if !T::is_void() {
+			T::solidity_name(writer, tc)?;
+			if !T::is_simple() {
+				write!(writer, " memory")?;
+			}
+			write!(writer, " {}", self.0)
+		} else {
+			Ok(())
+		}
+	}
+	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {
+		writeln!(writer, "\t{prefix}\t{};", self.0)
+	}
+	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		T::solidity_default(writer, tc)
+	}
+	fn len(&self) -> usize {
+		if T::is_void() {
+			0
+		} else {
+			1
+		}
+	}
+}
+
+pub struct SolidityEventArgument<T>(pub bool, &'static str, PhantomData<*const T>);
+
+impl<T> SolidityEventArgument<T> {
+	pub fn new(indexed: bool, name: &'static str) -> Self {
+		Self(indexed, name, Default::default())
+	}
+}
+
+impl<T: SolidityTypeName> SolidityArguments for SolidityEventArgument<T> {
+	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		if !T::is_void() {
+			T::solidity_name(writer, tc)?;
+			if self.0 {
+				write!(writer, " indexed")?;
+			}
+			write!(writer, " {}", self.1)
+		} else {
+			Ok(())
+		}
+	}
+	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {
+		writeln!(writer, "\t{prefix}\t{};", self.1)
+	}
+	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		T::solidity_default(writer, tc)
+	}
+	fn len(&self) -> usize {
+		if T::is_void() {
+			0
+		} else {
+			1
+		}
+	}
+}
+
+impl SolidityArguments for () {
+	fn solidity_name(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
+		Ok(())
+	}
+	fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {
+		Ok(())
+	}
+	fn solidity_default(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
+		Ok(())
+	}
+	fn len(&self) -> usize {
+		0
+	}
+}
+
+#[impl_for_tuples(1, 12)]
+impl SolidityArguments for Tuple {
+	for_tuples!( where #( Tuple: SolidityArguments ),* );
+
+	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		let mut first = true;
+		for_tuples!( #(
+            if !Tuple.is_empty() {
+                if !first {
+                    write!(writer, ", ")?;
+                }
+                first = false;
+                Tuple.solidity_name(writer, tc)?;
+            }
+        )* );
+		Ok(())
+	}
+	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {
+		for_tuples!( #(
+            Tuple.solidity_get(prefix, writer)?;
+        )* );
+		Ok(())
+	}
+	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {
+		if self.is_empty() {
+			Ok(())
+		} else if self.len() == 1 {
+			for_tuples!( #(
+				Tuple.solidity_default(writer, tc)?;
+			)* );
+			Ok(())
+		} else {
+			write!(writer, "(")?;
+			let mut first = true;
+			for_tuples!( #(
+				if !Tuple.is_empty() {
+					if !first {
+						write!(writer, ", ")?;
+					}
+					first = false;
+					Tuple.solidity_default(writer, tc)?;
+				}
+			)* );
+			write!(writer, ")")?;
+			Ok(())
+		}
+	}
+	fn len(&self) -> usize {
+		for_tuples!( #( Tuple.len() )+* )
+	}
+}
+
+pub enum SolidityMutability {
+	Pure,
+	View,
+	Mutable,
+}
+pub struct SolidityFunction<A, R> {
+	pub docs: &'static [&'static str],
+	pub selector: u32,
+	pub hide: bool,
+	pub custom_signature: SignatureUnit,
+	pub name: &'static str,
+	pub args: A,
+	pub result: R,
+	pub mutability: SolidityMutability,
+	pub is_payable: bool,
+}
+impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {
+	fn solidity_name(
+		&self,
+		is_impl: bool,
+		writer: &mut impl fmt::Write,
+		tc: &TypeCollector,
+	) -> fmt::Result {
+		let hide_comment = self.hide.then_some("// ").unwrap_or("");
+		for doc in self.docs {
+			writeln!(writer, "\t{hide_comment}///{}", doc)?;
+		}
+		writeln!(
+			writer,
+			"\t{hide_comment}/// @dev EVM selector for this function is: 0x{:0>8x},",
+			self.selector
+		)?;
+		writeln!(
+			writer,
+			"\t{hide_comment}///  or in textual repr: {}",
+			self.custom_signature.as_str().expect("bad utf-8")
+		)?;
+		write!(writer, "\t{hide_comment}function {}(", self.name)?;
+		self.args.solidity_name(writer, tc)?;
+		write!(writer, ")")?;
+		if is_impl {
+			write!(writer, " public")?;
+		} else {
+			write!(writer, " external")?;
+		}
+		match &self.mutability {
+			SolidityMutability::Pure => write!(writer, " pure")?,
+			SolidityMutability::View => write!(writer, " view")?,
+			SolidityMutability::Mutable => {}
+		}
+		if self.is_payable {
+			write!(writer, " payable")?;
+		}
+		if !self.result.is_empty() {
+			write!(writer, " returns (")?;
+			self.result.solidity_name(writer, tc)?;
+			write!(writer, ")")?;
+		}
+		if is_impl {
+			writeln!(writer, " {{")?;
+			writeln!(writer, "\t{hide_comment}\trequire(false, stub_error);")?;
+			self.args.solidity_get(hide_comment, writer)?;
+			match &self.mutability {
+				SolidityMutability::Pure => {}
+				SolidityMutability::View => writeln!(writer, "\t{hide_comment}\tdummy;")?,
+				SolidityMutability::Mutable => writeln!(writer, "\t{hide_comment}\tdummy = 0;")?,
+			}
+			if !self.result.is_empty() {
+				write!(writer, "\t{hide_comment}\treturn ")?;
+				self.result.solidity_default(writer, tc)?;
+				writeln!(writer, ";")?;
+			}
+			writeln!(writer, "\t{hide_comment}}}")?;
+		} else {
+			writeln!(writer, ";")?;
+		}
+		if self.hide {
+			writeln!(writer, "// FORMATTING: FORCE NEWLINE")?;
+		}
+		Ok(())
+	}
+}
+
+#[impl_for_tuples(0, 48)]
+impl SolidityFunctions for Tuple {
+	for_tuples!( where #( Tuple: SolidityFunctions ),* );
+
+	fn solidity_name(
+		&self,
+		is_impl: bool,
+		writer: &mut impl fmt::Write,
+		tc: &TypeCollector,
+	) -> fmt::Result {
+		let mut first = false;
+		for_tuples!( #(
+            Tuple.solidity_name(is_impl, writer, tc)?;
+        )* );
+		Ok(())
+	}
+}
+
+pub struct SolidityInterface<F: SolidityFunctions> {
+	pub docs: &'static [&'static str],
+	pub selector: bytes4,
+	pub name: &'static str,
+	pub is: &'static [&'static str],
+	pub functions: F,
+}
+
+impl<F: SolidityFunctions> SolidityInterface<F> {
+	pub fn format(
+		&self,
+		is_impl: bool,
+		out: &mut impl fmt::Write,
+		tc: &TypeCollector,
+	) -> fmt::Result {
+		const ZERO_BYTES: [u8; 4] = [0; 4];
+		for doc in self.docs {
+			writeln!(out, "///{}", doc)?;
+		}
+		if self.selector != ZERO_BYTES {
+			writeln!(
+				out,
+				"/// @dev the ERC-165 identifier for this interface is 0x{:0>8x}",
+				u32::from_be_bytes(self.selector)
+			)?;
+		}
+		if is_impl {
+			write!(out, "contract ")?;
+		} else {
+			write!(out, "interface ")?;
+		}
+		write!(out, "{}", self.name)?;
+		if !self.is.is_empty() {
+			write!(out, " is")?;
+			for (i, n) in self.is.iter().enumerate() {
+				if i != 0 {
+					write!(out, ",")?;
+				}
+				write!(out, " {}", n)?;
+			}
+		}
+		writeln!(out, " {{")?;
+		self.functions.solidity_name(is_impl, out, tc)?;
+		writeln!(out, "}}")?;
+		Ok(())
+	}
+}
+
+pub struct SolidityEvent<A> {
+	pub name: &'static str,
+	pub args: A,
+}
+
+impl<A: SolidityArguments> SolidityFunctions for SolidityEvent<A> {
+	fn solidity_name(
+		&self,
+		_is_impl: bool,
+		writer: &mut impl fmt::Write,
+		tc: &TypeCollector,
+	) -> fmt::Result {
+		write!(writer, "\tevent {}(", self.name)?;
+		self.args.solidity_name(writer, tc)?;
+		writeln!(writer, ");")
+	}
+}
addedcrates/evm-coder/src/solidity/traits.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/src/solidity/traits.rs
@@ -0,0 +1,48 @@
+use super::TypeCollector;
+use core::fmt;
+
+pub trait StructCollect: 'static {
+	/// Structure name.
+	fn name() -> String;
+	/// Structure declaration.
+	fn declaration() -> String;
+}
+
+pub trait SolidityEnum: 'static {
+	fn solidity_option(&self) -> &str;
+}
+
+pub trait SolidityTypeName: 'static {
+	fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
+	/// "simple" types are stored inline, no `memory` modifier should be used in solidity
+	fn is_simple() -> bool;
+	fn solidity_default(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
+	/// Specialization
+	fn is_void() -> bool {
+		false
+	}
+}
+
+pub trait SolidityType {
+	fn names(tc: &TypeCollector) -> Vec<String>;
+	fn len() -> usize;
+}
+
+pub trait SolidityArguments {
+	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
+	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result;
+	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
+	fn is_empty(&self) -> bool {
+		self.len() == 0
+	}
+	fn len(&self) -> usize;
+}
+
+pub trait SolidityFunctions {
+	fn solidity_name(
+		&self,
+		is_impl: bool,
+		writer: &mut impl fmt::Write,
+		tc: &TypeCollector,
+	) -> fmt::Result;
+}
addedcrates/evm-coder/tests/abi_derive_generation.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/tests/abi_derive_generation.rs
@@ -0,0 +1,841 @@
+mod test_struct {
+	use evm_coder_procedural::AbiCoder;
+	use evm_coder::types::bytes;
+
+	#[test]
+	fn empty_struct() {
+		let t = trybuild::TestCases::new();
+		t.compile_fail("tests/build_failed/abi_derive_struct_generation.rs");
+	}
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TypeStruct1SimpleParam {
+		_a: u8,
+	}
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TypeStruct1DynamicParam {
+		_a: String,
+	}
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TypeStruct2SimpleParam {
+		_a: u8,
+		_b: u32,
+	}
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TypeStruct2DynamicParam {
+		_a: String,
+		_b: bytes,
+	}
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TypeStruct2MixedParam {
+		_a: u8,
+		_b: bytes,
+	}
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TypeStruct1DerivedSimpleParam {
+		_a: TypeStruct1SimpleParam,
+	}
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TypeStruct2DerivedSimpleParam {
+		_a: TypeStruct1SimpleParam,
+		_b: TypeStruct2SimpleParam,
+	}
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TypeStruct1DerivedDynamicParam {
+		_a: TypeStruct1DynamicParam,
+	}
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TypeStruct2DerivedDynamicParam {
+		_a: TypeStruct1DynamicParam,
+		_b: TypeStruct2DynamicParam,
+	}
+
+	/// Some docs
+	/// At multi
+	/// line
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TypeStruct3DerivedMixedParam {
+		/// Docs for A
+		/// multi
+		/// line
+		_a: TypeStruct1SimpleParam,
+		/// Docs for B
+		_b: TypeStruct2DynamicParam,
+		/// Docs for C
+		_c: TypeStruct2MixedParam,
+	}
+
+	#[test]
+	#[cfg(feature = "stubgen")]
+	fn struct_collect_type_struct3_derived_mixed_param() {
+		assert_eq!(
+			<TypeStruct3DerivedMixedParam as ::evm_coder::solidity::StructCollect>::name(),
+			"TypeStruct3DerivedMixedParam"
+		);
+		similar_asserts::assert_eq!(
+			<TypeStruct3DerivedMixedParam as ::evm_coder::solidity::StructCollect>::declaration(),
+			r#"/// @dev Some docs
+/// At multi
+/// line
+struct TypeStruct3DerivedMixedParam {
+	/// @dev Docs for A
+	/// multi
+	/// line
+	TypeStruct1SimpleParam _a;
+	/// @dev Docs for B
+	TypeStruct2DynamicParam _b;
+	/// @dev Docs for C
+	TypeStruct2MixedParam _c;
+}
+"#
+		);
+	}
+
+	#[test]
+	fn impl_abi_type_signature() {
+		assert_eq!(
+			<TypeStruct1SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			"(uint8)"
+		);
+		assert_eq!(
+			<TypeStruct1DynamicParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			"(string)"
+		);
+		assert_eq!(
+			<TypeStruct2SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			"(uint8,uint32)"
+		);
+		assert_eq!(
+			<TypeStruct2DynamicParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			"(string,bytes)"
+		);
+		assert_eq!(
+			<TypeStruct2MixedParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			"(uint8,bytes)"
+		);
+		assert_eq!(
+			<TypeStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			"((uint8))"
+		);
+		assert_eq!(
+			<TypeStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			"((uint8),(uint8,uint32))"
+		);
+		assert_eq!(
+			<TypeStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			"((string))"
+		);
+		assert_eq!(
+			<TypeStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			"((string),(string,bytes))"
+		);
+		assert_eq!(
+			<TypeStruct3DerivedMixedParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			"((uint8),(string,bytes),(uint8,bytes))"
+		);
+	}
+
+	#[test]
+	fn impl_abi_type_is_dynamic() {
+		assert_eq!(
+			<TypeStruct1SimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
+			false
+		);
+		assert_eq!(
+			<TypeStruct1DynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
+			true
+		);
+		assert_eq!(
+			<TypeStruct2SimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
+			false
+		);
+		assert_eq!(
+			<TypeStruct2DynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
+			true
+		);
+		assert_eq!(
+			<TypeStruct2MixedParam as evm_coder::abi::AbiType>::is_dynamic(),
+			true
+		);
+		assert_eq!(
+			<TypeStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
+			false
+		);
+		assert_eq!(
+			<TypeStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
+			false
+		);
+		assert_eq!(
+			<TypeStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
+			true
+		);
+		assert_eq!(
+			<TypeStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
+			true
+		);
+		assert_eq!(
+			<TypeStruct3DerivedMixedParam as evm_coder::abi::AbiType>::is_dynamic(),
+			true
+		);
+	}
+
+	#[test]
+	fn impl_abi_type_size() {
+		const ABI_ALIGNMENT: usize = 32;
+		assert_eq!(
+			<TypeStruct1SimpleParam as evm_coder::abi::AbiType>::size(),
+			ABI_ALIGNMENT
+		);
+		assert_eq!(
+			<TypeStruct1DynamicParam as evm_coder::abi::AbiType>::size(),
+			ABI_ALIGNMENT
+		);
+		assert_eq!(
+			<TypeStruct2SimpleParam as evm_coder::abi::AbiType>::size(),
+			ABI_ALIGNMENT * 2
+		);
+		assert_eq!(
+			<TypeStruct2DynamicParam as evm_coder::abi::AbiType>::size(),
+			ABI_ALIGNMENT * 2
+		);
+		assert_eq!(
+			<TypeStruct2MixedParam as evm_coder::abi::AbiType>::size(),
+			ABI_ALIGNMENT * 2
+		);
+		assert_eq!(
+			<TypeStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::size(),
+			ABI_ALIGNMENT
+		);
+		assert_eq!(
+			<TypeStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::size(),
+			ABI_ALIGNMENT * 3
+		);
+		assert_eq!(
+			<TypeStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::size(),
+			ABI_ALIGNMENT
+		);
+		assert_eq!(
+			<TypeStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::size(),
+			ABI_ALIGNMENT * 3
+		);
+		assert_eq!(
+			<TypeStruct3DerivedMixedParam as evm_coder::abi::AbiType>::size(),
+			ABI_ALIGNMENT * 5
+		);
+	}
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TupleStruct1SimpleParam(u8);
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TupleStruct1DynamicParam(String);
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TupleStruct2SimpleParam(u8, u32);
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TupleStruct2DynamicParam(String, bytes);
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TupleStruct2MixedParam(u8, bytes);
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TupleStruct1DerivedSimpleParam(TupleStruct1SimpleParam);
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TupleStruct2DerivedSimpleParam(TupleStruct1SimpleParam, TupleStruct2SimpleParam);
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TupleStruct1DerivedDynamicParam(TupleStruct1DynamicParam);
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TupleStruct2DerivedDynamicParam(TupleStruct1DynamicParam, TupleStruct2DynamicParam);
+
+	/// Some docs
+	/// At multi
+	/// line
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TupleStruct3DerivedMixedParam(
+		/// Docs for A
+		/// multi
+		/// line
+		TupleStruct1SimpleParam,
+		TupleStruct2DynamicParam,
+		/// Docs for C
+		TupleStruct2MixedParam,
+	);
+
+	#[test]
+	#[cfg(feature = "stubgen")]
+	fn struct_collect_tuple_struct3_derived_mixed_param() {
+		assert_eq!(
+			<TupleStruct3DerivedMixedParam as ::evm_coder::solidity::StructCollect>::name(),
+			"TupleStruct3DerivedMixedParam"
+		);
+		similar_asserts::assert_eq!(
+			<TupleStruct3DerivedMixedParam as ::evm_coder::solidity::StructCollect>::declaration(),
+			r#"/// @dev Some docs
+/// At multi
+/// line
+struct TupleStruct3DerivedMixedParam {
+	/// @dev Docs for A
+	/// multi
+	/// line
+	TupleStruct1SimpleParam field0;
+	TupleStruct2DynamicParam field1;
+	/// @dev Docs for C
+	TupleStruct2MixedParam field2;
+}
+"#
+		);
+	}
+
+	#[test]
+	fn impl_abi_type_signature_same_for_structs() {
+		assert_eq!(
+			<TypeStruct1SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			<TupleStruct1SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap()
+		);
+		assert_eq!(
+			<TypeStruct1DynamicParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			<TupleStruct1DynamicParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap()
+		);
+		assert_eq!(
+			<TypeStruct2SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			<TupleStruct2SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap()
+		);
+		assert_eq!(
+			<TypeStruct2DynamicParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			<TupleStruct2DynamicParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap()
+		);
+		assert_eq!(
+			<TypeStruct2MixedParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			<TupleStruct2MixedParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+		);
+		assert_eq!(
+			<TypeStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			<TupleStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+		);
+		assert_eq!(
+			<TypeStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			<TupleStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+		);
+		assert_eq!(
+			<TypeStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			<TupleStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+		);
+		assert_eq!(
+			<TypeStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			<TupleStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+		);
+		assert_eq!(
+			<TypeStruct3DerivedMixedParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			<TupleStruct3DerivedMixedParam as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+		);
+	}
+
+	#[test]
+	fn impl_abi_type_is_dynamic_same_for_structs() {
+		assert_eq!(
+			<TypeStruct1SimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
+			<TupleStruct1SimpleParam as evm_coder::abi::AbiType>::is_dynamic()
+		);
+		assert_eq!(
+			<TypeStruct1DynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
+			<TupleStruct1DynamicParam as evm_coder::abi::AbiType>::is_dynamic()
+		);
+		assert_eq!(
+			<TypeStruct2SimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
+			<TupleStruct2SimpleParam as evm_coder::abi::AbiType>::is_dynamic()
+		);
+		assert_eq!(
+			<TypeStruct2DynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
+			<TupleStruct2DynamicParam as evm_coder::abi::AbiType>::is_dynamic()
+		);
+		assert_eq!(
+			<TypeStruct2MixedParam as evm_coder::abi::AbiType>::is_dynamic(),
+			<TupleStruct2MixedParam as evm_coder::abi::AbiType>::is_dynamic()
+		);
+		assert_eq!(
+			<TypeStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
+			<TupleStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::is_dynamic()
+		);
+		assert_eq!(
+			<TypeStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::is_dynamic(),
+			<TupleStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::is_dynamic()
+		);
+		assert_eq!(
+			<TypeStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
+			<TupleStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::is_dynamic()
+		);
+		assert_eq!(
+			<TypeStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::is_dynamic(),
+			<TupleStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::is_dynamic()
+		);
+		assert_eq!(
+			<TypeStruct3DerivedMixedParam as evm_coder::abi::AbiType>::is_dynamic(),
+			<TupleStruct3DerivedMixedParam as evm_coder::abi::AbiType>::is_dynamic()
+		);
+	}
+
+	#[test]
+	fn impl_abi_type_size_same_for_structs() {
+		assert_eq!(
+			<TypeStruct1SimpleParam as evm_coder::abi::AbiType>::size(),
+			<TupleStruct1SimpleParam as evm_coder::abi::AbiType>::size()
+		);
+		assert_eq!(
+			<TypeStruct1DynamicParam as evm_coder::abi::AbiType>::size(),
+			<TupleStruct1DynamicParam as evm_coder::abi::AbiType>::size()
+		);
+		assert_eq!(
+			<TypeStruct2SimpleParam as evm_coder::abi::AbiType>::size(),
+			<TupleStruct2SimpleParam as evm_coder::abi::AbiType>::size()
+		);
+		assert_eq!(
+			<TypeStruct2DynamicParam as evm_coder::abi::AbiType>::size(),
+			<TupleStruct2DynamicParam as evm_coder::abi::AbiType>::size()
+		);
+		assert_eq!(
+			<TypeStruct2MixedParam as evm_coder::abi::AbiType>::size(),
+			<TupleStruct2MixedParam as evm_coder::abi::AbiType>::size()
+		);
+		assert_eq!(
+			<TypeStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::size(),
+			<TupleStruct1DerivedSimpleParam as evm_coder::abi::AbiType>::size()
+		);
+		assert_eq!(
+			<TypeStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::size(),
+			<TupleStruct2DerivedSimpleParam as evm_coder::abi::AbiType>::size()
+		);
+		assert_eq!(
+			<TypeStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::size(),
+			<TupleStruct1DerivedDynamicParam as evm_coder::abi::AbiType>::size()
+		);
+		assert_eq!(
+			<TypeStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::size(),
+			<TupleStruct2DerivedDynamicParam as evm_coder::abi::AbiType>::size()
+		);
+		assert_eq!(
+			<TypeStruct3DerivedMixedParam as evm_coder::abi::AbiType>::size(),
+			<TupleStruct3DerivedMixedParam as evm_coder::abi::AbiType>::size()
+		);
+	}
+
+	const FUNCTION_IDENTIFIER: u32 = 0xdeadbeef;
+
+	fn test_impl<Tuple, TupleStruct, TypeStruct>(
+		tuple_data: Tuple,
+		tuple_struct_data: TupleStruct,
+		type_struct_data: TypeStruct,
+	) where
+		TypeStruct: evm_coder::abi::AbiWrite
+			+ evm_coder::abi::AbiRead
+			+ std::cmp::PartialEq
+			+ std::fmt::Debug,
+		TupleStruct: evm_coder::abi::AbiWrite
+			+ evm_coder::abi::AbiRead
+			+ std::cmp::PartialEq
+			+ std::fmt::Debug,
+		Tuple: evm_coder::abi::AbiWrite
+			+ evm_coder::abi::AbiRead
+			+ std::cmp::PartialEq
+			+ std::fmt::Debug,
+	{
+		let encoded_type_struct = test_abi_write_impl(&type_struct_data);
+		let encoded_tuple_struct = test_abi_write_impl(&tuple_struct_data);
+		let encoded_tuple = test_abi_write_impl(&tuple_data);
+
+		similar_asserts::assert_eq!(encoded_tuple, encoded_type_struct);
+		similar_asserts::assert_eq!(encoded_tuple, encoded_tuple_struct);
+
+		{
+			let (_, mut decoder) = evm_coder::abi::AbiReader::new_call(&encoded_tuple).unwrap();
+			let restored_struct_data = <TypeStruct>::abi_read(&mut decoder).unwrap();
+			assert_eq!(restored_struct_data, type_struct_data);
+		}
+		{
+			let (_, mut decoder) = evm_coder::abi::AbiReader::new_call(&encoded_tuple).unwrap();
+			let restored_struct_data = <TupleStruct>::abi_read(&mut decoder).unwrap();
+			assert_eq!(restored_struct_data, tuple_struct_data);
+		}
+
+		{
+			let (_, mut decoder) =
+				evm_coder::abi::AbiReader::new_call(&encoded_type_struct).unwrap();
+			let restored_tuple_data = <Tuple>::abi_read(&mut decoder).unwrap();
+			assert_eq!(restored_tuple_data, tuple_data);
+		}
+		{
+			let (_, mut decoder) =
+				evm_coder::abi::AbiReader::new_call(&encoded_tuple_struct).unwrap();
+			let restored_tuple_data = <Tuple>::abi_read(&mut decoder).unwrap();
+			assert_eq!(restored_tuple_data, tuple_data);
+		}
+	}
+
+	fn test_abi_write_impl<A>(data: &A) -> Vec<u8>
+	where
+		A: evm_coder::abi::AbiWrite
+			+ evm_coder::abi::AbiRead
+			+ std::cmp::PartialEq
+			+ std::fmt::Debug,
+	{
+		let mut writer = evm_coder::abi::AbiWriter::new_call(FUNCTION_IDENTIFIER);
+		data.abi_write(&mut writer);
+		let encoded_tuple = writer.finish();
+		encoded_tuple
+	}
+
+	#[test]
+	fn codec_struct_1_simple() {
+		let _a = 0xff;
+		test_impl::<(u8,), TupleStruct1SimpleParam, TypeStruct1SimpleParam>(
+			(_a,),
+			TupleStruct1SimpleParam(_a),
+			TypeStruct1SimpleParam { _a },
+		);
+	}
+
+	#[test]
+	fn codec_struct_1_dynamic() {
+		let _a: String = "some string".into();
+		test_impl::<(String,), TupleStruct1DynamicParam, TypeStruct1DynamicParam>(
+			(_a.clone(),),
+			TupleStruct1DynamicParam(_a.clone()),
+			TypeStruct1DynamicParam { _a },
+		);
+	}
+
+	#[test]
+	fn codec_struct_1_derived_simple() {
+		let _a: u8 = 0xff;
+		test_impl::<((u8,),), TupleStruct1DerivedSimpleParam, TypeStruct1DerivedSimpleParam>(
+			((_a,),),
+			TupleStruct1DerivedSimpleParam(TupleStruct1SimpleParam(_a)),
+			TypeStruct1DerivedSimpleParam {
+				_a: TypeStruct1SimpleParam { _a },
+			},
+		);
+	}
+
+	#[test]
+	fn codec_struct_1_derived_dynamic() {
+		let _a: String = "some string".into();
+		test_impl::<((String,),), TupleStruct1DerivedDynamicParam, TypeStruct1DerivedDynamicParam>(
+			((_a.clone(),),),
+			TupleStruct1DerivedDynamicParam(TupleStruct1DynamicParam(_a.clone())),
+			TypeStruct1DerivedDynamicParam {
+				_a: TypeStruct1DynamicParam { _a },
+			},
+		);
+	}
+
+	#[test]
+	fn codec_struct_2_simple() {
+		let _a = 0xff;
+		let _b = 0xbeefbaba;
+		test_impl::<(u8, u32), TupleStruct2SimpleParam, TypeStruct2SimpleParam>(
+			(_a, _b),
+			TupleStruct2SimpleParam(_a, _b),
+			TypeStruct2SimpleParam { _a, _b },
+		);
+	}
+
+	#[test]
+	fn codec_struct_2_dynamic() {
+		let _a: String = "some string".into();
+		let _b: bytes = bytes(vec![0x11, 0x22, 0x33]);
+		test_impl::<(String, bytes), TupleStruct2DynamicParam, TypeStruct2DynamicParam>(
+			(_a.clone(), _b.clone()),
+			TupleStruct2DynamicParam(_a.clone(), _b.clone()),
+			TypeStruct2DynamicParam { _a, _b },
+		);
+	}
+
+	#[test]
+	fn codec_struct_2_mixed() {
+		let _a: u8 = 0xff;
+		let _b: bytes = bytes(vec![0x11, 0x22, 0x33]);
+		test_impl::<(u8, bytes), TupleStruct2MixedParam, TypeStruct2MixedParam>(
+			(_a.clone(), _b.clone()),
+			TupleStruct2MixedParam(_a.clone(), _b.clone()),
+			TypeStruct2MixedParam { _a, _b },
+		);
+	}
+
+	#[test]
+	fn codec_struct_2_derived_simple() {
+		let _a = 0xff;
+		let _b = 0xbeefbaba;
+		test_impl::<
+			((u8,), (u8, u32)),
+			TupleStruct2DerivedSimpleParam,
+			TypeStruct2DerivedSimpleParam,
+		>(
+			((_a,), (_a, _b)),
+			TupleStruct2DerivedSimpleParam(
+				TupleStruct1SimpleParam(_a),
+				TupleStruct2SimpleParam(_a, _b),
+			),
+			TypeStruct2DerivedSimpleParam {
+				_a: TypeStruct1SimpleParam { _a },
+				_b: TypeStruct2SimpleParam { _a, _b },
+			},
+		);
+	}
+
+	#[test]
+	fn codec_struct_2_derived_dynamic() {
+		let _a = "some string".to_string();
+		let _b = bytes(vec![0x11, 0x22, 0x33]);
+		test_impl::<
+			((String,), (String, bytes)),
+			TupleStruct2DerivedDynamicParam,
+			TypeStruct2DerivedDynamicParam,
+		>(
+			((_a.clone(),), (_a.clone(), _b.clone())),
+			TupleStruct2DerivedDynamicParam(
+				TupleStruct1DynamicParam(_a.clone()),
+				TupleStruct2DynamicParam(_a.clone(), _b.clone()),
+			),
+			TypeStruct2DerivedDynamicParam {
+				_a: TypeStruct1DynamicParam { _a: _a.clone() },
+				_b: TypeStruct2DynamicParam { _a, _b },
+			},
+		);
+	}
+
+	#[test]
+	fn codec_struct_3_derived_mixed() {
+		let int = 0xff;
+		let by = bytes(vec![0x11, 0x22, 0x33]);
+		let string = "some string".to_string();
+		test_impl::<
+			((u8,), (String, bytes), (u8, bytes)),
+			TupleStruct3DerivedMixedParam,
+			TypeStruct3DerivedMixedParam,
+		>(
+			((int,), (string.clone(), by.clone()), (int, by.clone())),
+			TupleStruct3DerivedMixedParam(
+				TupleStruct1SimpleParam(int),
+				TupleStruct2DynamicParam(string.clone(), by.clone()),
+				TupleStruct2MixedParam(int, by.clone()),
+			),
+			TypeStruct3DerivedMixedParam {
+				_a: TypeStruct1SimpleParam { _a: int },
+				_b: TypeStruct2DynamicParam {
+					_a: string.clone(),
+					_b: by.clone(),
+				},
+				_c: TypeStruct2MixedParam { _a: int, _b: by },
+			},
+		);
+	}
+
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TypeStruct2SimpleStruct1Simple {
+		_a: TypeStruct2SimpleParam,
+		_b: TypeStruct2SimpleParam,
+		_c: u8,
+	}
+	#[derive(AbiCoder, PartialEq, Debug)]
+	struct TupleStruct2SimpleStruct1Simple(TupleStruct2SimpleParam, TupleStruct2SimpleParam, u8);
+
+	#[test]
+	fn codec_struct_2_struct_simple_1_simple() {
+		let _a = 0xff;
+		let _b = 0xbeefbaba;
+		test_impl::<
+			((u8, u32), (u8, u32), u8),
+			TupleStruct2SimpleStruct1Simple,
+			TypeStruct2SimpleStruct1Simple,
+		>(
+			((_a, _b), (_a, _b), _a),
+			TupleStruct2SimpleStruct1Simple(
+				TupleStruct2SimpleParam(_a, _b),
+				TupleStruct2SimpleParam(_a, _b),
+				_a,
+			),
+			TypeStruct2SimpleStruct1Simple {
+				_a: TypeStruct2SimpleParam { _a, _b },
+				_b: TypeStruct2SimpleParam { _a, _b },
+				_c: _a,
+			},
+		);
+	}
+}
+
+mod test_enum {
+	use evm_coder::AbiCoder;
+
+	/// Some docs
+	/// At multi
+	/// line
+	#[derive(AbiCoder, Debug, PartialEq, Default)]
+	#[repr(u8)]
+	enum Color {
+		/// Docs for Red
+		/// multi
+		/// line
+		Red,
+		Green,
+		/// Docs for Blue
+		#[default]
+		Blue,
+	}
+
+	#[test]
+	fn empty() {}
+
+	#[test]
+	fn bad_enums() {
+		let t = trybuild::TestCases::new();
+		t.compile_fail("tests/build_failed/abi_derive_enum_generation.rs");
+	}
+
+	#[test]
+	fn impl_abi_type_signature_same_for_structs() {
+		assert_eq!(
+			<Color as evm_coder::abi::AbiType>::SIGNATURE
+				.as_str()
+				.unwrap(),
+			<u8 as evm_coder::abi::AbiType>::SIGNATURE.as_str().unwrap()
+		);
+	}
+
+	#[test]
+	fn impl_abi_type_is_dynamic_same_for_structs() {
+		assert_eq!(
+			<Color as evm_coder::abi::AbiType>::is_dynamic(),
+			<u8 as evm_coder::abi::AbiType>::is_dynamic()
+		);
+	}
+
+	#[test]
+	fn impl_abi_type_size_same_for_structs() {
+		assert_eq!(
+			<Color as evm_coder::abi::AbiType>::size(),
+			<u8 as evm_coder::abi::AbiType>::size()
+		);
+	}
+
+	#[test]
+	fn test_coder() {
+		const FUNCTION_IDENTIFIER: u32 = 0xdeadbeef;
+
+		let encoded_enum = {
+			let mut writer = evm_coder::abi::AbiWriter::new_call(FUNCTION_IDENTIFIER);
+			<Color as evm_coder::abi::AbiWrite>::abi_write(&Color::Green, &mut writer);
+			writer.finish()
+		};
+
+		let encoded_u8 = {
+			let mut writer = evm_coder::abi::AbiWriter::new_call(FUNCTION_IDENTIFIER);
+			<u8 as evm_coder::abi::AbiWrite>::abi_write(&(Color::Green as u8), &mut writer);
+			writer.finish()
+		};
+
+		similar_asserts::assert_eq!(encoded_enum, encoded_u8);
+
+		{
+			let (_, mut decoder) = evm_coder::abi::AbiReader::new_call(&encoded_enum).unwrap();
+			let restored_enum_data =
+				<Color as evm_coder::abi::AbiRead>::abi_read(&mut decoder).unwrap();
+			assert_eq!(restored_enum_data, Color::Green);
+		}
+	}
+
+	#[test]
+	#[cfg(feature = "stubgen")]
+	fn struct_collect_enum() {
+		assert_eq!(
+			<Color as ::evm_coder::solidity::StructCollect>::name(),
+			"Color"
+		);
+		similar_asserts::assert_eq!(
+			<Color as ::evm_coder::solidity::StructCollect>::declaration(),
+			r#"/// @dev Some docs
+/// At multi
+/// line
+enum Color {
+	/// @dev Docs for Red
+	/// multi
+	/// line
+	Red,
+	Green,
+	/// @dev Docs for Blue
+	Blue
+}
+"#
+		);
+	}
+}
addedcrates/evm-coder/tests/build_failed/abi_derive_enum_generation.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/tests/build_failed/abi_derive_enum_generation.rs
@@ -0,0 +1,36 @@
+use evm_coder_procedural::AbiCoder;
+
+#[derive(AbiCoder)]
+enum NonRepr {
+	A,
+	B,
+	C,
+}
+
+#[derive(AbiCoder)]
+#[repr(u32)]
+enum NonReprU8 {
+	A,
+	B,
+	C,
+}
+
+#[derive(AbiCoder)]
+#[repr(u8)]
+enum RustEnum {
+	A(u128),
+	B,
+	C,
+}
+
+#[derive(AbiCoder)]
+#[repr(u8)]
+enum WithExplicit {
+	A = 128,
+	B,
+	C,
+}
+
+fn main() {
+	assert!(false);
+}
addedcrates/evm-coder/tests/build_failed/abi_derive_enum_generation.stderrdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/tests/build_failed/abi_derive_enum_generation.stderr
@@ -0,0 +1,23 @@
+error: Enum is not "repr(u8)"
+ --> tests/build_failed/abi_derive_enum_generation.rs:4:6
+  |
+4 | enum NonRepr {
+  |      ^^^^^^^
+
+error: Enum is not "repr(u8)"
+  --> tests/build_failed/abi_derive_enum_generation.rs:11:8
+   |
+11 | #[repr(u32)]
+   |        ^^^
+
+error: Enumeration parameters should not have fields
+  --> tests/build_failed/abi_derive_enum_generation.rs:21:2
+   |
+21 |     A(u128),
+   |     ^
+
+error: Enumeration options should not have an explicit specified value
+  --> tests/build_failed/abi_derive_enum_generation.rs:29:2
+   |
+29 |     A = 128,
+   |     ^
addedcrates/evm-coder/tests/build_failed/abi_derive_struct_generation.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/tests/build_failed/abi_derive_struct_generation.rs
@@ -0,0 +1,11 @@
+use evm_coder_procedural::AbiCoder;
+
+#[derive(AbiCoder, PartialEq, Debug)]
+struct EmptyStruct {}
+
+#[derive(AbiCoder, PartialEq, Debug)]
+struct EmptyTupleStruct();
+
+fn main() {
+	assert!(false);
+}
addedcrates/evm-coder/tests/build_failed/abi_derive_struct_generation.stderrdiffbeforeafterboth
--- /dev/null
+++ b/crates/evm-coder/tests/build_failed/abi_derive_struct_generation.stderr
@@ -0,0 +1,11 @@
+error: Empty structs not supported
+ --> tests/build_failed/abi_derive_struct_generation.rs:4:8
+  |
+4 | struct EmptyStruct {}
+  |        ^^^^^^^^^^^
+
+error: Empty structs not supported
+ --> tests/build_failed/abi_derive_struct_generation.rs:7:8
+  |
+7 | struct EmptyTupleStruct();
+  |        ^^^^^^^^^^^^^^^^
modifiednode/cli/Cargo.tomldiffbeforeafterboth
--- a/node/cli/Cargo.toml
+++ b/node/cli/Cargo.toml
@@ -309,13 +309,13 @@
 jsonrpsee = { version = "0.15.1", features = ["server", "macros"] }
 tokio = { version = "1.19.2", features = ["time"] }
 
-fc-rpc-core = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fc-consensus = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fc-mapping-sync = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fc-rpc = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fc-db = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fp-rpc = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+fc-rpc-core = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fc-consensus = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fc-mapping-sync = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fc-rpc = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fc-db = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fp-rpc = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 
 unique-rpc = { default-features = false, path = "../rpc" }
 app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false }
@@ -335,3 +335,7 @@
     'quartz-runtime?/try-runtime',
     'opal-runtime?/try-runtime',
 ]
+sapphire-runtime = [
+    'opal-runtime',
+    'opal-runtime/become-sapphire',
+]
modifiednode/cli/src/chain_spec.rsdiffbeforeafterboth
--- a/node/cli/src/chain_spec.rs
+++ b/node/cli/src/chain_spec.rs
@@ -66,7 +66,7 @@
 }
 
 #[cfg(not(feature = "unique-runtime"))]
-/// PARA_ID for Opal/Quartz
+/// PARA_ID for Opal/Sapphire/Quartz
 const PARA_ID: u32 = 2095;
 
 #[cfg(feature = "unique-runtime")]
@@ -89,7 +89,11 @@
 			return RuntimeId::Quartz;
 		}
 
-		if self.id().starts_with("opal") || self.id() == "dev" || self.id() == "local_testnet" {
+		if self.id().starts_with("opal")
+			|| self.id().starts_with("sapphire")
+			|| self.id() == "dev"
+			|| self.id() == "local_testnet"
+		{
 			return RuntimeId::Opal;
 		}
 
modifiednode/cli/src/cli.rsdiffbeforeafterboth
--- a/node/cli/src/cli.rs
+++ b/node/cli/src/cli.rs
@@ -101,6 +101,8 @@
 					"Unique"
 				} else if cfg!(feature = "quartz-runtime") {
 					"Quartz"
+				} else if cfg!(feature = "sapphire-runtime") {
+					"Sapphire"
 				} else {
 					"Opal"
 				}
modifiednode/cli/src/service.rsdiffbeforeafterboth
--- a/node/cli/src/service.rs
+++ b/node/cli/src/service.rs
@@ -46,6 +46,7 @@
 use cumulus_relay_chain_rpc_interface::{RelayChainRpcInterface, create_client_and_start_worker};
 
 // Substrate Imports
+use sp_api::BlockT;
 use sc_executor::NativeElseWasmExecutor;
 use sc_executor::NativeExecutionDispatch;
 use sc_network::{NetworkService, NetworkBlock};
@@ -159,7 +160,10 @@
 	}
 }
 
-pub fn open_frontier_backend(config: &Configuration) -> Result<Arc<fc_db::Backend<Block>>, String> {
+pub fn open_frontier_backend<Block: BlockT, C: sp_blockchain::HeaderBackend<Block>>(
+	client: Arc<C>,
+	config: &Configuration,
+) -> Result<Arc<fc_db::Backend<Block>>, String> {
 	let config_dir = config
 		.base_path
 		.as_ref()
@@ -170,6 +174,7 @@
 	let database_dir = config_dir.join("frontier").join("db");
 
 	Ok(Arc::new(fc_db::Backend::<Block>::new(
+		client,
 		&fc_db::DatabaseSettings {
 			source: fc_db::DatabaseSource::RocksDb {
 				path: database_dir,
@@ -285,7 +290,7 @@
 
 	let filter_pool: Option<FilterPool> = Some(Arc::new(Mutex::new(BTreeMap::new())));
 
-	let frontier_backend = open_frontier_backend(config)?;
+	let frontier_backend = open_frontier_backend(client.clone(), config)?;
 
 	let import_queue = build_import_queue(
 		client.clone(),
modifiednode/rpc/Cargo.tomldiffbeforeafterboth
--- a/node/rpc/Cargo.toml
+++ b/node/rpc/Cargo.toml
@@ -40,20 +40,20 @@
 substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 tokio = { version = "1.19.2", features = ["macros", "sync"] }
 
-pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fp-storage = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fc-db = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-ethereum = { git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fc-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fp-storage = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fc-rpc-core = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fc-db = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fc-mapping-sync = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 
 pallet-common = { default-features = false, path = "../../pallets/common" }
 up-common = { path = "../../primitives/common" }
 pallet-unique = { path = "../../pallets/unique" }
 uc-rpc = { path = "../../client/rpc" }
 up-rpc = { path = "../../primitives/rpc" }
-app-promotion-rpc = { path = "../../primitives/app_promotion_rpc"}
+app-promotion-rpc = { path = "../../primitives/app_promotion_rpc" }
 rmrk-rpc = { path = "../../primitives/rmrk-rpc" }
 up-data-structs = { default-features = false, path = "../../primitives/data-structs" }
 
modifiednode/rpc/src/lib.rsdiffbeforeafterboth
--- a/node/rpc/src/lib.rs
+++ b/node/rpc/src/lib.rs
@@ -216,6 +216,7 @@
 
 	let overrides = overrides_handle::<_, _, R>(client.clone());
 
+	let execute_gas_limit_multiplier = 10;
 	io.merge(
 		Eth::new(
 			client.clone(),
@@ -230,6 +231,7 @@
 			block_data_cache.clone(),
 			fee_history_cache,
 			fee_history_limit,
+			execute_gas_limit_multiplier,
 		)
 		.into_rpc(),
 	)?;
modifiedpallets/app-promotion/Cargo.tomldiffbeforeafterboth
--- a/pallets/app-promotion/Cargo.toml
+++ b/pallets/app-promotion/Cargo.toml
@@ -47,28 +47,30 @@
 ################################################################################
 # Substrate Dependencies
 
-codec = { default-features = false, features = ['derive'], package = 'parity-scale-codec', version = '3.1.2' }
-frame-benchmarking = {default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
+codec = { default-features = false, features = [
+    'derive',
+], package = 'parity-scale-codec', version = '3.1.2' }
+frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-frame-system ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-pallet-balances ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-pallet-timestamp ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-pallet-randomness-collective-flip ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-pallet-evm ={ default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-sp-std ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
+frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
+pallet-balances = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
+pallet-timestamp = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
+pallet-randomness-collective-flip = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-sp-io ={ default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
+sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 serde = { default-features = false, features = ['derive'], version = '1.0.130' }
 
 ################################################################################
 # local dependencies
 
-up-data-structs ={ default-features = false, path = "../../primitives/data-structs" }
-pallet-common ={ default-features = false, path = "../common" }
-pallet-unique ={ default-features = false, path = "../unique" }
-pallet-evm-contract-helpers ={ default-features = false, path = "../evm-contract-helpers" }
-pallet-evm-migration ={ default-features = false, path = "../evm-migration" }
+up-data-structs = { default-features = false, path = "../../primitives/data-structs" }
+pallet-common = { default-features = false, path = "../common" }
+pallet-unique = { default-features = false, path = "../unique" }
+pallet-evm-contract-helpers = { default-features = false, path = "../evm-contract-helpers" }
+pallet-evm-migration = { default-features = false, path = "../evm-migration" }
 
 # [dev-dependencies]
 
modifiedpallets/app-promotion/src/lib.rsdiffbeforeafterboth
--- a/pallets/app-promotion/src/lib.rs
+++ b/pallets/app-promotion/src/lib.rs
@@ -102,7 +102,7 @@
 	use frame_system::pallet_prelude::*;
 
 	#[pallet::config]
-	pub trait Config: frame_system::Config + pallet_evm::account::Config {
+	pub trait Config: frame_system::Config + pallet_evm::Config {
 		/// Type to interact with the native token
 		type Currency: ExtendedLockableCurrency<Self::AccountId>
 			+ ReservableCurrency<Self::AccountId>;
@@ -274,11 +274,13 @@
 
 			if !block_pending.is_empty() {
 				block_pending.into_iter().for_each(|(staker, amount)| {
-					<T::Currency as ReservableCurrency<T::AccountId>>::unreserve(&staker, amount);
+					<<T as Config>::Currency as ReservableCurrency<T::AccountId>>::unreserve(
+						&staker, amount,
+					);
 				});
 			}
 
-			T::WeightInfo::on_initialize(counter)
+			<T as Config>::WeightInfo::on_initialize(counter)
 		}
 	}
 
@@ -297,7 +299,7 @@
 		/// # Arguments
 		///
 		/// * `admin`: account of the new admin.
-		#[pallet::weight(T::WeightInfo::set_admin_address())]
+		#[pallet::weight(<T as Config>::WeightInfo::set_admin_address())]
 		pub fn set_admin_address(origin: OriginFor<T>, admin: T::CrossAccountId) -> DispatchResult {
 			ensure_root(origin)?;
 
@@ -315,7 +317,7 @@
 		/// # Arguments
 		///
 		/// * `amount`: in native tokens.
-		#[pallet::weight(T::WeightInfo::stake())]
+		#[pallet::weight(<T as Config>::WeightInfo::stake())]
 		pub fn stake(staker: OriginFor<T>, amount: BalanceOf<T>) -> DispatchResult {
 			let staker_id = ensure_signed(staker)?;
 
@@ -388,7 +390,7 @@
 		/// Moves the sum of all stakes to the `reserved` state.
 		/// After the end of `PendingInterval` this sum becomes completely
 		/// free for further use.
-		#[pallet::weight(T::WeightInfo::unstake())]
+		#[pallet::weight(<T as Config>::WeightInfo::unstake())]
 		pub fn unstake(staker: OriginFor<T>) -> DispatchResultWithPostInfo {
 			let staker_id = ensure_signed(staker)?;
 
@@ -421,7 +423,10 @@
 
 			Self::unlock_balance(&staker_id, total_staked)?;
 
-			<T::Currency as ReservableCurrency<T::AccountId>>::reserve(&staker_id, total_staked)?;
+			<<T as Config>::Currency as ReservableCurrency<T::AccountId>>::reserve(
+				&staker_id,
+				total_staked,
+			)?;
 
 			TotalStaked::<T>::set(
 				TotalStaked::<T>::get()
@@ -445,7 +450,7 @@
 		/// # Arguments
 		///
 		/// * `collection_id`: ID of the collection that will be sponsored by `pallet_id`
-		#[pallet::weight(T::WeightInfo::sponsor_collection())]
+		#[pallet::weight(<T as Config>::WeightInfo::sponsor_collection())]
 		pub fn sponsor_collection(
 			admin: OriginFor<T>,
 			collection_id: CollectionId,
@@ -470,7 +475,7 @@
 		/// # Arguments
 		///
 		/// * `collection_id`: ID of the collection that is sponsored by `pallet_id`
-		#[pallet::weight(T::WeightInfo::stop_sponsoring_collection())]
+		#[pallet::weight(<T as Config>::WeightInfo::stop_sponsoring_collection())]
 		pub fn stop_sponsoring_collection(
 			admin: OriginFor<T>,
 			collection_id: CollectionId,
@@ -499,7 +504,7 @@
 		/// # Arguments
 		///
 		/// * `contract_id`: the contract address that will be sponsored by `pallet_id`
-		#[pallet::weight(T::WeightInfo::sponsor_contract())]
+		#[pallet::weight(<T as Config>::WeightInfo::sponsor_contract())]
 		pub fn sponsor_contract(admin: OriginFor<T>, contract_id: H160) -> DispatchResult {
 			let admin_id = ensure_signed(admin)?;
 
@@ -525,7 +530,7 @@
 		/// # Arguments
 		///
 		/// * `contract_id`: the contract address that is sponsored by `pallet_id`
-		#[pallet::weight(T::WeightInfo::stop_sponsoring_contract())]
+		#[pallet::weight(<T as Config>::WeightInfo::stop_sponsoring_contract())]
 		pub fn stop_sponsoring_contract(admin: OriginFor<T>, contract_id: H160) -> DispatchResult {
 			let admin_id = ensure_signed(admin)?;
 
@@ -555,7 +560,7 @@
 		/// # Arguments
 		///
 		/// * `stakers_number`: the number of stakers for which recalculation will be performed
-		#[pallet::weight(T::WeightInfo::payout_stakers(stakers_number.unwrap_or(20) as u32))]
+		#[pallet::weight(<T as Config>::WeightInfo::payout_stakers(stakers_number.unwrap_or(20) as u32))]
 		pub fn payout_stakers(admin: OriginFor<T>, stakers_number: Option<u8>) -> DispatchResult {
 			let admin_id = ensure_signed(admin)?;
 
@@ -589,7 +594,7 @@
 				let flush_stake = || -> DispatchResult {
 					if let Some(last_id) = &*last_id.borrow() {
 						if !income_acc.borrow().is_zero() {
-							<T::Currency as Currency<T::AccountId>>::transfer(
+							<<T as Config>::Currency as Currency<T::AccountId>>::transfer(
 								&T::TreasuryAccountId::get(),
 								last_id,
 								*income_acc.borrow(),
@@ -700,9 +705,12 @@
 	/// - `amount`: amount of locked funds.
 	fn set_lock_unchecked(staker: &T::AccountId, amount: BalanceOf<T>) {
 		if amount.is_zero() {
-			<T::Currency as LockableCurrency<T::AccountId>>::remove_lock(LOCK_IDENTIFIER, &staker);
+			<<T as Config>::Currency as LockableCurrency<T::AccountId>>::remove_lock(
+				LOCK_IDENTIFIER,
+				&staker,
+			);
 		} else {
-			<T::Currency as LockableCurrency<T::AccountId>>::set_lock(
+			<<T as Config>::Currency as LockableCurrency<T::AccountId>>::set_lock(
 				LOCK_IDENTIFIER,
 				staker,
 				amount,
@@ -717,7 +725,7 @@
 	pub fn get_locked_balance(
 		staker: impl EncodeLike<T::AccountId>,
 	) -> Option<BalanceLock<BalanceOf<T>>> {
-		<T::Currency as ExtendedLockableCurrency<T::AccountId>>::locks(staker)
+		<<T as Config>::Currency as ExtendedLockableCurrency<T::AccountId>>::locks(staker)
 			.into_iter()
 			.find(|l| l.id == LOCK_IDENTIFIER)
 	}
modifiedpallets/common/CHANGELOG.mddiffbeforeafterboth
--- a/pallets/common/CHANGELOG.md
+++ b/pallets/common/CHANGELOG.md
@@ -4,7 +4,7 @@
 
 <!-- bureaucrate goes here -->
 
-## [0.1.11] - 2022-11-16
+## [0.1.12] - 2022-11-16
 
 ### Changed
 
@@ -12,6 +12,14 @@
   Removed method overload: single signature `(string, uint256)`
   is used for both cases.
 
+## [0.1.11] - 2022-11-12
+
+### Changed
+
+- In the `Collection` solidity interface,
+  the `allowed` function has been renamed to `allow_listed_cross`.
+  Also `EthCrossAccount` type is now used as `user` arg.
+
 ## [0.1.10] - 2022-11-02
 
 ### Changed
modifiedpallets/common/Cargo.tomldiffbeforeafterboth
--- a/pallets/common/Cargo.toml
+++ b/pallets/common/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "pallet-common"
-version = "0.1.11"
+version = "0.1.12"
 license = "GPLv3"
 edition = "2021"
 
@@ -17,12 +17,12 @@
 sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
 pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }
 evm-coder = { default-features = false, path = '../../crates/evm-coder' }
 ethereum = { version = "0.12.0", default-features = false }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 
 serde = { version = "1.0.130", default-features = false }
 scale-info = { version = "2.0.1", default-features = false, features = [
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -16,6 +16,7 @@
 
 //! This module contains the implementation of pallet methods for evm.
 
+pub use pallet_evm::{PrecompileOutput, PrecompileResult, PrecompileHandle, account::CrossAccountId};
 use evm_coder::{
 	abi::AbiType,
 	solidity_interface, solidity, ToLog,
@@ -24,7 +25,6 @@
 	execution::{Result, Error},
 	weight,
 };
-pub use pallet_evm::{PrecompileOutput, PrecompileResult, PrecompileHandle, account::CrossAccountId};
 use pallet_evm_coder_substrate::dispatch_to_evm;
 use sp_std::vec::Vec;
 use up_data_structs::{
@@ -35,7 +35,8 @@
 
 use crate::{
 	Pallet, CollectionHandle, Config, CollectionProperties, SelfWeightOf,
-	eth::convert_cross_account_to_uint256, weights::WeightInfo,
+	eth::{EthCrossAccount, convert_cross_account_to_uint256},
+	weights::WeightInfo,
 };
 
 /// Events for ethereum collection helper.
@@ -529,11 +530,9 @@
 	/// Checks that user allowed to operate with collection.
 	///
 	/// @param user User address to check.
-	fn allowed(&self, user: address) -> Result<bool> {
-		Ok(Pallet::<T>::allowed(
-			self.id,
-			T::CrossAccountId::from_eth(user),
-		))
+	fn allowlisted_cross(&self, user: EthCrossAccount) -> Result<bool> {
+		let user = user.into_sub_cross_account::<T>()?;
+		Ok(Pallet::<T>::allowed(self.id, user))
 	}
 
 	/// Add the user to the allowed list.
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
--- a/pallets/common/src/eth.rs
+++ b/pallets/common/src/eth.rs
@@ -16,8 +16,11 @@
 
 //! The module contains a number of functions for converting and checking ethereum identifiers.
 
-use evm_coder::types::{uint256, address};
-pub use pallet_evm::account::{Config, CrossAccountId};
+use evm_coder::{
+	AbiCoder,
+	types::{uint256, address},
+};
+pub use pallet_evm::{Config, account::CrossAccountId};
 use sp_core::H160;
 use up_data_structs::CollectionId;
 
@@ -109,3 +112,46 @@
 		Err("All fields of cross account is non zeroed".into())
 	}
 }
+
+/// Cross account struct
+#[derive(Debug, Default, AbiCoder)]
+pub struct EthCrossAccount {
+	pub(crate) eth: address,
+	pub(crate) sub: uint256,
+}
+
+impl EthCrossAccount {
+	pub fn from_sub_cross_account<T>(cross_account_id: &T::CrossAccountId) -> Self
+	where
+		T: pallet_evm::Config,
+		T::AccountId: AsRef<[u8; 32]>,
+	{
+		if cross_account_id.is_canonical_substrate() {
+			Self {
+				eth: Default::default(),
+				sub: convert_cross_account_to_uint256::<T>(cross_account_id),
+			}
+		} else {
+			Self {
+				eth: *cross_account_id.as_eth(),
+				sub: Default::default(),
+			}
+		}
+	}
+
+	pub fn into_sub_cross_account<T>(&self) -> evm_coder::execution::Result<T::CrossAccountId>
+	where
+		T: pallet_evm::Config,
+		T::AccountId: From<[u8; 32]>,
+	{
+		if self.eth == Default::default() && self.sub == Default::default() {
+			Err("All fields of cross account is zeroed".into())
+		} else if self.eth == Default::default() {
+			Ok(convert_uint256_to_cross_account::<T>(self.sub))
+		} else if self.sub == Default::default() {
+			Ok(T::CrossAccountId::from_eth(self.eth))
+		} else {
+			Err("All fields of cross account is non zeroed".into())
+		}
+	}
+}
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -342,7 +342,6 @@
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
-	use pallet_evm::account;
 	use dispatch::CollectionDispatch;
 	use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};
 	use frame_system::pallet_prelude::*;
@@ -353,11 +352,7 @@
 
 	#[pallet::config]
 	pub trait Config:
-		frame_system::Config
-		+ pallet_evm_coder_substrate::Config
-		+ pallet_evm::Config
-		+ TypeInfo
-		+ account::Config
+		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::Config + TypeInfo
 	{
 		/// Weight information for functions of this pallet.
 		type WeightInfo: WeightInfo;
@@ -381,6 +376,7 @@
 		type TreasuryAccountId: Get<Self::AccountId>;
 
 		/// Address under which the CollectionHelper contract would be available.
+		#[pallet::constant]
 		type ContractAddress: Get<H160>;
 
 		/// Mapper for token addresses to Ethereum addresses.
modifiedpallets/configuration/Cargo.tomldiffbeforeafterboth
--- a/pallets/configuration/Cargo.toml
+++ b/pallets/configuration/Cargo.toml
@@ -16,7 +16,7 @@
 sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-arithmetic = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 smallvec = "1.6.1"
 
 [features]
modifiedpallets/evm-coder-substrate/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-coder-substrate/Cargo.toml
+++ b/pallets/evm-coder-substrate/Cargo.toml
@@ -12,8 +12,8 @@
 sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 ethereum = { version = "0.12.0", default-features = false }
 evm-coder = { default-features = false, path = "../../crates/evm-coder" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
modifiedpallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/Cargo.toml
+++ b/pallets/evm-contract-helpers/Cargo.toml
@@ -19,8 +19,8 @@
 sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 
 # Unique
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30" }
 
 # Locals
modifiedpallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/lib.rs
+++ b/pallets/evm-contract-helpers/src/lib.rs
@@ -41,12 +41,13 @@
 
 	#[pallet::config]
 	pub trait Config:
-		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::account::Config
+		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::Config
 	{
 		/// Overarching event type.
 		type RuntimeEvent: IsType<<Self as frame_system::Config>::RuntimeEvent> + From<Event<Self>>;
 
 		/// Address, under which magic contract will be available
+		#[pallet::constant]
 		type ContractAddress: Get<H160>;
 
 		/// In case of enabled sponsoring, but no sponsoring rate limit set,
modifiedpallets/evm-migration/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-migration/Cargo.toml
+++ b/pallets/evm-migration/Cargo.toml
@@ -16,8 +16,8 @@
 sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 
 [dependencies.codec]
 default-features = false
modifiedpallets/evm-transaction-payment/Cargo.tomldiffbeforeafterboth
--- a/pallets/evm-transaction-payment/Cargo.toml
+++ b/pallets/evm-transaction-payment/Cargo.toml
@@ -14,11 +14,11 @@
 sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fp-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.30" }
-fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 
 [dependencies.codec]
 default-features = false
modifiedpallets/evm-transaction-payment/src/lib.rsdiffbeforeafterboth
--- a/pallets/evm-transaction-payment/src/lib.rs
+++ b/pallets/evm-transaction-payment/src/lib.rs
@@ -44,7 +44,7 @@
 	}
 
 	#[pallet::config]
-	pub trait Config: frame_system::Config + pallet_evm::account::Config {
+	pub trait Config: frame_system::Config + pallet_evm::Config {
 		/// Loosly-coupled handlers for evm call sponsoring
 		type EvmSponsorshipHandler: SponsorshipHandler<Self::CrossAccountId, CallContext>;
 	}
modifiedpallets/fungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/fungible/Cargo.toml
+++ b/pallets/fungible/Cargo.toml
@@ -23,7 +23,7 @@
 pallet-evm-coder-substrate = { default-features = false, path = '../evm-coder-substrate' }
 ethereum = { version = "0.12.0", default-features = false }
 frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 scale-info = { version = "2.0.1", default-features = false, features = [
     "derive",
 ] }
modifiedpallets/fungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -24,12 +24,16 @@
 	weight,
 };
 use up_data_structs::CollectionMode;
-use pallet_common::erc::{CommonEvmHandler, PrecompileResult};
+use pallet_common::{
+	CollectionHandle,
+	erc::{CommonEvmHandler, PrecompileResult, CollectionCall},
+	eth::EthCrossAccount,
+};
 use sp_std::vec::Vec;
 use pallet_evm::{account::CrossAccountId, PrecompileHandle};
 use pallet_evm_coder_substrate::{call, dispatch_to_evm};
 use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
-use pallet_common::{CollectionHandle, erc::CollectionCall};
+use sp_core::Get;
 
 use crate::{
 	Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,
@@ -132,6 +136,11 @@
 
 		Ok(<Allowance<T>>::get((self.id, owner, spender)).into())
 	}
+
+	/// @notice Returns collection helper contract address
+	fn collection_helper_address(&self) -> Result<address> {
+		Ok(T::ContractAddress::get())
+	}
 }
 
 #[solidity_interface(name = ERC20Mintable)]
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -106,7 +106,7 @@
 pub mod erc;
 pub mod weights;
 
-pub type CreateItemData<T> = (<T as pallet_evm::account::Config>::CrossAccountId, u128);
+pub type CreateItemData<T> = (<T as pallet_evm::Config>::CrossAccountId, u128);
 pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
 
 #[frame_support::pallet]
@@ -379,7 +379,7 @@
 		let balance_from = <Balance<T>>::get((collection.id, from))
 			.checked_sub(amount)
 			.ok_or(<CommonError<T>>::TokenValueTooLow)?;
-		let balance_to = if from != to {
+		let balance_to = if from != to && amount != 0 {
 			Some(
 				<Balance<T>>::get((collection.id, to))
 					.checked_add(amount)
@@ -390,17 +390,18 @@
 		};
 
 		// =========
-
-		<PalletStructure<T>>::nest_if_sent_to_token(
-			from.clone(),
-			to,
-			collection.id,
-			TokenId::default(),
-			nesting_budget,
-		)?;
 
 		if let Some(balance_to) = balance_to {
-			// from != to
+			// from != to && amount != 0
+
+			<PalletStructure<T>>::nest_if_sent_to_token(
+				from.clone(),
+				to,
+				collection.id,
+				TokenId::default(),
+				nesting_budget,
+			)?;
+
 			if balance_from == 0 {
 				<Balance<T>>::remove((collection.id, from));
 				<PalletStructure<T>>::unnest_if_nested(from, collection.id, TokenId::default());
modifiedpallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth
--- a/pallets/fungible/src/stubs/UniqueFungible.sol
+++ b/pallets/fungible/src/stubs/UniqueFungible.sol
@@ -18,7 +18,7 @@
 }
 
 /// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x8b91d192
+/// @dev the ERC-165 identifier for this interface is 0xcc1d80ca
 contract Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -269,9 +269,9 @@
 	/// Checks that user allowed to operate with collection.
 	///
 	/// @param user User address to check.
-	/// @dev EVM selector for this function is: 0xd63a8e11,
-	///  or in textual repr: allowed(address)
-	function allowed(address user) public view returns (bool) {
+	/// @dev EVM selector for this function is: 0x91b6df49,
+	///  or in textual repr: allowlistedCross((address,uint256))
+	function allowlistedCross(EthCrossAccount memory user) public view returns (bool) {
 		require(false, stub_error);
 		user;
 		dummy;
@@ -547,7 +547,7 @@
 	event Approval(address indexed owner, address indexed spender, uint256 value);
 }
 
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
+/// @dev the ERC-165 identifier for this interface is 0x8cb847c4
 contract ERC20 is Dummy, ERC165, ERC20Events {
 	/// @dev EVM selector for this function is: 0x06fdde03,
 	///  or in textual repr: name()
@@ -634,6 +634,15 @@
 		dummy;
 		return 0;
 	}
+
+	/// @notice Returns collection helper contract address
+	/// @dev EVM selector for this function is: 0x1896cce6,
+	///  or in textual repr: collectionHelperAddress()
+	function collectionHelperAddress() public view returns (address) {
+		require(false, stub_error);
+		dummy;
+		return 0x0000000000000000000000000000000000000000;
+	}
 }
 
 contract UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {}
modifiedpallets/nonfungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/nonfungible/Cargo.toml
+++ b/pallets/nonfungible/Cargo.toml
@@ -16,7 +16,7 @@
 sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 pallet-common = { default-features = false, path = '../common' }
 pallet-structure = { default-features = false, path = '../structure' }
 up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -291,6 +291,7 @@
 				<CommonWeights<T>>::burn_item(),
 			)
 		} else {
+			<Pallet<T>>::check_token_immediate_ownership(self, token, &sender)?;
 			Ok(().into())
 		}
 	}
@@ -320,6 +321,7 @@
 				<CommonWeights<T>>::transfer(),
 			)
 		} else {
+			<Pallet<T>>::check_token_immediate_ownership(self, token, &from)?;
 			Ok(().into())
 		}
 	}
@@ -360,6 +362,8 @@
 				<CommonWeights<T>>::transfer_from(),
 			)
 		} else {
+			<Pallet<T>>::check_allowed(self, &sender, &from, token, nesting_budget)?;
+
 			Ok(().into())
 		}
 	}
@@ -380,6 +384,8 @@
 				<CommonWeights<T>>::burn_from(),
 			)
 		} else {
+			<Pallet<T>>::check_allowed(self, &sender, &from, token, nesting_budget)?;
+
 			Ok(().into())
 		}
 	}
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -36,12 +36,14 @@
 use pallet_evm_coder_substrate::dispatch_to_evm;
 use sp_std::vec::Vec;
 use pallet_common::{
+	CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,
 	erc::{CommonEvmHandler, PrecompileResult, CollectionCall, static_property::key},
-	CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,
+	eth::EthCrossAccount,
 };
 use pallet_evm::{account::CrossAccountId, PrecompileHandle};
 use pallet_evm_coder_substrate::call;
 use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
+use sp_core::Get;
 
 use crate::{
 	AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,
@@ -489,6 +491,11 @@
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
+
+	/// @notice Returns collection helper contract address
+	fn collection_helper_address(&self) -> Result<address> {
+		Ok(T::ContractAddress::get())
+	}
 }
 
 /// @title ERC721 Token that can be irreversibly burned (destroyed).
@@ -721,11 +728,7 @@
 	/// @param tokenId Id for the token.
 	/// @param keys Properties keys. Empty keys for all propertyes.
 	/// @return Vector of properties key/value pairs.
-	fn token_properties(
-		&self,
-		token_id: uint256,
-		keys: Vec<string>,
-	) -> Result<Vec<PropertyStruct>> {
+	fn properties(&self, token_id: uint256, keys: Vec<string>) -> Result<Vec<PropertyStruct>> {
 		let keys = keys
 			.into_iter()
 			.map(|key| {
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -127,7 +127,7 @@
 pub mod erc;
 pub mod weights;
 
-pub type CreateItemData<T> = CreateNftExData<<T as pallet_evm::account::Config>::CrossAccountId>;
+pub type CreateItemData<T> = CreateNftExData<<T as pallet_evm::Config>::CrossAccountId>;
 pub(crate) type SelfWeightOf<T> = <T as Config>::WeightInfo;
 
 /// Token data, stored independently from other data used to describe it
@@ -814,6 +814,20 @@
 		<PalletCommon<T>>::set_property_permission(collection, sender, permission)
 	}
 
+	pub fn check_token_immediate_ownership(
+		collection: &NonfungibleHandle<T>,
+		token: TokenId,
+		possible_owner: &T::CrossAccountId,
+	) -> DispatchResult {
+		let token_data =
+			<TokenData<T>>::get((collection.id, token)).ok_or(<CommonError<T>>::TokenNotFound)?;
+		ensure!(
+			&token_data.owner == possible_owner,
+			<CommonError<T>>::NoPermission
+		);
+		Ok(())
+	}
+
 	/// Transfer NFT token from one account to another.
 	///
 	/// `from` account stops being the owner and `to` account becomes the owner of the token.
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -119,7 +119,7 @@
 }
 
 /// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x8b91d192
+/// @dev the ERC-165 identifier for this interface is 0xcc1d80ca
 contract Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -370,9 +370,9 @@
 	/// Checks that user allowed to operate with collection.
 	///
 	/// @param user User address to check.
-	/// @dev EVM selector for this function is: 0xd63a8e11,
-	///  or in textual repr: allowed(address)
-	function allowed(address user) public view returns (bool) {
+	/// @dev EVM selector for this function is: 0x91b6df49,
+	///  or in textual repr: allowlistedCross((address,uint256))
+	function allowlistedCross(EthCrossAccount memory user) public view returns (bool) {
 		require(false, stub_error);
 		user;
 		dummy;
@@ -676,7 +676,7 @@
 }
 
 /// @title Unique extensions for ERC721.
-/// @dev the ERC-165 identifier for this interface is 0xb8f094a0
+/// @dev the ERC-165 identifier for this interface is 0xb74c26b7
 contract ERC721UniqueExtensions is Dummy, ERC165 {
 	/// @notice A descriptive name for a collection of NFTs in this contract
 	/// @dev EVM selector for this function is: 0x06fdde03,
@@ -722,9 +722,9 @@
 	/// @param tokenId Id for the token.
 	/// @param keys Properties keys. Empty keys for all propertyes.
 	/// @return Vector of properties key/value pairs.
-	/// @dev EVM selector for this function is: 0xefc26c69,
-	///  or in textual repr: tokenProperties(uint256,string[])
-	function tokenProperties(uint256 tokenId, string[] memory keys) public view returns (Property[] memory) {
+	/// @dev EVM selector for this function is: 0xe07ede7e,
+	///  or in textual repr: properties(uint256,string[])
+	function properties(uint256 tokenId, string[] memory keys) public view returns (Property[] memory) {
 		require(false, stub_error);
 		tokenId;
 		keys;
@@ -920,7 +920,7 @@
 
 /// @title ERC-721 Non-Fungible Token Standard
 /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
+/// @dev the ERC-165 identifier for this interface is 0x983a942b
 contract ERC721 is Dummy, ERC165, ERC721Events {
 	/// @notice Count all NFTs assigned to an owner
 	/// @dev NFTs assigned to the zero address are considered invalid, and this
@@ -1050,6 +1050,15 @@
 		dummy;
 		return 0x0000000000000000000000000000000000000000;
 	}
+
+	/// @notice Returns collection helper contract address
+	/// @dev EVM selector for this function is: 0x1896cce6,
+	///  or in textual repr: collectionHelperAddress()
+	function collectionHelperAddress() public view returns (address) {
+		require(false, stub_error);
+		dummy;
+		return 0x0000000000000000000000000000000000000000;
+	}
 }
 
 contract UniqueNFT is
modifiedpallets/proxy-rmrk-core/Cargo.tomldiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/Cargo.toml
+++ b/pallets/proxy-rmrk-core/Cargo.toml
@@ -20,7 +20,7 @@
 pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" }
 pallet-structure = { default-features = false, path = "../../pallets/structure" }
 up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 rmrk-traits = { default-features = false, path = "../../primitives/rmrk-traits" }
 scale-info = { version = "2.0.1", default-features = false, features = [
modifiedpallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth
--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -178,7 +178,7 @@
 
 use RmrkProperty::*;
 
-/// Maximum number of levels of depth in the token nesting tree.
+/// A maximum number of levels of depth in the token nesting tree.
 pub const NESTING_BUDGET: u32 = 5;
 
 type PendingTarget = (CollectionId, TokenId);
@@ -190,11 +190,13 @@
 #[frame_support::pallet]
 pub mod pallet {
 	use super::*;
-	use pallet_evm::account;
 
 	#[pallet::config]
 	pub trait Config:
-		frame_system::Config + pallet_common::Config + pallet_nonfungible::Config + account::Config
+		frame_system::Config
+		+ pallet_common::Config
+		+ pallet_nonfungible::Config
+		+ pallet_evm::Config
 	{
 		/// Overarching event type.
 		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
modifiedpallets/proxy-rmrk-equip/Cargo.tomldiffbeforeafterboth
--- a/pallets/proxy-rmrk-equip/Cargo.toml
+++ b/pallets/proxy-rmrk-equip/Cargo.toml
@@ -19,7 +19,7 @@
 pallet-common = { default-features = false, path = '../common' }
 pallet-nonfungible = { default-features = false, path = "../../pallets/nonfungible" }
 up-data-structs = { default-features = false, path = '../../primitives/data-structs' }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 rmrk-traits = { default-features = false, path = "../../primitives/rmrk-traits" }
 scale-info = { version = "2.0.1", default-features = false, features = [
modifiedpallets/refungible/Cargo.tomldiffbeforeafterboth
--- a/pallets/refungible/Cargo.toml
+++ b/pallets/refungible/Cargo.toml
@@ -16,7 +16,7 @@
 sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 evm-coder = { default-features = false, path = '../../crates/evm-coder' }
 pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }
 pallet-common = { default-features = false, path = '../common' }
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -31,14 +31,15 @@
 };
 use frame_support::{BoundedBTreeMap, BoundedVec};
 use pallet_common::{
-	CollectionHandle, CollectionPropertyPermissions,
+	CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations,
 	erc::{CommonEvmHandler, CollectionCall, static_property::key},
-	CommonCollectionOperations,
+	eth::EthCrossAccount,
+	Error as CommonError,
 };
 use pallet_evm::{account::CrossAccountId, PrecompileHandle};
 use pallet_evm_coder_substrate::{call, dispatch_to_evm};
 use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
-use sp_core::H160;
+use sp_core::{H160, Get};
 use sp_std::{collections::btree_map::BTreeMap, vec::Vec, vec};
 use up_data_structs::{
 	CollectionId, CollectionPropertiesVec, mapping::TokenAddressMapping, Property, PropertyKey,
@@ -482,6 +483,11 @@
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
+
+	/// @notice Returns collection helper contract address
+	fn collection_helper_address(&self) -> Result<address> {
+		Ok(T::ContractAddress::get())
+	}
 }
 
 /// Returns amount of pieces of `token` that `owner` have
@@ -503,6 +509,13 @@
 ) -> Result<()> {
 	collection.consume_store_reads(1)?;
 	let total_supply = <TotalSupply<T>>::get((collection.id, token));
+
+	if owner_balance == 0 {
+		return Err(dispatch_to_evm::<T>(
+			<CommonError<T>>::MustBeTokenOwner.into(),
+		));
+	}
+
 	if total_supply != owner_balance {
 		return Err("token has multiple owners".into());
 	}
@@ -749,11 +762,7 @@
 	/// @param tokenId Id for the token.
 	/// @param keys Properties keys. Empty keys for all propertyes.
 	/// @return Vector of properties key/value pairs.
-	fn token_properties(
-		&self,
-		token_id: uint256,
-		keys: Vec<string>,
-	) -> Result<Vec<PropertyStruct>> {
+	fn properties(&self, token_id: uint256, keys: Vec<string>) -> Result<Vec<PropertyStruct>> {
 		let keys = keys
 			.into_iter()
 			.map(|key| {
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -452,6 +452,10 @@
 		token: TokenId,
 		amount: u128,
 	) -> DispatchResult {
+		if <Balance<T>>::get((collection.id, token, owner)) == 0 {
+			return Err(<CommonError<T>>::TokenValueTooLow.into());
+		}
+
 		let total_supply = <TotalSupply<T>>::get((collection.id, token))
 			.checked_sub(amount)
 			.ok_or(<CommonError<T>>::TokenValueTooLow)?;
@@ -739,12 +743,17 @@
 		<PalletCommon<T>>::ensure_correct_receiver(to)?;
 
 		let initial_balance_from = <Balance<T>>::get((collection.id, token, from));
+
+		if initial_balance_from == 0 {
+			return Err(<CommonError<T>>::TokenValueTooLow.into());
+		}
+
 		let updated_balance_from = initial_balance_from
 			.checked_sub(amount)
 			.ok_or(<CommonError<T>>::TokenValueTooLow)?;
 		let mut create_target = false;
 		let from_to_differ = from != to;
-		let updated_balance_to = if from != to {
+		let updated_balance_to = if from != to && amount != 0 {
 			let old_balance = <Balance<T>>::get((collection.id, token, to));
 			if old_balance == 0 {
 				create_target = true;
@@ -786,16 +795,17 @@
 
 		// =========
 
-		<PalletStructure<T>>::nest_if_sent_to_token(
-			from.clone(),
-			to,
-			collection.id,
-			token,
-			nesting_budget,
-		)?;
+		if let Some(updated_balance_to) = updated_balance_to {
+			// from != to && amount != 0
+
+			<PalletStructure<T>>::nest_if_sent_to_token(
+				from.clone(),
+				to,
+				collection.id,
+				token,
+				nesting_budget,
+			)?;
 
-		if let Some(updated_balance_to) = updated_balance_to {
-			// from != to
 			if updated_balance_from == 0 {
 				<Balance<T>>::remove((collection.id, token, from));
 				<PalletStructure<T>>::unnest_if_nested(from, collection.id, token);
modifiedpallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth
--- a/pallets/refungible/src/stubs/UniqueRefungible.sol
+++ b/pallets/refungible/src/stubs/UniqueRefungible.sol
@@ -119,7 +119,7 @@
 }
 
 /// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x8b91d192
+/// @dev the ERC-165 identifier for this interface is 0xcc1d80ca
 contract Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -370,9 +370,9 @@
 	/// Checks that user allowed to operate with collection.
 	///
 	/// @param user User address to check.
-	/// @dev EVM selector for this function is: 0xd63a8e11,
-	///  or in textual repr: allowed(address)
-	function allowed(address user) public view returns (bool) {
+	/// @dev EVM selector for this function is: 0x91b6df49,
+	///  or in textual repr: allowlistedCross((address,uint256))
+	function allowlistedCross(EthCrossAccount memory user) public view returns (bool) {
 		require(false, stub_error);
 		user;
 		dummy;
@@ -674,7 +674,7 @@
 }
 
 /// @title Unique extensions for ERC721.
-/// @dev the ERC-165 identifier for this interface is 0x1d4b64d6
+/// @dev the ERC-165 identifier for this interface is 0x12f7d6c1
 contract ERC721UniqueExtensions is Dummy, ERC165 {
 	/// @notice A descriptive name for a collection of NFTs in this contract
 	/// @dev EVM selector for this function is: 0x06fdde03,
@@ -720,9 +720,9 @@
 	/// @param tokenId Id for the token.
 	/// @param keys Properties keys. Empty keys for all propertyes.
 	/// @return Vector of properties key/value pairs.
-	/// @dev EVM selector for this function is: 0xefc26c69,
-	///  or in textual repr: tokenProperties(uint256,string[])
-	function tokenProperties(uint256 tokenId, string[] memory keys) public view returns (Property[] memory) {
+	/// @dev EVM selector for this function is: 0xe07ede7e,
+	///  or in textual repr: properties(uint256,string[])
+	function properties(uint256 tokenId, string[] memory keys) public view returns (Property[] memory) {
 		require(false, stub_error);
 		tokenId;
 		keys;
@@ -919,7 +919,7 @@
 
 /// @title ERC-721 Non-Fungible Token Standard
 /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-/// @dev the ERC-165 identifier for this interface is 0x58800161
+/// @dev the ERC-165 identifier for this interface is 0x4016cd87
 contract ERC721 is Dummy, ERC165, ERC721Events {
 	/// @notice Count all RFTs assigned to an owner
 	/// @dev RFTs assigned to the zero address are considered invalid, and this
@@ -1047,6 +1047,15 @@
 		dummy;
 		return 0x0000000000000000000000000000000000000000;
 	}
+
+	/// @notice Returns collection helper contract address
+	/// @dev EVM selector for this function is: 0x1896cce6,
+	///  or in textual repr: collectionHelperAddress()
+	function collectionHelperAddress() public view returns (address) {
+		require(false, stub_error);
+		dummy;
+		return 0x0000000000000000000000000000000000000000;
+	}
 }
 
 contract UniqueRefungible is
modifiedpallets/structure/Cargo.tomldiffbeforeafterboth
--- a/pallets/structure/Cargo.toml
+++ b/pallets/structure/Cargo.toml
@@ -16,7 +16,7 @@
 	"derive",
 ] }
 up-data-structs = { path = "../../primitives/data-structs", default-features = false }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 
 [features]
 default = ["std"]
modifiedpallets/unique/Cargo.tomldiffbeforeafterboth
--- a/pallets/unique/Cargo.toml
+++ b/pallets/unique/Cargo.toml
@@ -100,7 +100,7 @@
 scale-info = { version = "2.0.1", default-features = false, features = [
     "derive",
 ] }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 pallet-common = { default-features = false, path = "../common" }
 evm-coder = { default-features = false, path = '../../crates/evm-coder' }
 pallet-evm-coder-substrate = { default-features = false, path = '../../pallets/evm-coder-substrate' }
modifiedpallets/unique/src/eth/mod.rsdiffbeforeafterboth
--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -28,6 +28,7 @@
 	CollectionById,
 	dispatch::CollectionDispatch,
 	erc::{CollectionHelpersEvents, static_property::key},
+	eth::{map_eth_to_id, collection_id_to_address},
 	Pallet as PalletCommon,
 };
 use pallet_evm::{account::CrossAccountId, OnMethodCall, PrecompileHandle, PrecompileResult};
@@ -35,7 +36,7 @@
 use sp_std::vec;
 use up_data_structs::{
 	CollectionDescription, CollectionMode, CollectionName, CollectionTokenPrefix,
-	CreateCollectionData,
+	CreateCollectionData, CollectionId,
 };
 
 use crate::{weights::WeightInfo, Config, SelfWeightOf};
@@ -361,6 +362,25 @@
 			.expect("Collection creation price should be convertible to u128");
 		Ok(price.into())
 	}
+
+	/// Returns address of a collection.
+	/// @param collectionId  - CollectionId  of the collection
+	/// @return eth mirror address of the collection
+	fn collection_address(&self, collection_id: uint32) -> Result<address> {
+		Ok(collection_id_to_address(collection_id.into()))
+	}
+
+	/// Returns collectionId of a collection.
+	/// @param collectionAddress  - Eth address of the collection
+	/// @return collectionId of the collection
+	fn collection_id(&self, collection_address: address) -> Result<uint32> {
+		map_eth_to_id(&collection_address)
+			.map(|id| id.0)
+			.ok_or(Error::Revert(format!(
+				"failed to convert address {} into collectionId.",
+				collection_address
+			)))
+	}
 }
 
 /// Implements [`OnMethodCall`], which delegates call to [`EvmCollectionHelpers`]
modifiedpallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/unique/src/eth/stubs/CollectionHelpers.soldiffbeforeafterboth
--- a/pallets/unique/src/eth/stubs/CollectionHelpers.sol
+++ b/pallets/unique/src/eth/stubs/CollectionHelpers.sol
@@ -24,7 +24,7 @@
 }
 
 /// @title Contract, which allows users to operate with collections
-/// @dev the ERC-165 identifier for this interface is 0x7dea03b1
+/// @dev the ERC-165 identifier for this interface is 0xe65011aa
 contract CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {
 	/// Create an NFT collection
 	/// @param name Name of the collection
@@ -130,4 +130,28 @@
 		dummy;
 		return 0;
 	}
+
+	/// Returns address of a collection.
+	/// @param collectionId  - CollectionId  of the collection
+	/// @return eth mirror address of the collection
+	/// @dev EVM selector for this function is: 0x2e716683,
+	///  or in textual repr: collectionAddress(uint32)
+	function collectionAddress(uint32 collectionId) public view returns (address) {
+		require(false, stub_error);
+		collectionId;
+		dummy;
+		return 0x0000000000000000000000000000000000000000;
+	}
+
+	/// Returns collectionId of a collection.
+	/// @param collectionAddress  - Eth address of the collection
+	/// @return collectionId of the collection
+	/// @dev EVM selector for this function is: 0xb5cb7498,
+	///  or in textual repr: collectionId(address)
+	function collectionId(address collectionAddress) public view returns (uint32) {
+		require(false, stub_error);
+		collectionAddress;
+		dummy;
+		return 0;
+	}
 }
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -86,6 +86,8 @@
 use sp_std::{vec, vec::Vec};
 use up_data_structs::{
 	MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
+	MAX_PROPERTIES_PER_ITEM, MAX_PROPERTY_KEY_LENGTH, MAX_PROPERTY_VALUE_LENGTH,
+	MAX_COLLECTION_PROPERTIES_SIZE, COLLECTION_ADMINS_LIMIT, MAX_TOKEN_PROPERTIES_SIZE,
 	CreateItemData, CollectionLimits, CollectionPermissions, CollectionId, CollectionMode, TokenId,
 	SponsorshipState, CreateCollectionData, CreateItemExData, budget, Property, PropertyKey,
 	PropertyKeyPermission,
@@ -102,7 +104,7 @@
 pub mod weights;
 use weights::WeightInfo;
 
-/// Maximum number of levels of depth in the token nesting tree.
+/// A maximum number of levels of depth in the token nesting tree.
 pub const NESTING_BUDGET: u32 = 5;
 
 decl_error! {
@@ -138,7 +140,7 @@
 	pub enum Event<T>
 	where
 		<T as frame_system::Config>::AccountId,
-		<T as pallet_evm::account::Config>::CrossAccountId,
+		<T as pallet_evm::Config>::CrossAccountId,
 	{
 		/// Collection sponsor was removed
 		///
@@ -277,6 +279,46 @@
 	{
 		type Error = Error<T>;
 
+		#[doc = "A maximum number of levels of depth in the token nesting tree."]
+		const NESTING_BUDGET: u32 = NESTING_BUDGET;
+
+		#[doc = "Maximal length of a collection name."]
+		const MAX_COLLECTION_NAME_LENGTH: u32 = MAX_COLLECTION_NAME_LENGTH;
+
+		#[doc = "Maximal length of a collection description."]
+		const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = MAX_COLLECTION_DESCRIPTION_LENGTH;
+
+		#[doc = "Maximal length of a token prefix."]
+		const MAX_TOKEN_PREFIX_LENGTH: u32 = MAX_TOKEN_PREFIX_LENGTH;
+
+		#[doc = "Maximum admins per collection."]
+		const COLLECTION_ADMINS_LIMIT: u32 = COLLECTION_ADMINS_LIMIT;
+
+		#[doc = "Maximal length of a property key."]
+		const MAX_PROPERTY_KEY_LENGTH: u32 = MAX_PROPERTY_KEY_LENGTH;
+
+		#[doc = "Maximal length of a property value."]
+		const MAX_PROPERTY_VALUE_LENGTH: u32 = MAX_PROPERTY_VALUE_LENGTH;
+
+		#[doc = "A maximum number of token properties."]
+		const MAX_PROPERTIES_PER_ITEM: u32 = MAX_PROPERTIES_PER_ITEM;
+
+		#[doc = "Maximum size for all collection properties."]
+		const MAX_COLLECTION_PROPERTIES_SIZE: u32 = MAX_COLLECTION_PROPERTIES_SIZE;
+
+		#[doc = "Maximum size of all token properties."]
+		const MAX_TOKEN_PROPERTIES_SIZE: u32 = MAX_TOKEN_PROPERTIES_SIZE;
+
+		#[doc = "Default NFT collection limit."]
+		const NFT_DEFAULT_COLLECTION_LIMITS: CollectionLimits = CollectionLimits::with_default_limits(CollectionMode::NFT);
+
+		#[doc = "Default RFT collection limit."]
+		const RFT_DEFAULT_COLLECTION_LIMITS: CollectionLimits = CollectionLimits::with_default_limits(CollectionMode::ReFungible);
+
+		#[doc = "Default FT collection limit."]
+		const FT_DEFAULT_COLLECTION_LIMITS: CollectionLimits = CollectionLimits::with_default_limits(CollectionMode::Fungible(0));
+
+
 		pub fn deposit_event() = default;
 
 		fn on_initialize(_now: T::BlockNumber) -> Weight {
modifiedprimitives/app_promotion_rpc/Cargo.tomldiffbeforeafterboth
--- a/primitives/app_promotion_rpc/Cargo.toml
+++ b/primitives/app_promotion_rpc/Cargo.toml
@@ -14,7 +14,7 @@
 sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 
 [features]
 default = ["std"]
modifiedprimitives/common/Cargo.tomldiffbeforeafterboth
--- a/primitives/common/Cargo.toml
+++ b/primitives/common/Cargo.toml
@@ -48,9 +48,9 @@
 [dependencies.fp-rpc]
 default-features = false
 git = "https://github.com/uniquenetwork/frontier"
-branch = "unique-polkadot-v0.9.30"
+branch = "unique-polkadot-v0.9.30-2"
 
 [dependencies.pallet-evm]
 default-features = false
 git = "https://github.com/uniquenetwork/frontier"
-branch = "unique-polkadot-v0.9.30"
+branch = "unique-polkadot-v0.9.30-2"
modifiedprimitives/data-structs/CHANGELOG.mddiffbeforeafterboth
--- a/primitives/data-structs/CHANGELOG.md
+++ b/primitives/data-structs/CHANGELOG.md
@@ -3,6 +3,7 @@
 All notable changes to this project will be documented in this file.
 
 <!-- bureaucrate goes here -->
+
 ## [v0.2.2] 2022-08-16
 
 ### Other changes
@@ -28,12 +29,19 @@
 multiple users into `RefungibleMultipleItems` call.
 
 ## [v0.2.0] - 2022-08-01
+
 ### Deprecated
+
 - `CreateReFungibleData::const_data`
 
 ## [v0.1.2] - 2022-07-25
+
 ### Added
+
 - Type aliases `CollectionName`, `CollectionDescription`, `CollectionTokenPrefix`
+
 ## [v0.1.1] - 2022-07-22
+
 ### Added
-- Аields with properties to `CreateReFungibleData` and `CreateRefungibleExData`.
\ No newline at end of file
+
+- Fields with properties to `CreateReFungibleData` and `CreateRefungibleExData`.
modifiedprimitives/data-structs/Cargo.tomldiffbeforeafterboth
--- a/primitives/data-structs/Cargo.toml
+++ b/primitives/data-structs/Cargo.toml
@@ -25,9 +25,11 @@
 sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 derivative = { version = "2.2.0", features = ["use_core"] }
 struct-versioning = { path = "../../crates/struct-versioning" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 rmrk-traits = { default-features = false, path = "../rmrk-traits" }
-bondrewd = { version = "0.1.14", features = ["derive"], default-features = false }
+bondrewd = { version = "0.1.14", features = [
+  "derive",
+], default-features = false }
 
 [features]
 default = ["std"]
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -120,22 +120,22 @@
 // TODO: not used. Delete?
 pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;
 
-/// Maximum length for collection name.
+/// Maximal length of a collection name.
 pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;
 
-/// Maximum length for collection description.
+/// Maximal length of a collection description.
 pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;
 
-/// Maximal token prefix length.
+/// Maximal length of a token prefix.
 pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;
 
-/// Maximal lenght of property key.
+/// Maximal length of a property key.
 pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;
 
-/// Maximal lenght of property value.
+/// Maximal length of a property value.
 pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;
 
-/// Maximum properties that can be assigned to token.
+/// A maximum number of token properties.
 pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;
 
 /// Maximal lenght of extended property value.
@@ -144,7 +144,7 @@
 /// Maximum size for all collection properties.
 pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;
 
-/// Maximum size for all token properties.
+/// Maximum size of all token properties.
 pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;
 
 /// How much items can be created per single
@@ -609,6 +609,24 @@
 }
 
 impl CollectionLimits {
+	pub fn with_default_limits(collection_type: CollectionMode) -> Self {
+		CollectionLimits {
+			account_token_ownership_limit: Some(ACCOUNT_TOKEN_OWNERSHIP_LIMIT),
+			sponsored_data_size: Some(CUSTOM_DATA_LIMIT),
+			sponsored_data_rate_limit: Some(SponsoringRateLimit::SponsoringDisabled),
+			token_limit: Some(COLLECTION_TOKEN_LIMIT),
+			sponsor_transfer_timeout: match collection_type {
+				CollectionMode::NFT => Some(NFT_SPONSOR_TRANSFER_TIMEOUT),
+				CollectionMode::ReFungible => Some(REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),
+				CollectionMode::Fungible(_) => Some(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT),
+			},
+			sponsor_approve_timeout: Some(SPONSOR_APPROVE_TIMEOUT),
+			owner_can_transfer: Some(false),
+			owner_can_destroy: Some(true),
+			transfers_enabled: Some(true),
+		}
+	}
+
 	/// Get effective value for [`account_token_ownership_limit`](self.account_token_ownership_limit).
 	pub fn account_token_ownership_limit(&self) -> u32 {
 		self.account_token_ownership_limit
@@ -962,12 +980,15 @@
 		use scale_info::{
 			Type, Path,
 			build::{FieldsBuilder, UnnamedFields},
+			form::MetaForm,
 			type_params,
 		};
 		Type::builder()
 			.path(Path::new("up_data_structs", "PhantomType"))
 			.type_params(type_params!(T))
-			.composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))
+			.composite(
+				<FieldsBuilder<MetaForm, UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()),
+			)
 	}
 }
 impl<T> MaxEncodedLen for PhantomType<T> {
modifiedprimitives/rpc/Cargo.tomldiffbeforeafterboth
--- a/primitives/rpc/Cargo.toml
+++ b/primitives/rpc/Cargo.toml
@@ -14,7 +14,7 @@
 sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-api = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 
 [features]
 default = ["std"]
modifiedruntime/common/config/ethereum.rsdiffbeforeafterboth
--- a/runtime/common/config/ethereum.rs
+++ b/runtime/common/config/ethereum.rs
@@ -17,19 +17,15 @@
 
 pub type CrossAccountId = pallet_evm::account::BasicCrossAccountId<Runtime>;
 
-impl pallet_evm::account::Config for Runtime {
-	type CrossAccountId = CrossAccountId;
-	type EvmAddressMapping = pallet_evm::HashedAddressMapping<Self::Hashing>;
-	type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated;
-}
-
 // Assuming slowest ethereum opcode is SSTORE, with gas price of 20000 as our worst case
 // (contract, which only writes a lot of data),
 // approximating on top of our real store write weight
 parameter_types! {
 	pub const WritesPerSecond: u64 = WEIGHT_PER_SECOND.ref_time() / <Runtime as frame_system::Config>::DbWeight::get().write;
 	pub const GasPerSecond: u64 = WritesPerSecond::get() * 20000;
-	pub const WeightPerGas: u64 = WEIGHT_PER_SECOND.ref_time() / GasPerSecond::get();
+	pub const WeightTimePerGas: u64 = WEIGHT_PER_SECOND.ref_time() / GasPerSecond::get();
+
+	pub const WeightPerGas: Weight = Weight::from_ref_time(WeightTimePerGas::get());
 }
 
 /// Limiting EVM execution to 50% of block for substrate users and management tasks
@@ -37,17 +33,7 @@
 /// scheduled fairly
 const EVM_DISPATCH_RATIO: Perbill = Perbill::from_percent(50);
 parameter_types! {
-	pub BlockGasLimit: U256 = U256::from((NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightPerGas::get()).ref_time());
-}
-
-pub enum FixedGasWeightMapping {}
-impl pallet_evm::GasWeightMapping for FixedGasWeightMapping {
-	fn gas_to_weight(gas: u64) -> Weight {
-		Weight::from_ref_time(gas).saturating_mul(WeightPerGas::get())
-	}
-	fn weight_to_gas(weight: Weight) -> u64 {
-		(weight / WeightPerGas::get()).ref_time()
-	}
+	pub BlockGasLimit: U256 = U256::from((NORMAL_DISPATCH_RATIO * EVM_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WeightTimePerGas::get()).ref_time());
 }
 
 pub struct EthereumFindAuthor<F>(core::marker::PhantomData<F>);
@@ -65,9 +51,13 @@
 }
 
 impl pallet_evm::Config for Runtime {
+	type CrossAccountId = CrossAccountId;
+	type EvmAddressMapping = pallet_evm::HashedAddressMapping<Self::Hashing>;
+	type EvmBackwardsAddressMapping = fp_evm_mapping::MapBackwardsAddressTruncated;
 	type BlockGasLimit = BlockGasLimit;
 	type FeeCalculator = pallet_configuration::FeeCalculator<Self>;
-	type GasWeightMapping = FixedGasWeightMapping;
+	type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
+	type WeightPerGas = WeightPerGas;
 	type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
 	type CallOrigin = EnsureAddressTruncated<Self>;
 	type WithdrawOrigin = EnsureAddressTruncated<Self>;
modifiedruntime/common/config/pallets/app_promotion.rsdiffbeforeafterboth
--- a/runtime/common/config/pallets/app_promotion.rs
+++ b/runtime/common/config/pallets/app_promotion.rs
@@ -22,7 +22,7 @@
 use frame_support::{parameter_types, PalletId};
 use sp_arithmetic::Perbill;
 use up_common::{
-	constants::{UNIQUE, RELAY_DAYS},
+	constants::{UNIQUE, RELAY_DAYS, DAYS},
 	types::Balance,
 };
 
@@ -32,7 +32,6 @@
 	pub const RecalculationInterval: BlockNumber = 8;
 	pub const PendingInterval: BlockNumber = 4;
 	pub const Nominal: Balance = UNIQUE;
-	// pub const Day: BlockNumber = DAYS;
 	pub IntervalIncome: Perbill = Perbill::from_rational(RecalculationInterval::get(), RELAY_DAYS) * Perbill::from_rational(5u32, 10_000);
 }
 
@@ -40,9 +39,8 @@
 parameter_types! {
 	pub const AppPromotionId: PalletId = PalletId(*b"appstake");
 	pub const RecalculationInterval: BlockNumber = RELAY_DAYS;
-	pub const PendingInterval: BlockNumber = 7 * RELAY_DAYS;
+	pub const PendingInterval: BlockNumber = 7 * DAYS;
 	pub const Nominal: Balance = UNIQUE;
-	// pub const Day: BlockNumber = RELAY_DAYS;
 	pub IntervalIncome: Perbill = Perbill::from_rational(5u32, 10_000);
 }
 
@@ -56,7 +54,6 @@
 	type RelayBlockNumberProvider = RelayChainBlockNumberProvider<Runtime>;
 	type RecalculationInterval = RecalculationInterval;
 	type PendingInterval = PendingInterval;
-	// type Day = Day;
 	type Nominal = Nominal;
 	type IntervalIncome = IntervalIncome;
 	type RuntimeEvent = RuntimeEvent;
modifiedruntime/common/ethereum/self_contained_call.rsdiffbeforeafterboth
--- a/runtime/common/ethereum/self_contained_call.rs
+++ b/runtime/common/ethereum/self_contained_call.rs
@@ -69,9 +69,13 @@
 	fn pre_dispatch_self_contained(
 		&self,
 		info: &Self::SignedInfo,
+		dispatch_info: &DispatchInfoOf<RuntimeCall>,
+		len: usize,
 	) -> Option<Result<(), TransactionValidityError>> {
 		match self {
-			RuntimeCall::Ethereum(call) => call.pre_dispatch_self_contained(info),
+			RuntimeCall::Ethereum(call) => {
+				call.pre_dispatch_self_contained(info, dispatch_info, len)
+			}
 			_ => None,
 		}
 	}
modifiedruntime/common/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/runtime_apis.rs
+++ b/runtime/common/runtime_apis.rs
@@ -482,6 +482,7 @@
                     };
 
                     let is_transactional = false;
+                    let validate = false;
                     <Runtime as pallet_evm::Config>::Runner::call(
                         CrossAccountId::from_eth(from),
                         to,
@@ -493,6 +494,7 @@
                         nonce,
                         access_list.unwrap_or_default(),
                         is_transactional,
+                        validate,
                         config.as_ref().unwrap_or_else(|| <Runtime as pallet_evm::Config>::config()),
                     ).map_err(|err| err.error.into())
                 }
@@ -518,6 +520,7 @@
                     };
 
                     let is_transactional = false;
+                    let validate = false;
                     <Runtime as pallet_evm::Config>::Runner::create(
                         CrossAccountId::from_eth(from),
                         data,
@@ -528,6 +531,7 @@
                         nonce,
                         access_list.unwrap_or_default(),
                         is_transactional,
+                        validate,
                         config.as_ref().unwrap_or_else(|| <Runtime as pallet_evm::Config>::config()),
                     ).map_err(|err| err.error.into())
                 }
modifiedruntime/opal/Cargo.tomldiffbeforeafterboth
--- a/runtime/opal/Cargo.toml
+++ b/runtime/opal/Cargo.toml
@@ -82,7 +82,6 @@
     'pallet-proxy-rmrk-equip/try-runtime',
     'pallet-app-promotion/try-runtime',
     'pallet-foreign-assets/try-runtime',
-    'pallet-evm/try-runtime',
     'pallet-ethereum/try-runtime',
     'pallet-evm-coder-substrate/try-runtime',
     'pallet-evm-contract-helpers/try-runtime',
@@ -174,7 +173,15 @@
     'pallet-test-utils?/std',
 ]
 limit-testing = ['pallet-unique/limit-testing', 'up-data-structs/limit-testing']
-opal-runtime = ['refungible', 'scheduler', 'rmrk', 'app-promotion', 'foreign-assets', 'pallet-test-utils']
+opal-runtime = [
+    'refungible',
+    'scheduler',
+    'rmrk',
+    'app-promotion',
+    'foreign-assets',
+    'pallet-test-utils',
+]
+become-sapphire = []
 
 refungible = []
 scheduler = []
@@ -461,7 +468,7 @@
 up-rpc = { path = "../../primitives/rpc", default-features = false }
 app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false }
 rmrk-rpc = { path = "../../primitives/rmrk-rpc", default-features = false }
-fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 pallet-inflation = { path = '../../pallets/inflation', default-features = false }
 pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false }
 up-data-structs = { path = '../../primitives/data-structs', default-features = false }
@@ -479,11 +486,11 @@
 pallet-evm-contract-helpers = { path = '../../pallets/evm-contract-helpers', default-features = false }
 pallet-evm-transaction-payment = { path = '../../pallets/evm-transaction-payment', default-features = false }
 pallet-evm-coder-substrate = { default-features = false, path = "../../pallets/evm-coder-substrate" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 evm-coder = { default-features = false, path = '../../crates/evm-coder' }
 up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.30' }
 pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" }
modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
--- a/runtime/opal/src/lib.rs
+++ b/runtime/opal/src/lib.rs
@@ -42,7 +42,14 @@
 
 pub use runtime_common::*;
 
+#[cfg(feature = "become-sapphire")]
+pub const RUNTIME_NAME: &str = "sapphire";
+#[cfg(feature = "become-sapphire")]
+pub const TOKEN_SYMBOL: &str = "QTZ";
+
+#[cfg(not(feature = "become-sapphire"))]
 pub const RUNTIME_NAME: &str = "opal";
+#[cfg(not(feature = "become-sapphire"))]
 pub const TOKEN_SYMBOL: &str = "OPL";
 
 /// This runtime version.
@@ -59,7 +66,16 @@
 
 parameter_types! {
 	pub const Version: RuntimeVersion = VERSION;
-	pub const SS58Prefix: u8 = 42;
+}
+#[cfg(feature = "become-sapphire")]
+parameter_types! {
+	pub const SS58Prefix: u16 = 8883;
+	pub const ChainId: u64 = 8883;
+}
+
+#[cfg(not(feature = "become-sapphire"))]
+parameter_types! {
+	pub const SS58Prefix: u16 = 42;
 	pub const ChainId: u64 = 8882;
 }
 
modifiedruntime/quartz/Cargo.tomldiffbeforeafterboth
--- a/runtime/quartz/Cargo.toml
+++ b/runtime/quartz/Cargo.toml
@@ -80,7 +80,6 @@
     'pallet-proxy-rmrk-equip/try-runtime',
     'pallet-app-promotion/try-runtime',
     'pallet-foreign-assets/try-runtime',
-    'pallet-evm/try-runtime',
     'pallet-ethereum/try-runtime',
     'pallet-evm-coder-substrate/try-runtime',
     'pallet-evm-contract-helpers/try-runtime',
@@ -460,7 +459,7 @@
 pallet-unique = { path = '../../pallets/unique', default-features = false }
 up-rpc = { path = "../../primitives/rpc", default-features = false }
 app-promotion-rpc = { path = "../../primitives/app_promotion_rpc", default-features = false }
-fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 pallet-inflation = { path = '../../pallets/inflation', default-features = false }
 pallet-app-promotion = { path = '../../pallets/app-promotion', default-features = false }
 up-data-structs = { path = '../../primitives/data-structs', default-features = false }
@@ -478,11 +477,11 @@
 pallet-evm-contract-helpers = { path = '../../pallets/evm-contract-helpers', default-features = false }
 pallet-evm-transaction-payment = { path = '../../pallets/evm-transaction-payment', default-features = false }
 pallet-evm-coder-substrate = { default-features = false, path = "../../pallets/evm-coder-substrate" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 evm-coder = { default-features = false, path = '../../crates/evm-coder' }
 up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.30' }
 pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" }
modifiedruntime/tests/Cargo.tomldiffbeforeafterboth
--- a/runtime/tests/Cargo.toml
+++ b/runtime/tests/Cargo.toml
@@ -16,7 +16,7 @@
 sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 
-fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 
 frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
@@ -25,8 +25,8 @@
 pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.30" }
 
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 
 pallet-common = { path = '../../pallets/common' }
 pallet-structure = { path = '../../pallets/structure' }
modifiedruntime/tests/src/lib.rsdiffbeforeafterboth
--- a/runtime/tests/src/lib.rs
+++ b/runtime/tests/src/lib.rs
@@ -21,6 +21,7 @@
 	parameter_types,
 	traits::{Everything, ConstU32, ConstU64},
 	weights::IdentityFee,
+	pallet_prelude::Weight,
 };
 use sp_runtime::{
 	traits::{BlakeTwo256, IdentityLookup},
@@ -202,6 +203,7 @@
 
 parameter_types! {
 	pub BlockGasLimit: U256 = 0u32.into();
+	pub WeightPerGas: Weight = Weight::from_ref_time(20);
 }
 
 impl pallet_ethereum::Config for Test {
@@ -210,11 +212,15 @@
 }
 
 impl pallet_evm::Config for Test {
+	type CrossAccountId = TestCrossAccountId;
+	type EvmAddressMapping = TestEvmAddressMapping;
+	type EvmBackwardsAddressMapping = TestEvmBackwardsAddressMapping;
 	type RuntimeEvent = RuntimeEvent;
 	type FeeCalculator = ();
-	type GasWeightMapping = ();
-	type CallOrigin = EnsureAddressNever<Self::CrossAccountId>;
-	type WithdrawOrigin = EnsureAddressNever<Self::CrossAccountId>;
+	type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
+	type WeightPerGas = WeightPerGas;
+	type CallOrigin = EnsureAddressNever<Self>;
+	type WithdrawOrigin = EnsureAddressNever<Self>;
 	type AddressMapping = TestEvmAddressMapping;
 	type Currency = Balances;
 	type PrecompilesType = ();
@@ -242,12 +248,6 @@
 	type EvmTokenAddressMapping = EvmTokenAddressMapping;
 	type CrossTokenAddressMapping = CrossTokenAddressMapping<Self::AccountId>;
 	type ContractAddress = EvmCollectionHelpersAddress;
-}
-
-impl pallet_evm::account::Config for Test {
-	type CrossAccountId = TestCrossAccountId;
-	type EvmAddressMapping = TestEvmAddressMapping;
-	type EvmBackwardsAddressMapping = TestEvmBackwardsAddressMapping;
 }
 
 impl pallet_structure::Config for Test {
modifiedruntime/unique/Cargo.tomldiffbeforeafterboth
--- a/runtime/unique/Cargo.toml
+++ b/runtime/unique/Cargo.toml
@@ -81,7 +81,6 @@
     'pallet-proxy-rmrk-equip/try-runtime',
     'pallet-app-promotion/try-runtime',
     'pallet-foreign-assets/try-runtime',
-    'pallet-evm/try-runtime',
     'pallet-ethereum/try-runtime',
     'pallet-evm-coder-substrate/try-runtime',
     'pallet-evm-contract-helpers/try-runtime',
@@ -472,12 +471,12 @@
 pallet-evm-contract-helpers = { path = '../../pallets/evm-contract-helpers', default-features = false }
 pallet-evm-transaction-payment = { path = '../../pallets/evm-transaction-payment', default-features = false }
 pallet-evm-coder-substrate = { default-features = false, path = "../../pallets/evm-coder-substrate" }
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
-fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30" }
+pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+pallet-ethereum = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+pallet-base-fee = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fp-rpc = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fp-self-contained = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
+fp-evm-mapping = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.30-2" }
 evm-coder = { default-features = false, path = '../../crates/evm-coder' }
 up-sponsorship = { default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = 'polkadot-v0.9.30' }
 pallet-foreign-assets = { default-features = false, path = "../../pallets/foreign-assets" }
modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -102,6 +102,7 @@
     "testXcmTransferStatemine": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferStatemine.test.ts statemineId=1000 uniqueId=5000",
     "testXcmTransferMoonbeam": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferMoonbeam.test.ts",
     "benchMintingFee": "ts-node src/benchmarks/mintFee/benchmark.ts",
+    "testApiConsts": "mocha --timeout 9999999 -r ts-node/register ./**/apiConsts.test.ts",
     "load": "mocha --timeout 9999999 -r ts-node/register './**/*.load.ts'",
     "loadTransfer": "ts-node src/transfer.nload.ts",
     "polkadot-types-fetch-metadata": "curl -H 'Content-Type: application/json' -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > src/interfaces/metadata.json",
addedtests/scripts/functions.shdiffbeforeafterboth
--- /dev/null
+++ b/tests/scripts/functions.sh
@@ -0,0 +1,4 @@
+
+function do_rpc {
+	curl -s --header "Content-Type: application/json" -XPOST --data "{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"$1\",\"params\":[$2]}" $RPC_URL
+}
addedtests/scripts/generate_types_package.shdiffbeforeafterboth
--- /dev/null
+++ b/tests/scripts/generate_types_package.sh
@@ -0,0 +1,214 @@
+#!/usr/bin/env bash
+
+set -eu
+
+DIR=$(realpath $(dirname "$0"))
+TEMPLATE=$DIR/types_template
+GIT_REPO=git@github.com:UniqueNetwork/unique-types-js.git
+
+. $DIR/functions.sh
+
+usage() {
+	echo "Usage: [RPC_URL=http://localhost:9933] $0 <--rc|--release|--sapphire> [--force] [--push] [--rpc-url=http://localhost:9933]" 1>&2
+	exit 1
+}
+
+rc=
+sapphire=
+release=
+force=
+push=
+
+for i in "$@"; do
+case $i in
+	--rc)
+		rc=1
+		if test "$release" -o "$sapphire"; then usage; fi
+		;;
+	--sapphire)
+		sapphire=1
+		if test "$rc" -o "$release"; then usage; fi
+		;;
+	--release)
+		release=1
+		if test "$rc" -o "$sapphire"; then usage; fi
+		;;
+	--force)
+		force=1
+		;;
+	--push)
+		push=1
+		;;
+	--rpc-url=*)
+		RPC_URL=${i#*=}
+		;;
+	*)
+		usage
+		;;
+esac
+done
+
+if test \( ! \( "$rc" -o "$release" -o "$sapphire" \) \) -o \( "${RPC_URL=}" = "" \); then
+	usage
+elif test "$rc"; then
+	echo "Rc build"
+else
+	echo "Release build"
+fi
+
+cd $DIR/..
+yarn polkadot-types
+
+version=$(do_rpc state_getRuntimeVersion "")
+spec_version=$(echo $version | jq -r .result.specVersion)
+spec_name=$(echo $version | jq -r .result.specName)
+echo "Spec version: $spec_version, name: $spec_name"
+
+case $spec_name in
+	opal)
+		package_name=@unique-nft/opal-testnet-types
+		repo_branch=opal-testnet
+		repo_tag=$repo_branch
+		;;
+	quartz)
+		package_name=@unique-nft/quartz-mainnet-types
+		repo_branch=quartz-mainnet
+		repo_tag=$repo_branch
+		;;
+	unique)
+		package_name=@unique-nft/unique-mainnet-types
+		repo_branch=master
+		repo_tag=unique-mainnet
+		;;
+	*)
+		echo "unknown spec name: $spec_name"
+		exit 1
+		;;
+esac
+
+if test "$rc" = 1; then
+	if "$spec_name" != opal; then
+		echo "rc types can only be based on opal spec"
+		exit 1
+	fi
+	package_name=@unique-nft/rc-types
+	repo_branch=rc
+	repo_tag=$repo_branch
+fi
+if test "$sapphire" = 1; then
+	if "$spec_name" != opal; then
+		echo "sapphire types can only be based on opal spec"
+		exit 1
+	fi
+	package_name=@unique-nft/sapphire-mainnet-types
+	repo_branch=sapphire-mainnet
+	repo_tag=$repo_branch
+fi
+
+package_version=${spec_version:0:3}.$(echo ${spec_version:3:3} | sed 's/^0*//').
+last_patch=NEVER
+for tag in $(git ls-remote -t --refs $GIT_REPO | cut -f 2 | sort -r); do
+	tag_prefix=refs/tags/$repo_tag-v$package_version
+	if [[ $tag == $tag_prefix* ]]; then
+		last_patch=${tag#$tag_prefix}
+		break;
+	fi
+done
+echo "Package version: ${package_version}X, name: $package_name"
+echo "Last published: $package_version$last_patch"
+
+if test "$last_patch" = "NEVER"; then
+	new_package_version=${package_version}0
+else
+	new_package_version=${package_version}$((last_patch+1))
+fi
+package_version=${package_version}$last_patch
+echo "New package version: $new_package_version"
+
+pjsapi_ver=^$(cat $DIR/../package.json | jq -r '.dependencies."@polkadot/api"' | sed -e "s/^\^//")
+tsnode_ver=^$(cat $DIR/../package.json | jq -r '.devDependencies."ts-node"' | sed -e "s/^\^//")
+ts_ver=^$(cat $DIR/../package.json | jq -r '.devDependencies."typescript"' | sed -e "s/^\^//")
+
+gen=$(mktemp -d)
+pushd $gen
+git clone $GIT_REPO -b $repo_branch --depth 1 .
+if test "$last_patch" != "NEVER"; then
+	git reset --hard $repo_tag-v$package_version
+fi
+git rm -r "*"
+popd
+
+# Using old package_version here, becaue we first check if
+# there is any difference between generated and already uplaoded types
+cat $TEMPLATE/package.json \
+| jq '.private = false' - \
+| jq '.name = "'$package_name'"' - \
+| jq '.version = "'$package_version'"' - \
+| jq '.peerDependencies."@polkadot/api" = "'$pjsapi_ver'"' - \
+| jq '.peerDependencies."@polkadot/types" = "'$pjsapi_ver'"' - \
+| jq '.devDependencies."@polkadot/api" = "'$pjsapi_ver'"' - \
+| jq '.devDependencies."@polkadot/types" = "'$pjsapi_ver'"' - \
+| jq '.devDependencies."ts-node" = "'$tsnode_ver'"' - \
+| jq '.devDependencies."typescript" = "'$ts_ver'"' - \
+> $gen/package.json
+for file in .gitignore .npmignore README.md tsconfig.json; do
+	cp $TEMPLATE/$file $gen/
+done
+package_name_replacement=$(printf '%s\n' "$package_name" | sed -e 's/[\/&]/\\&/g')
+sed -i 's/PKGNAME/'$package_name_replacement'/' $gen/README.md
+
+rsync -ar --exclude .gitignore src/interfaces/ $gen
+for file in $gen/augment-* $gen/**/types.ts $gen/registry.ts; do
+	sed -i '1s;^;//@ts-nocheck\n;' $file
+done
+
+pushd $gen
+git add .
+popd
+
+pushd $gen
+if git diff --quiet HEAD && test ! "$force"; then
+	echo "no changes detected"
+	exit 0
+fi
+popd
+
+mv $gen/package.json $gen/package.old.json
+cat $gen/package.old.json \
+| jq '.version = "'$new_package_version'"' - \
+> $gen/package.json
+rm $gen/package.old.json
+pushd $gen
+git add package.json
+popd
+
+echo "package.json contents:"
+cat $gen/package.json
+echo "overall diff:"
+pushd $gen
+git status
+git diff HEAD || true
+popd
+
+# This check is only active if running in interactive terminal
+if [ -t 0 ]; then
+	read -p "Is everything ok at $gen [y/n]? " -n 1 -r
+	echo
+	if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+		echo "Aborting!"
+		exit 1
+	fi
+fi
+
+pushd $gen
+yarn
+yarn prepublish
+git commit -m "chore: upgrade types to v$new_package_version"
+git tag --force $repo_tag-v$new_package_version
+if test "$push" = 1; then
+	git push --tags --force -u origin HEAD
+else
+	echo "--push not given, origin repo left intact"
+	echo "To publish manually, go to $gen, and run \"git push --tags --force -u origin HEAD\""
+fi
+popd
addedtests/scripts/types_template/.gitignorediffbeforeafterboth
--- /dev/null
+++ b/tests/scripts/types_template/.gitignore
@@ -0,0 +1,5 @@
+*.js
+*.map
+*.d.ts
+/node_modules
+metadata.json
addedtests/scripts/types_template/.npmignorediffbeforeafterboth
--- /dev/null
+++ b/tests/scripts/types_template/.npmignore
@@ -0,0 +1 @@
+/src
addedtests/scripts/types_template/README.mddiffbeforeafterboth
--- /dev/null
+++ b/tests/scripts/types_template/README.md
@@ -0,0 +1,31 @@
+# PKGNAME
+
+Unique network api types
+
+Do not edit by hand, those types are generated automatically, and definitions are located in chain repo
+
+## Using types
+
+Install library:
+
+```bash
+yarn add --dev PKGNAME
+```
+
+Replace polkadot.js types with our chain types adding corresponding path override to the tsconfig `compilerOptions.paths` section:
+
+```json
+// in tsconfig.json
+{
+  "compilerOptions": {
+    "paths": {
+      "@polkadot/types/lookup": ["node_modules/PKGNAME/types-lookup"]
+    }
+  }
+}
+```
+
+Since polkadot v7 api augmentations not loaded by default, in every file, where you need to access `api.tx`, `api.query`, `api.rpc`, etc; you should explicitly import corresponding augmentation before any other `polkadot.js` related import:
+```
+import 'PKGNAME/augment-api';
+```
addedtests/scripts/types_template/package.jsondiffbeforeafterboth
--- /dev/null
+++ b/tests/scripts/types_template/package.json
@@ -0,0 +1,22 @@
+{
+  "name": "TODO",
+  "private": true,
+  "version": "TODO",
+  "main": "index.js",
+  "repository": "git@github.com:UniqueNetwork/unique-types-js.git",
+  "homepage": "https://unique.network/",
+  "license": "MIT",
+  "scripts": {
+    "prepublish": "tsc -d"
+  },
+  "peerDependencies": {
+    "@polkadot/api": "TODO",
+    "@polkadot/types": "TODO"
+  },
+  "devDependencies": {
+    "@polkadot/api": "TODO",
+    "@polkadot/types": "TODO",
+    "ts-node": "TODO",
+    "typescript": "TODO"
+  }
+}
addedtests/scripts/types_template/tsconfig.jsondiffbeforeafterboth
--- /dev/null
+++ b/tests/scripts/types_template/tsconfig.json
@@ -0,0 +1,28 @@
+{
+	"exclude": [
+		"node_modules",
+		"node_modules/**/*",
+		"../node_modules/**/*",
+		"**/node_modules/**/*"
+	],
+	"compilerOptions": {
+		"target": "ES2020",
+		"moduleResolution": "node",
+		"esModuleInterop": true,
+		"resolveJsonModule": true,
+		"module": "commonjs",
+		"sourceMap": true,
+		"outDir": ".",
+		"rootDir": ".",
+		"strict": true,
+		"paths": {
+		},
+		"skipLibCheck": true,
+	},
+	"include": [
+		"**/*",
+	],
+	"lib": [
+		"es2017"
+	],
+}
modifiedtests/scripts/wait_for_first_block.shdiffbeforeafterboth
--- a/tests/scripts/wait_for_first_block.sh
+++ b/tests/scripts/wait_for_first_block.sh
@@ -1,15 +1,11 @@
 #!/usr/bin/env bash
 
-function do_rpc {
-	curl -s --header "Content-Type: application/json" -XPOST --data "{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"$1\",\"params\":[$2]}" $RPC_URL
-}
+DIR=$(dirname "$0")
+
+. $DIR/functions.sh
 
 function is_started {
-    block_hash_rpc=$(do_rpc chain_getFinalizedHead)
-    echo Rpc response = $block_hash_rpc
-	block_hash=$(echo $block_hash_rpc | jq -r .result)
-	echo Head = $block_hash
-	block_id_hex=$(do_rpc chain_getHeader "\"$block_hash\"" | jq -r .result.number)
+	block_id_hex=$(do_rpc chain_getHeader | jq -r .result.number)
 	block_id=$((${block_id_hex}))
 	echo Id = $block_id
 	if (( $block_id > 1 )); then
addedtests/src/apiConsts.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/apiConsts.test.ts
@@ -0,0 +1,120 @@
+// 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 {ApiPromise} from '@polkadot/api';
+import {ApiBase} from '@polkadot/api/base';
+import {usingPlaygrounds, itSub, expect} from './util';
+
+
+const MAX_COLLECTION_DESCRIPTION_LENGTH = 256n;
+const MAX_COLLECTION_NAME_LENGTH = 64n;
+const COLLECTION_ADMINS_LIMIT = 5n;
+const MAX_COLLECTION_PROPERTIES_SIZE = 40960n;
+const MAX_TOKEN_PREFIX_LENGTH = 16n;
+const MAX_PROPERTY_KEY_LENGTH = 256n;
+const MAX_PROPERTY_VALUE_LENGTH = 32768n;
+const MAX_PROPERTIES_PER_ITEM = 64n;
+const MAX_TOKEN_PROPERTIES_SIZE = 32768n;
+const NESTING_BUDGET = 5n;
+
+const DEFAULT_COLLETCTION_LIMIT = {
+  accountTokenOwnershipLimit: '1,000,000',
+  sponsoredDataSize: '2,048',
+  sponsoredDataRateLimit: 'SponsoringDisabled',
+  tokenLimit: '4,294,967,295',
+  sponsorTransferTimeout: '5',
+  sponsorApproveTimeout: '5',
+  ownerCanTransfer: false,
+  ownerCanDestroy: true,
+  transfersEnabled: true,
+};
+
+const EVM_COLLECTION_HELPERS_ADDRESS = '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f';
+const HELPERS_CONTRACT_ADDRESS = '0x842899ECF380553E8a4de75bF534cdf6fBF64049';
+
+describe('integration test: API UNIQUE consts', () => {
+  let api: ApiPromise;
+  
+  before(async () => {
+    await usingPlaygrounds(async (helper) => {
+      api = await helper.getApi();
+    });
+  });
+  
+  itSub('DEFAULT_NFT_COLLECTION_LIMITS', () => {
+    expect(api.consts.unique.nftDefaultCollectionLimits.toHuman()).to.deep.equal(DEFAULT_COLLETCTION_LIMIT);
+  });
+  
+  itSub('DEFAULT_RFT_COLLECTION_LIMITS', () => {
+    expect(api.consts.unique.rftDefaultCollectionLimits.toHuman()).to.deep.equal(DEFAULT_COLLETCTION_LIMIT);
+  });
+  
+  itSub('DEFAULT_FT_COLLECTION_LIMITS', () => {
+    expect(api.consts.unique.ftDefaultCollectionLimits.toHuman()).to.deep.equal(DEFAULT_COLLETCTION_LIMIT);
+  });
+  
+  itSub('MAX_COLLECTION_NAME_LENGTH', () => {
+    checkConst(api.consts.unique.maxCollectionNameLength, MAX_COLLECTION_NAME_LENGTH);
+  });
+  
+  itSub('MAX_COLLECTION_DESCRIPTION_LENGTH', () => {
+    checkConst(api.consts.unique.maxCollectionDescriptionLength, MAX_COLLECTION_DESCRIPTION_LENGTH);
+  });
+  
+  itSub('MAX_COLLECTION_PROPERTIES_SIZE', () => {
+    checkConst(api.consts.unique.maxCollectionPropertiesSize, MAX_COLLECTION_PROPERTIES_SIZE);
+  });
+
+  itSub('MAX_TOKEN_PREFIX_LENGTH', () => {
+    checkConst(api.consts.unique.maxTokenPrefixLength, MAX_TOKEN_PREFIX_LENGTH);
+  });
+
+  itSub('MAX_PROPERTY_KEY_LENGTH', () => {
+    checkConst(api.consts.unique.maxPropertyKeyLength, MAX_PROPERTY_KEY_LENGTH);
+  });
+  
+  itSub('MAX_PROPERTY_VALUE_LENGTH', () => {
+    checkConst(api.consts.unique.maxPropertyValueLength, MAX_PROPERTY_VALUE_LENGTH);
+  });
+  
+  itSub('MAX_PROPERTIES_PER_ITEM', () => {
+    checkConst(api.consts.unique.maxPropertiesPerItem, MAX_PROPERTIES_PER_ITEM);
+  });
+  
+  itSub('NESTING_BUDGET', () => {
+    checkConst(api.consts.unique.nestingBudget, NESTING_BUDGET);
+  });
+  
+  itSub('MAX_TOKEN_PROPERTIES_SIZE', () => {
+    checkConst(api.consts.unique.maxTokenPropertiesSize, MAX_TOKEN_PROPERTIES_SIZE);
+  });
+  
+  itSub('COLLECTION_ADMINS_LIMIT', () => {
+    checkConst(api.consts.unique.collectionAdminsLimit, COLLECTION_ADMINS_LIMIT);
+  });
+  
+  itSub('HELPERS_CONTRACT_ADDRESS', () => {
+    expect(api.consts.evmContractHelpers.contractAddress.toString().toLowerCase()).to.be.equal(HELPERS_CONTRACT_ADDRESS.toLowerCase());
+  });
+  
+  itSub('EVM_COLLECTION_HELPERS_ADDRESS', () => {
+    expect(api.consts.common.contractAddress.toString().toLowerCase()).to.be.equal(EVM_COLLECTION_HELPERS_ADDRESS.toLowerCase());
+  });
+});
+
+function checkConst<T>(constValue: any, expectedValue: T) {
+  expect(constValue.toBigInt()).equal(expectedValue);
+}
\ No newline at end of file
modifiedtests/src/burnItem.test.tsdiffbeforeafterboth
--- a/tests/src/burnItem.test.ts
+++ b/tests/src/burnItem.test.ts
@@ -140,6 +140,31 @@
     await expect(token.burn(bob)).to.be.rejectedWith('common.NoPermission');
   });
 
+  itSub.ifWithPallets('RFT: cannot burn non-owned token pieces', [Pallets.ReFungible], async ({helper}) => {
+    const collection = await helper.rft.mintCollection(alice);
+    const aliceToken = await collection.mintToken(alice, 10n, {Substrate: alice.address});
+    const bobToken = await collection.mintToken(alice, 10n, {Substrate: bob.address});
+
+    // 1. Cannot burn non-owned token:
+    await expect(bobToken.burn(alice, 0n)).to.be.rejectedWith('common.TokenValueTooLow');
+    await expect(bobToken.burn(alice, 5n)).to.be.rejectedWith('common.TokenValueTooLow');
+    // 2. Cannot burn non-existing token:
+    await expect(helper.rft.burnToken(alice, 99999, 10)).to.be.rejectedWith('common.CollectionNotFound');
+    await expect(helper.rft.burnToken(alice, collection.collectionId, 99999)).to.be.rejectedWith('common.TokenValueTooLow');
+    // 3. Can burn zero amount of owned tokens (EIP-20)
+    await aliceToken.burn(alice, 0n);
+
+    // 4. Storage is not corrupted:
+    expect(await aliceToken.getTop10Owners()).to.deep.eq([{Substrate: alice.address}]);
+    expect(await bobToken.getTop10Owners()).to.deep.eq([{Substrate: bob.address}]);
+
+    // 4.1 Tokens can be transfered:
+    await aliceToken.transfer(alice, {Substrate: bob.address}, 10n);
+    await bobToken.transfer(bob, {Substrate: alice.address}, 10n);
+    expect(await aliceToken.getTop10Owners()).to.deep.eq([{Substrate: bob.address}]);
+    expect(await bobToken.getTop10Owners()).to.deep.eq([{Substrate: alice.address}]);
+  });
+
   itSub('Transfer a burned token', async ({helper}) => {
     const collection = await helper.nft.mintCollection(alice);
     const token = await collection.mintToken(alice);
@@ -155,4 +180,48 @@
     await expect(collection.burnTokens(alice, 11n)).to.be.rejectedWith('common.TokenValueTooLow');
     expect(await collection.getBalance({Substrate: alice.address})).to.eq(10n);
   });
+
+  itSub('Zero burn NFT', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {name: 'Coll', description: 'Desc', tokenPrefix: 'T'});
+    const tokenAlice = await collection.mintToken(alice, {Substrate: alice.address});
+    const tokenBob = await collection.mintToken(alice, {Substrate: bob.address});
+    
+    // 1. Zero burn of own tokens allowed:
+    await helper.executeExtrinsic(alice, 'api.tx.unique.burnItem', [collection.collectionId, tokenAlice.tokenId, 0]);
+    // 2. Zero burn of non-owned tokens not allowed:
+    await expect(helper.executeExtrinsic(alice, 'api.tx.unique.burnItem', [collection.collectionId, tokenBob.tokenId, 0])).to.be.rejectedWith('common.NoPermission');
+    // 3. Zero burn of non-existing tokens not allowed:
+    await expect(helper.executeExtrinsic(alice, 'api.tx.unique.burnItem', [collection.collectionId, 9999, 0])).to.be.rejectedWith('common.TokenNotFound');
+    expect(await tokenAlice.doesExist()).to.be.true;
+    expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: alice.address});
+    expect(await tokenBob.getOwner()).to.deep.eq({Substrate: bob.address});
+    // 4. Storage is not corrupted:
+    await tokenAlice.transfer(alice, {Substrate: bob.address});
+    await tokenBob.transfer(bob, {Substrate: alice.address});
+    expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: bob.address});
+    expect(await tokenBob.getOwner()).to.deep.eq({Substrate: alice.address});
+  });
+
+  itSub('zero burnFrom NFT', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {name: 'Zero', description: 'Zero transfer', tokenPrefix: 'TF'});
+    const notApprovedNft = await collection.mintToken(alice, {Substrate: bob.address});
+    const approvedNft = await collection.mintToken(alice, {Substrate: bob.address});
+    await approvedNft.approve(bob, {Substrate: alice.address});
+
+    // 1. Zero burnFrom of non-existing tokens not allowed:
+    await expect(helper.executeExtrinsic(alice, 'api.tx.unique.burnFrom', [collection.collectionId, {Substrate: bob.address}, 9999, 0])).to.be.rejectedWith('common.ApprovedValueTooLow');
+    // 2. Zero burnFrom of not approved tokens not allowed:
+    await expect(helper.executeExtrinsic(alice, 'api.tx.unique.burnFrom', [collection.collectionId, {Substrate: bob.address}, notApprovedNft.tokenId, 0])).to.be.rejectedWith('common.ApprovedValueTooLow');
+    // 3. Zero burnFrom of approved tokens allowed:
+    await helper.executeExtrinsic(alice, 'api.tx.unique.burnFrom', [collection.collectionId, {Substrate: bob.address}, approvedNft.tokenId, 0]);
+
+    // 4.1 approvedNft still approved:
+    expect(await approvedNft.isApproved({Substrate: alice.address})).to.be.true;
+    // 4.2 bob is still the owner:
+    expect(await approvedNft.getOwner()).to.deep.eq({Substrate: bob.address});
+    expect(await notApprovedNft.getOwner()).to.deep.eq({Substrate: bob.address});
+    // 4.3 Alice can burn approved nft:
+    await approvedNft.burnFrom(alice, {Substrate: bob.address});
+    expect(await approvedNft.doesExist()).to.be.false;
+  });
 });
modifiedtests/src/eth/abi/collectionHelpers.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/collectionHelpers.json
+++ b/tests/src/eth/abi/collectionHelpers.json
@@ -32,6 +32,15 @@
     "type": "event"
   },
   {
+    "inputs": [
+      { "internalType": "uint32", "name": "collectionId", "type": "uint32" }
+    ],
+    "name": "collectionAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
     "inputs": [],
     "name": "collectionCreationFee",
     "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
@@ -40,6 +49,19 @@
   },
   {
     "inputs": [
+      {
+        "internalType": "address",
+        "name": "collectionAddress",
+        "type": "address"
+      }
+    ],
+    "name": "collectionId",
+    "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
       { "internalType": "string", "name": "name", "type": "string" },
       { "internalType": "uint8", "name": "decimals", "type": "uint8" },
       { "internalType": "string", "name": "description", "type": "string" },
modifiedtests/src/eth/abi/fungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/fungible.json
+++ b/tests/src/eth/abi/fungible.json
@@ -95,9 +95,17 @@
   },
   {
     "inputs": [
-      { "internalType": "address", "name": "user", "type": "address" }
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct EthCrossAccount",
+        "name": "user",
+        "type": "tuple"
+      }
     ],
-    "name": "allowed",
+    "name": "allowlistedCross",
     "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
     "stateMutability": "view",
     "type": "function"
@@ -193,6 +201,13 @@
   },
   {
     "inputs": [],
+    "name": "collectionHelperAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
     "name": "collectionOwner",
     "outputs": [
       {
modifiedtests/src/eth/abi/nonFungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/nonFungible.json
+++ b/tests/src/eth/abi/nonFungible.json
@@ -116,9 +116,17 @@
   },
   {
     "inputs": [
-      { "internalType": "address", "name": "user", "type": "address" }
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct EthCrossAccount",
+        "name": "user",
+        "type": "tuple"
+      }
     ],
-    "name": "allowed",
+    "name": "allowlistedCross",
     "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
     "stateMutability": "view",
     "type": "function"
@@ -223,6 +231,13 @@
   },
   {
     "inputs": [],
+    "name": "collectionHelperAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
     "name": "collectionOwner",
     "outputs": [
       {
@@ -440,6 +455,26 @@
   {
     "inputs": [
       { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string[]", "name": "keys", "type": "string[]" }
+    ],
+    "name": "properties",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          { "internalType": "bytes", "name": "value", "type": "bytes" }
+        ],
+        "internalType": "struct Property[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
       { "internalType": "string", "name": "key", "type": "string" }
     ],
     "name": "property",
@@ -662,26 +697,6 @@
     ],
     "name": "tokenOfOwnerByIndex",
     "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "string[]", "name": "keys", "type": "string[]" }
-    ],
-    "name": "tokenProperties",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          { "internalType": "bytes", "name": "value", "type": "bytes" }
-        ],
-        "internalType": "struct Property[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
     "stateMutability": "view",
     "type": "function"
   },
modifiedtests/src/eth/abi/reFungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/reFungible.json
+++ b/tests/src/eth/abi/reFungible.json
@@ -116,9 +116,17 @@
   },
   {
     "inputs": [
-      { "internalType": "address", "name": "user", "type": "address" }
+      {
+        "components": [
+          { "internalType": "address", "name": "eth", "type": "address" },
+          { "internalType": "uint256", "name": "sub", "type": "uint256" }
+        ],
+        "internalType": "struct EthCrossAccount",
+        "name": "user",
+        "type": "tuple"
+      }
     ],
-    "name": "allowed",
+    "name": "allowlistedCross",
     "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
     "stateMutability": "view",
     "type": "function"
@@ -205,6 +213,13 @@
   },
   {
     "inputs": [],
+    "name": "collectionHelperAddress",
+    "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [],
     "name": "collectionOwner",
     "outputs": [
       {
@@ -422,6 +437,26 @@
   {
     "inputs": [
       { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
+      { "internalType": "string[]", "name": "keys", "type": "string[]" }
+    ],
+    "name": "properties",
+    "outputs": [
+      {
+        "components": [
+          { "internalType": "string", "name": "key", "type": "string" },
+          { "internalType": "bytes", "name": "value", "type": "bytes" }
+        ],
+        "internalType": "struct Property[]",
+        "name": "",
+        "type": "tuple[]"
+      }
+    ],
+    "stateMutability": "view",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
       { "internalType": "string", "name": "key", "type": "string" }
     ],
     "name": "property",
@@ -653,26 +688,6 @@
     ],
     "name": "tokenOfOwnerByIndex",
     "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
-    "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "uint256", "name": "tokenId", "type": "uint256" },
-      { "internalType": "string[]", "name": "keys", "type": "string[]" }
-    ],
-    "name": "tokenProperties",
-    "outputs": [
-      {
-        "components": [
-          { "internalType": "string", "name": "key", "type": "string" },
-          { "internalType": "bytes", "name": "value", "type": "bytes" }
-        ],
-        "internalType": "struct Property[]",
-        "name": "",
-        "type": "tuple[]"
-      }
-    ],
     "stateMutability": "view",
     "type": "function"
   },
modifiedtests/src/eth/allowlist.test.tsdiffbeforeafterboth
--- a/tests/src/eth/allowlist.test.ts
+++ b/tests/src/eth/allowlist.test.ts
@@ -78,32 +78,61 @@
   itEth('Collection allowlist can be added and removed by [eth] address', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
     const user = helper.eth.createAccount();
-
+    const crossUser = helper.ethCrossAccount.fromAddress(user);
+    
     const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
 
-    expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.false;
+    expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;
     await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});
-    expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.true;
+    expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.true;
 
     await collectionEvm.methods.removeFromCollectionAllowList(user).send({from: owner});
-    expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.false;
+    expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;
   });
 
   itEth('Collection allowlist can be added and removed by [cross] address', async ({helper}) => {
-    const owner = await helper.eth.createAccountWithBalance(donor);
-    const user = donor;
+    const owner = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
+    const [userSub] = await helper.arrange.createAccounts([10n], donor);
+    const userEth = await helper.eth.createAccountWithBalance(donor);
     
     const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-    const userCross = helper.ethCrossAccount.fromKeyringPair(user);
+    const userCrossSub = helper.ethCrossAccount.fromKeyringPair(userSub);
+    const userCrossEth = helper.ethCrossAccount.fromAddress(userEth);
+    const ownerCrossEth = helper.ethCrossAccount.fromAddress(owner);
+    
+    // Can addToCollectionAllowListCross:
+    expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;
+    await collectionEvm.methods.addToCollectionAllowListCross(userCrossSub).send({from: owner});
+    await collectionEvm.methods.addToCollectionAllowListCross(userCrossEth).send({from: owner});
+    await collectionEvm.methods.addToCollectionAllowListCross(ownerCrossEth).send({from: owner});
+    expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.true;
+    expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.true;
+    expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.true;
+    expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.true;
+
+    await collectionEvm.methods.mint(userEth).send(); // token #1
+    await collectionEvm.methods.mint(userEth).send(); // token #2
+    await collectionEvm.methods.setCollectionAccess(1).send();
     
-    expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;
-    await collectionEvm.methods.addToCollectionAllowListCross(userCross).send({from: owner});
-    expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.true;
+    // allowlisted account can transfer and transferCross:
+    await collectionEvm.methods.transfer(owner, 1).send({from: userEth});
+    await collectionEvm.methods.transferCross(userCrossSub, 2).send({from: userEth});
+    expect(await helper.nft.getTokenOwner(collectionId, 1)).to.deep.eq({Ethereum: owner});
+    expect(await helper.nft.getTokenOwner(collectionId, 2)).to.deep.eq({Substrate: userSub.address});
     
-    await collectionEvm.methods.removeFromCollectionAllowListCross(userCross).send({from: owner});
-    expect(await helper.collection.allowed(collectionId, {Substrate: user.address})).to.be.false;
+    // can removeFromCollectionAllowListCross:
+    await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossSub).send({from: owner});
+    await collectionEvm.methods.removeFromCollectionAllowListCross(userCrossEth).send({from: owner});
+    expect(await helper.collection.allowed(collectionId, {Substrate: userSub.address})).to.be.false;
+    expect(await helper.collection.allowed(collectionId, {Ethereum: userEth})).to.be.false;
+    expect(await collectionEvm.methods.allowlistedCross(userCrossSub).call({from: owner})).to.be.false;
+    expect(await collectionEvm.methods.allowlistedCross(userCrossEth).call({from: owner})).to.be.false;
+
+    // cannot transfer anymore
+    await collectionEvm.methods.mint(userEth).send();
+    await expect(collectionEvm.methods.transfer(owner, 2).send({from: userEth})).to.be.rejectedWith(/Transaction has been reverted/);
   });
 
   // Soft-deprecated
@@ -111,17 +140,18 @@
     const owner = await helper.eth.createAccountWithBalance(donor);
     const notOwner = await helper.eth.createAccountWithBalance(donor);
     const user = helper.eth.createAccount();
+    const crossUser = helper.ethCrossAccount.fromAddress(user);
 
     const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
 
-    expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.false;
+    expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;
     await expect(collectionEvm.methods.addToCollectionAllowList(user).call({from: notOwner})).to.be.rejectedWith('NoPermission');
-    expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.false;
+    expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.false;
     await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});
-    expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.true;
+    expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.true;
     await expect(collectionEvm.methods.removeFromCollectionAllowList(user).call({from: notOwner})).to.be.rejectedWith('NoPermission');
-    expect(await collectionEvm.methods.allowed(user).call({from: owner})).to.be.true;
+    expect(await collectionEvm.methods.allowlistedCross(crossUser).call({from: owner})).to.be.true;
   });
 
   itEth('Collection allowlist can not be add and remove [cross] address by not owner', async ({helper}) => {
modifiedtests/src/eth/api/CollectionHelpers.soldiffbeforeafterboth
--- a/tests/src/eth/api/CollectionHelpers.sol
+++ b/tests/src/eth/api/CollectionHelpers.sol
@@ -19,7 +19,7 @@
 }
 
 /// @title Contract, which allows users to operate with collections
-/// @dev the ERC-165 identifier for this interface is 0x7dea03b1
+/// @dev the ERC-165 identifier for this interface is 0xe65011aa
 interface CollectionHelpers is Dummy, ERC165, CollectionHelpersEvents {
 	/// Create an NFT collection
 	/// @param name Name of the collection
@@ -78,4 +78,18 @@
 	/// @dev EVM selector for this function is: 0xd23a7ab1,
 	///  or in textual repr: collectionCreationFee()
 	function collectionCreationFee() external view returns (uint256);
+
+	/// Returns address of a collection.
+	/// @param collectionId  - CollectionId  of the collection
+	/// @return eth mirror address of the collection
+	/// @dev EVM selector for this function is: 0x2e716683,
+	///  or in textual repr: collectionAddress(uint32)
+	function collectionAddress(uint32 collectionId) external view returns (address);
+
+	/// Returns collectionId of a collection.
+	/// @param collectionAddress  - Eth address of the collection
+	/// @return collectionId of the collection
+	/// @dev EVM selector for this function is: 0xb5cb7498,
+	///  or in textual repr: collectionId(address)
+	function collectionId(address collectionAddress) external view returns (uint32);
 }
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -13,7 +13,7 @@
 }
 
 /// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x8b91d192
+/// @dev the ERC-165 identifier for this interface is 0xcc1d80ca
 interface Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -177,9 +177,9 @@
 	/// Checks that user allowed to operate with collection.
 	///
 	/// @param user User address to check.
-	/// @dev EVM selector for this function is: 0xd63a8e11,
-	///  or in textual repr: allowed(address)
-	function allowed(address user) external view returns (bool);
+	/// @dev EVM selector for this function is: 0x91b6df49,
+	///  or in textual repr: allowlistedCross((address,uint256))
+	function allowlistedCross(EthCrossAccount memory user) external view returns (bool);
 
 	// /// Add the user to the allowed list.
 	// ///
@@ -354,7 +354,7 @@
 	event Approval(address indexed owner, address indexed spender, uint256 value);
 }
 
-/// @dev the ERC-165 identifier for this interface is 0x942e8b22
+/// @dev the ERC-165 identifier for this interface is 0x8cb847c4
 interface ERC20 is Dummy, ERC165, ERC20Events {
 	/// @dev EVM selector for this function is: 0x06fdde03,
 	///  or in textual repr: name()
@@ -395,6 +395,11 @@
 	/// @dev EVM selector for this function is: 0xdd62ed3e,
 	///  or in textual repr: allowance(address,address)
 	function allowance(address owner, address spender) external view returns (uint256);
+
+	/// @notice Returns collection helper contract address
+	/// @dev EVM selector for this function is: 0x1896cce6,
+	///  or in textual repr: collectionHelperAddress()
+	function collectionHelperAddress() external view returns (address);
 }
 
 interface UniqueFungible is Dummy, ERC165, ERC20, ERC20Mintable, ERC20UniqueExtensions, Collection {}
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -80,7 +80,7 @@
 }
 
 /// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x8b91d192
+/// @dev the ERC-165 identifier for this interface is 0xcc1d80ca
 interface Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -244,9 +244,9 @@
 	/// Checks that user allowed to operate with collection.
 	///
 	/// @param user User address to check.
-	/// @dev EVM selector for this function is: 0xd63a8e11,
-	///  or in textual repr: allowed(address)
-	function allowed(address user) external view returns (bool);
+	/// @dev EVM selector for this function is: 0x91b6df49,
+	///  or in textual repr: allowlistedCross((address,uint256))
+	function allowlistedCross(EthCrossAccount memory user) external view returns (bool);
 
 	// /// Add the user to the allowed list.
 	// ///
@@ -446,7 +446,7 @@
 }
 
 /// @title Unique extensions for ERC721.
-/// @dev the ERC-165 identifier for this interface is 0xb8f094a0
+/// @dev the ERC-165 identifier for this interface is 0xb74c26b7
 interface ERC721UniqueExtensions is Dummy, ERC165 {
 	/// @notice A descriptive name for a collection of NFTs in this contract
 	/// @dev EVM selector for this function is: 0x06fdde03,
@@ -475,9 +475,9 @@
 	/// @param tokenId Id for the token.
 	/// @param keys Properties keys. Empty keys for all propertyes.
 	/// @return Vector of properties key/value pairs.
-	/// @dev EVM selector for this function is: 0xefc26c69,
-	///  or in textual repr: tokenProperties(uint256,string[])
-	function tokenProperties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory);
+	/// @dev EVM selector for this function is: 0xe07ede7e,
+	///  or in textual repr: properties(uint256,string[])
+	function properties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory);
 
 	/// @notice Set or reaffirm the approved address for an NFT
 	/// @dev The zero address indicates there is no approved address.
@@ -605,7 +605,7 @@
 
 /// @title ERC-721 Non-Fungible Token Standard
 /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
+/// @dev the ERC-165 identifier for this interface is 0x983a942b
 interface ERC721 is Dummy, ERC165, ERC721Events {
 	/// @notice Count all NFTs assigned to an owner
 	/// @dev NFTs assigned to the zero address are considered invalid, and this
@@ -685,6 +685,11 @@
 	/// @dev EVM selector for this function is: 0xe985e9c5,
 	///  or in textual repr: isApprovedForAll(address,address)
 	function isApprovedForAll(address owner, address operator) external view returns (address);
+
+	/// @notice Returns collection helper contract address
+	/// @dev EVM selector for this function is: 0x1896cce6,
+	///  or in textual repr: collectionHelperAddress()
+	function collectionHelperAddress() external view returns (address);
 }
 
 interface UniqueNFT is
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungible.sol
+++ b/tests/src/eth/api/UniqueRefungible.sol
@@ -80,7 +80,7 @@
 }
 
 /// @title A contract that allows you to work with collections.
-/// @dev the ERC-165 identifier for this interface is 0x8b91d192
+/// @dev the ERC-165 identifier for this interface is 0xcc1d80ca
 interface Collection is Dummy, ERC165 {
 	// /// Set collection property.
 	// ///
@@ -244,9 +244,9 @@
 	/// Checks that user allowed to operate with collection.
 	///
 	/// @param user User address to check.
-	/// @dev EVM selector for this function is: 0xd63a8e11,
-	///  or in textual repr: allowed(address)
-	function allowed(address user) external view returns (bool);
+	/// @dev EVM selector for this function is: 0x91b6df49,
+	///  or in textual repr: allowlistedCross((address,uint256))
+	function allowlistedCross(EthCrossAccount memory user) external view returns (bool);
 
 	// /// Add the user to the allowed list.
 	// ///
@@ -444,7 +444,7 @@
 }
 
 /// @title Unique extensions for ERC721.
-/// @dev the ERC-165 identifier for this interface is 0x1d4b64d6
+/// @dev the ERC-165 identifier for this interface is 0x12f7d6c1
 interface ERC721UniqueExtensions is Dummy, ERC165 {
 	/// @notice A descriptive name for a collection of NFTs in this contract
 	/// @dev EVM selector for this function is: 0x06fdde03,
@@ -473,9 +473,9 @@
 	/// @param tokenId Id for the token.
 	/// @param keys Properties keys. Empty keys for all propertyes.
 	/// @return Vector of properties key/value pairs.
-	/// @dev EVM selector for this function is: 0xefc26c69,
-	///  or in textual repr: tokenProperties(uint256,string[])
-	function tokenProperties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory);
+	/// @dev EVM selector for this function is: 0xe07ede7e,
+	///  or in textual repr: properties(uint256,string[])
+	function properties(uint256 tokenId, string[] memory keys) external view returns (Property[] memory);
 
 	/// @notice Transfer ownership of an RFT
 	/// @dev Throws unless `msg.sender` is the current owner. Throws if `to`
@@ -604,7 +604,7 @@
 
 /// @title ERC-721 Non-Fungible Token Standard
 /// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
-/// @dev the ERC-165 identifier for this interface is 0x58800161
+/// @dev the ERC-165 identifier for this interface is 0x4016cd87
 interface ERC721 is Dummy, ERC165, ERC721Events {
 	/// @notice Count all RFTs assigned to an owner
 	/// @dev RFTs assigned to the zero address are considered invalid, and this
@@ -682,6 +682,11 @@
 	/// @dev EVM selector for this function is: 0xe985e9c5,
 	///  or in textual repr: isApprovedForAll(address,address)
 	function isApprovedForAll(address owner, address operator) external view returns (address);
+
+	/// @notice Returns collection helper contract address
+	/// @dev EVM selector for this function is: 0x1896cce6,
+	///  or in textual repr: collectionHelperAddress()
+	function collectionHelperAddress() external view returns (address);
 }
 
 interface UniqueRefungible is
modifiedtests/src/eth/base.test.tsdiffbeforeafterboth
--- a/tests/src/eth/base.test.ts
+++ b/tests/src/eth/base.test.ts
@@ -117,7 +117,7 @@
   });
 
   itEth('ERC721UniqueExtensions support', async ({helper}) => {
-    await checkInterface(helper, '0xb8f094a0', true, true);
+    await checkInterface(helper, '0xb74c26b7', true, true);
   });
 
   itEth('ERC721Burnable - 0x42966c68 - support', async ({helper}) => {
modifiedtests/src/eth/collectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/eth/collectionAdmin.test.ts
+++ b/tests/src/eth/collectionAdmin.test.ts
@@ -39,80 +39,98 @@
     });
   });
 
-  // Soft-deprecated
-  itEth('Add admin by owner', async ({helper}) => {
+  itEth('can add account admin by owner', async ({helper, privateKey}) => {
+    // arrange
     const owner = await helper.eth.createAccountWithBalance(donor);
+    const adminSub = await privateKey('//admin2');
+    const adminEth = helper.eth.createAccount().toLowerCase();
+
+    const adminDeprecated = helper.eth.createAccount().toLowerCase();
+    const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
+    const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
+        
     const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
 
-    const newAdmin = helper.eth.createAccount();
+    // Soft-deprecated: can addCollectionAdmin 
+    await collectionEvm.methods.addCollectionAdmin(adminDeprecated).send();
+    // Can addCollectionAdminCross for substrate and ethereum address
+    await collectionEvm.methods.addCollectionAdminCross(adminCrossSub).send();
+    await collectionEvm.methods.addCollectionAdminCross(adminCrossEth).send();
 
-    await collectionEvm.methods.addCollectionAdmin(newAdmin).send();
-    const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
-    expect(adminList[0].asEthereum.toString().toLocaleLowerCase())
-      .to.be.eq(newAdmin.toLocaleLowerCase());
+    // 1. Expect api.rpc.unique.adminlist returns admins:
+    const adminListRpc = await helper.collection.getAdmins(collectionId);
+    expect(adminListRpc).to.has.length(3);
+    expect(adminListRpc).to.be.deep.contain.members([{Substrate: adminSub.address}, {Ethereum: adminEth}, {Ethereum: adminDeprecated}]);
+
+    // 2. Expect methods.collectionAdmins == api.rpc.unique.adminlist
+    let adminListEth = await collectionEvm.methods.collectionAdmins().call();
+    adminListEth = adminListEth.map((element: IEthCrossAccountId) => {
+      return helper.address.convertCrossAccountFromEthCrossAccount(element);
+    });
+    expect(adminListRpc).to.be.like(adminListEth);
   });
 
-  itEth('Add cross account admin by owner', async ({helper, privateKey}) => {
+  itEth('cross account admin can mint', async ({helper}) => {
+    // arrange: create collection and accounts
     const owner = await helper.eth.createAccountWithBalance(donor);
-        
-    const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+    const {collectionAddress, collectionId} = await helper.eth.createERC721MetadataCompatibleNFTCollection(owner, 'Mint collection', 'a', 'b', 'uri');
+    const adminEth = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
+    const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
+    const [adminSub] = await helper.arrange.createAccounts([100n], donor);
+    const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+    
+    // cannot mint while not admin
+    await expect(collectionEvm.methods.mint(owner).send({from: adminEth})).to.be.rejected;
+    await expect(helper.nft.mintToken(adminSub, {collectionId, owner: {Ethereum: owner}})).to.be.rejectedWith(/common.PublicMintingNotAllowed/);
     
-    const newAdmin = await privateKey('//Bob');
-    const newAdminCross = helper.ethCrossAccount.fromKeyringPair(newAdmin);
-    await collectionEvm.methods.addCollectionAdminCross(newAdminCross).send();
+    // admin (sub and eth) can mint token:
+    await collectionEvm.methods.addCollectionAdminCross(adminCrossEth).send();
+    await collectionEvm.methods.addCollectionAdminCross(adminCrossSub).send();
+    await collectionEvm.methods.mint(owner).send({from: adminEth});
+    await helper.nft.mintToken(adminSub, {collectionId, owner: {Ethereum: owner}});
 
-    const adminList = await helper.collection.getAdmins(collectionId);
-    expect(adminList).to.be.like([{Substrate: newAdmin.address}]);
+    expect(await helper.collection.getLastTokenId(collectionId)).to.eq(2);
   });
 
-  itEth('Check adminlist', async ({helper, privateKey}) => {
+  itEth('cannot add invalid cross account admin', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
-        
-    const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
+    const [admin] = await helper.arrange.createAccounts([100n, 100n], donor);
 
-    const admin1 = helper.eth.createAccount();
-    const admin2 = await privateKey('admin');
-    const admin2Cross = helper.ethCrossAccount.fromKeyringPair(admin2);
-    
-    // Soft-deprecated
-    await collectionEvm.methods.addCollectionAdmin(admin1).send();
-    await collectionEvm.methods.addCollectionAdminCross(admin2Cross).send();
+    const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
 
-    const adminListRpc = await helper.collection.getAdmins(collectionId);
-    let adminListEth = await collectionEvm.methods.collectionAdmins().call();
-    adminListEth = adminListEth.map((element: IEthCrossAccountId) => {
-      return helper.address.convertCrossAccountFromEthCrossAcoount(element);
-    });
-    expect(adminListRpc).to.be.like(adminListEth);
+    const adminCross = {
+      eth: helper.address.substrateToEth(admin.address),
+      sub: admin.addressRaw,
+    };
+    await expect(collectionEvm.methods.addCollectionAdminCross(adminCross).send()).to.be.rejected;
   });
 
-  // Soft-deprecated
-  itEth('Verify owner or admin', async ({helper}) => {
+  itEth('can verify owner with methods.isOwnerOrAdmin[Cross]', async ({helper, privateKey}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
     const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
 
-    const newAdmin = helper.eth.createAccount();
+    const adminDeprecated = helper.eth.createAccount();
+    const admin1Cross = helper.ethCrossAccount.fromKeyringPair(await privateKey('admin'));
+    const admin2Cross = helper.ethCrossAccount.fromAddress(helper.address.substrateToEth((await privateKey('admin3')).address));
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner, true);
   
-    expect(await collectionEvm.methods.isOwnerOrAdmin(newAdmin).call()).to.be.false;
-    await collectionEvm.methods.addCollectionAdmin(newAdmin).send();
-    expect(await collectionEvm.methods.isOwnerOrAdmin(newAdmin).call()).to.be.true;
-  });
+    // Soft-deprecated:
+    expect(await collectionEvm.methods.isOwnerOrAdmin(adminDeprecated).call()).to.be.false;
+    expect(await collectionEvm.methods.isOwnerOrAdminCross(admin1Cross).call()).to.be.false;
+    expect(await collectionEvm.methods.isOwnerOrAdminCross(admin2Cross).call()).to.be.false;
 
-  itEth('Verify owner or admin cross', async ({helper, privateKey}) => {
-    const owner = await helper.eth.createAccountWithBalance(donor);
-    const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+    await collectionEvm.methods.addCollectionAdmin(adminDeprecated).send();
+    await collectionEvm.methods.addCollectionAdminCross(admin1Cross).send();
+    await collectionEvm.methods.addCollectionAdminCross(admin2Cross).send();
 
-    const newAdmin = await privateKey('admin');
-    const newAdminCross = helper.ethCrossAccount.fromKeyringPair(newAdmin);
-    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-  
-    expect(await collectionEvm.methods.isOwnerOrAdminCross(newAdminCross).call()).to.be.false;
-    await collectionEvm.methods.addCollectionAdminCross(newAdminCross).send();
-    expect(await collectionEvm.methods.isOwnerOrAdminCross(newAdminCross).call()).to.be.true;
+    // Soft-deprecated: isOwnerOrAdmin returns true
+    expect(await collectionEvm.methods.isOwnerOrAdmin(adminDeprecated).call()).to.be.true;
+    // Expect isOwnerOrAdminCross return true
+    expect(await collectionEvm.methods.isOwnerOrAdminCross(admin1Cross).call()).to.be.true;
+    expect(await collectionEvm.methods.isOwnerOrAdminCross(admin2Cross).call()).to.be.true;
   });
 
   // Soft-deprecated
@@ -154,12 +172,11 @@
     const owner = await helper.eth.createAccountWithBalance(donor);
     const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
 
-    const [admin] = await helper.arrange.createAccounts([10n], donor);
+    const [admin, notAdmin] = await helper.arrange.createAccounts([10n, 10n], donor);
     const adminCross = helper.ethCrossAccount.fromKeyringPair(admin);
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
     await collectionEvm.methods.addCollectionAdminCross(adminCross).send();
 
-    const [notAdmin] = await helper.arrange.createAccounts([10n], donor);
     const notAdminCross = helper.ethCrossAccount.fromKeyringPair(notAdmin);
     await expect(collectionEvm.methods.addCollectionAdminCross(notAdminCross).call({from: adminCross.eth}))
       .to.be.rejectedWith('NoPermission');
@@ -222,19 +239,29 @@
     const owner = await helper.eth.createAccountWithBalance(donor);
     const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
 
-    const [newAdmin] = await helper.arrange.createAccounts([10n], donor);
-    const newAdminCross = helper.ethCrossAccount.fromKeyringPair(newAdmin);
+    const [adminSub] = await helper.arrange.createAccounts([10n], donor);
+    const adminEth = (await helper.eth.createAccountWithBalance(donor)).toLowerCase();
+    const adminCrossSub = helper.ethCrossAccount.fromKeyringPair(adminSub);
+    const adminCrossEth = helper.ethCrossAccount.fromAddress(adminEth);
+
     const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
-    await collectionEvm.methods.addCollectionAdminCross(newAdminCross).send();
+    await collectionEvm.methods.addCollectionAdminCross(adminCrossSub).send();
+    await collectionEvm.methods.addCollectionAdminCross(adminCrossEth).send();
+
     {
-      const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
-      expect(adminList[0].asSubstrate.toString().toLocaleLowerCase())
-        .to.be.eq(newAdmin.address.toLocaleLowerCase());
+      const adminList = await helper.collection.getAdmins(collectionId);
+      expect(adminList).to.deep.include({Substrate: adminSub.address});
+      expect(adminList).to.deep.include({Ethereum: adminEth});
     }
 
-    await collectionEvm.methods.removeCollectionAdminCross(newAdminCross).send();
-    const adminList = await helper.callRpc('api.rpc.unique.adminlist', [collectionId]);
+    await collectionEvm.methods.removeCollectionAdminCross(adminCrossSub).send();
+    await collectionEvm.methods.removeCollectionAdminCross(adminCrossEth).send();
+    const adminList = await helper.collection.getAdmins(collectionId);
     expect(adminList.length).to.be.eq(0);
+
+    // Non admin cannot mint:
+    await expect(helper.nft.mintToken(adminSub, {collectionId, owner: {Substrate: adminSub.address}})).to.be.rejectedWith(/common.PublicMintingNotAllowed/);
+    await expect(collectionEvm.methods.mint(adminEth).send({from: adminEth})).to.be.rejected;
   });
 
   // Soft-deprecated
@@ -378,16 +405,27 @@
 
   itEth('Change owner [cross]', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
-    const [newOwner] = await helper.arrange.createAccounts([10n], donor);
-    const newOwnerCross = helper.ethCrossAccount.fromKeyringPair(newOwner);
-    const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
-    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+    const ownerEth = await helper.eth.createAccountWithBalance(donor);
+    const ownerCrossEth = helper.ethCrossAccount.fromAddress(ownerEth);
+    const [ownerSub] = await helper.arrange.createAccounts([10n], donor);
+    const ownerCrossSub = helper.ethCrossAccount.fromKeyringPair(ownerSub);
 
-    expect(await collectionEvm.methods.isOwnerOrAdminCross(newOwnerCross).call()).to.be.false;
+    const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'A', 'B', 'C');
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
 
-    await collectionEvm.methods.changeCollectionOwnerCross(newOwnerCross).send();
+    expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossSub).call()).to.be.false;
 
-    expect(await collectionEvm.methods.isOwnerOrAdminCross(newOwnerCross).call()).to.be.true;
+    // Can set ethereum owner:
+    await collectionEvm.methods.changeCollectionOwnerCross(ownerCrossEth).send({from: owner});
+    expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossEth).call()).to.be.true;
+    expect(await helper.collection.getData(collectionId))
+      .to.have.property('normalizedOwner').that.is.eq(helper.address.ethToSubstrate(ownerEth));
+    
+    // Can set Substrate owner:
+    await collectionEvm.methods.changeCollectionOwnerCross(ownerCrossSub).send({from: ownerEth});
+    expect(await collectionEvm.methods.isOwnerOrAdminCross(ownerCrossSub).call()).to.be.true;
+    expect(await helper.collection.getData(collectionId))
+      .to.have.property('normalizedOwner').that.is.eq(helper.address.normalizeSubstrate(ownerSub.address));
   });
 
   itEth.skip('change owner call fee', async ({helper}) => {
addedtests/src/eth/collectionHelperAddress.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/eth/collectionHelperAddress.test.ts
@@ -0,0 +1,72 @@
+// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
+// This file is part of Unique Network.
+
+// Unique Network is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Unique Network is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
+
+import {itEth, usingEthPlaygrounds, expect} from './util';
+import {IKeyringPair} from '@polkadot/types/types';
+import {Pallets} from '../util';
+
+const EVM_COLLECTION_HELPERS_ADDRESS = '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f';
+
+describe('[eth]CollectionHelperAddress test: ERC20/ERC721 ', () => {
+  let donor: IKeyringPair;
+
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      donor = await privateKey({filename: __filename});
+    });
+  });
+
+  itEth('NFT', async ({helper}) => {
+    const owner =  await helper.eth.createAccountWithBalance(donor);
+    
+    const {collectionAddress: nftCollectionAddress} = await helper.eth.createNFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC');
+    const nftCollection = helper.ethNativeContract.collection(nftCollectionAddress, 'nft', owner);
+    
+    expect((await nftCollection.methods.collectionHelperAddress().call())
+      .toString().toLowerCase()).to.be.equal(EVM_COLLECTION_HELPERS_ADDRESS);
+  });
+  
+  itEth.ifWithPallets('RFT ', [Pallets.ReFungible], async ({helper}) => {
+    const owner =  await helper.eth.createAccountWithBalance(donor);
+
+    const {collectionAddress: rftCollectionAddress} = await helper.eth.createRFTCollection(owner, 'Sponsor', 'absolutely anything', 'ROC');
+
+    const rftCollection = helper.ethNativeContract.collection(rftCollectionAddress, 'rft', owner);
+    expect((await rftCollection.methods.collectionHelperAddress().call())
+      .toString().toLowerCase()).to.be.equal(EVM_COLLECTION_HELPERS_ADDRESS);
+  });
+  
+  itEth('FT', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+
+    const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Sponsor', 18, 'absolutely anything', 'ROC');
+    const collection = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+    
+    expect((await collection.methods.collectionHelperAddress().call())
+      .toString().toLowerCase()).to.be.equal(EVM_COLLECTION_HELPERS_ADDRESS);
+  });
+  
+  itEth('[collectionHelpers] convert collectionId into address', async ({helper}) => {
+    const owner = await helper.eth.createAccountWithBalance(donor);
+    const collectionId = 7;
+    const collectionAddress = helper.ethAddress.fromCollectionId(collectionId);
+    const helperContract = helper.ethNativeContract.collectionHelpers(owner);
+    
+    expect(await helperContract.methods.collectionAddress(collectionId).call()).to.be.equal(collectionAddress);
+    expect(parseInt(await helperContract.methods.collectionId(collectionAddress).call())).to.be.equal(collectionId);
+  });
+ 
+});
modifiedtests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/contractSponsoring.test.ts
+++ b/tests/src/eth/contractSponsoring.test.ts
@@ -372,7 +372,7 @@
     const originalFlipperBalance = await helper.balance.getEthereum(flipper.options.address);
     expect(originalFlipperBalance).to.be.not.equal('0');
 
-    await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/InvalidTransaction::Payment/);
+    await expect(flipper.methods.flip().send({from: caller})).to.be.rejectedWith(/Returned error: insufficient funds for gas \* price \+ value/);
     expect(await flipper.methods.getValue().call()).to.be.false;
 
     // Balance should be taken from flipper instead of caller
modifiedtests/src/eth/createFTCollection.test.tsdiffbeforeafterboth
--- a/tests/src/eth/createFTCollection.test.ts
+++ b/tests/src/eth/createFTCollection.test.ts
@@ -144,7 +144,7 @@
   
   itEth('destroyCollection', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
-    const {collectionAddress} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT');
+    const {collectionAddress, collectionId} = await helper.eth.createFungibleCollection(owner, 'Exister', DECIMALS, 'absolutely anything', 'WIWT');
     const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
 
     const result = await collectionHelper.methods
@@ -166,6 +166,7 @@
     expect(await collectionHelper.methods
       .isCollectionExist(collectionAddress)
       .call()).to.be.false;
+    expect(await helper.collection.getData(collectionId)).to.be.null;
   });
 });
 
@@ -214,12 +215,15 @@
     }
   });
   
-  itEth('(!negative test!) Create collection (no funds)', async ({helper}) => {
+  itEth('(!negative test!) cannot create collection if value !== 2', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
     const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
-    await expect(collectionHelper.methods
-      .createFTCollection('Peasantry', DECIMALS, 'absolutely anything', 'TWIW')
-      .call({value: Number(1n * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
+    const expects = [0n, 1n, 30n].map(async value => {
+      await expect(collectionHelper.methods
+        .createFTCollection('Peasantry', DECIMALS, 'absolutely anything', 'TWIW')
+        .call({value: Number(value * nominal)})).to.be.rejectedWith('Sent amount not equals to collection creation price (2000000000000000000)');
+    });
+    await Promise.all(expects);
   });
 
   // Soft-deprecated
modifiedtests/src/eth/createNFTCollection.test.tsdiffbeforeafterboth
--- a/tests/src/eth/createNFTCollection.test.ts
+++ b/tests/src/eth/createNFTCollection.test.ts
@@ -308,7 +308,7 @@
 
   itEth('destroyCollection', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
-    const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
+    const {collectionAddress, collectionId} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
     const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
 
 
@@ -331,5 +331,6 @@
     expect(await collectionHelper.methods
       .isCollectionExist(collectionAddress)
       .call()).to.be.false;
+    expect(await helper.collection.getData(collectionId)).to.be.null;
   });
 });
\ No newline at end of file
modifiedtests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth
--- a/tests/src/eth/createRFTCollection.test.ts
+++ b/tests/src/eth/createRFTCollection.test.ts
@@ -340,7 +340,7 @@
   
   itEth('destroyCollection', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
-    const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
+    const {collectionAddress, collectionId} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
     const collectionHelper = helper.ethNativeContract.collectionHelpers(owner);
     
     await expect(collectionHelper.methods
@@ -349,6 +349,7 @@
     
     expect(await collectionHelper.methods
       .isCollectionExist(collectionAddress)
-      .call()).to.be.false;  
+      .call()).to.be.false;
+    expect(await helper.collection.getData(collectionId)).to.be.null;
   });
 });
modifiedtests/src/eth/destroyCollection.test.tsdiffbeforeafterboth
--- a/tests/src/eth/destroyCollection.test.ts
+++ b/tests/src/eth/destroyCollection.test.ts
@@ -15,62 +15,48 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import {IKeyringPair} from '@polkadot/types/types';
-import {Pallets, requirePalletsOrSkip} from '../util';
+import {Pallets} from '../util';
 import {expect, itEth, usingEthPlaygrounds} from './util';
 
-
-describe('Destroy Collection from EVM', () => {
+describe('Destroy Collection from EVM', function() {
   let donor: IKeyringPair;
+  const testCases = [
+    {method: 'createRFTCollection' as const, params: ['Limits', 'absolutely anything', 'OLF'], requiredPallets: [Pallets.ReFungible]},
+    {method: 'createNFTCollection' as const, params: ['Limits', 'absolutely anything', 'OLF'], requiredPallets: [Pallets.NFT]},
+    {method: 'createFTCollection' as const, params: ['Limits', 'absolutely anything', 'OLF', 18], requiredPallets: [Pallets.Fungible]},
+  ];
 
   before(async function() {
-    await usingEthPlaygrounds(async (helper, privateKey) => {
-      requirePalletsOrSkip(this, helper, [Pallets.ReFungible, Pallets.NFT]);
+    await usingEthPlaygrounds(async (_, privateKey) => {
       donor = await privateKey({filename: __filename});
     });
   });
 
-  
-  itEth('(!negative test!) RFT', async ({helper}) => {
-    const owner = await helper.eth.createAccountWithBalance(donor);
-    const signer = await helper.eth.createAccountWithBalance(donor);
-    
-    const unexistedCollection = helper.ethAddress.fromCollectionId(1000000);
-    
-    const {collectionAddress} = await helper.eth.createRFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
-    const collectionHelper = helper.ethNativeContract.collectionHelpers(signer);
-    
-    await expect(collectionHelper.methods
-      .destroyCollection(collectionAddress)
-      .send({from: signer})).to.be.rejected;
-    
-    await expect(collectionHelper.methods
-      .destroyCollection(unexistedCollection)
-      .send({from: signer})).to.be.rejected;
-    
-    expect(await collectionHelper.methods
-      .isCollectionExist(unexistedCollection)
-      .call()).to.be.false;
-  });
-  
-  itEth('(!negative test!) NFT', async ({helper}) => {
-    const owner = await helper.eth.createAccountWithBalance(donor);
-    const signer = await helper.eth.createAccountWithBalance(donor);
-    
-    const unexistedCollection = helper.ethAddress.fromCollectionId(1000000);
-    
-    const {collectionAddress} = await helper.eth.createNFTCollection(owner, 'Limits', 'absolutely anything', 'OLF');
-    const collectionHelper = helper.ethNativeContract.collectionHelpers(signer);
-    
-    await expect(collectionHelper.methods
-      .destroyCollection(collectionAddress)
-      .send({from: signer})).to.be.rejected;
-    
-    await expect(collectionHelper.methods
-      .destroyCollection(unexistedCollection)
-      .send({from: signer})).to.be.rejected;
-    
-    expect(await collectionHelper.methods
-      .isCollectionExist(unexistedCollection)
-      .call()).to.be.false;
-  });
+  testCases.map((testCase) => 
+    itEth.ifWithPallets(`Cannot burn non-owned or non-existing collection ${testCase.method}`, testCase.requiredPallets, async ({helper}) => {
+      const owner = await helper.eth.createAccountWithBalance(donor);
+      const signer = await helper.eth.createAccountWithBalance(donor);
+      
+      const unexistedCollection = helper.ethAddress.fromCollectionId(1000000);
+      
+      const collectionHelpers = helper.ethNativeContract.collectionHelpers(signer);
+      const {collectionAddress} = await helper.eth.createCollecion(testCase.method, owner, ...testCase.params as [string, string, string, number?]);
+
+      // cannot burn collec
+      await expect(collectionHelpers.methods
+        .destroyCollection(collectionAddress)
+        .send({from: signer})).to.be.rejected;
+      
+      await expect(collectionHelpers.methods
+        .destroyCollection(unexistedCollection)
+        .send({from: signer})).to.be.rejected;
+      
+      expect(await collectionHelpers.methods
+        .isCollectionExist(unexistedCollection)
+        .call()).to.be.false;
+      
+      expect(await collectionHelpers.methods
+        .isCollectionExist(collectionAddress)
+        .call()).to.be.true;
+    }));
 });
modifiedtests/src/eth/fungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/fungible.test.ts
+++ b/tests/src/eth/fungible.test.ts
@@ -232,57 +232,70 @@
   });
 
   itEth('Can perform transferCross()', async ({helper}) => {
-    const owner = await helper.eth.createAccountWithBalance(donor);
-    const receiver = await helper.eth.createAccountWithBalance(donor);
-    const to = helper.ethCrossAccount.fromAddress(receiver);
-    const toSubstrate = helper.ethCrossAccount.fromKeyringPair(donor);
+    const sender = await helper.eth.createAccountWithBalance(donor);
+    const receiverEth = await helper.eth.createAccountWithBalance(donor);
+    const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+    const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(donor);
     const collection = await helper.ft.mintCollection(alice);
-    await collection.mint(alice, 200n, {Ethereum: owner});
+    await collection.mint(alice, 200n, {Ethereum: sender});
 
     const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
-    const contract = helper.ethNativeContract.collection(collectionAddress, 'ft', owner);
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', sender);
 
     {
-      const result = await contract.methods.transferCross(to, 50).send({from: owner});
-      
+      // Can transferCross to ethereum address:
+      const result = await collectionEvm.methods.transferCross(receiverCrossEth, 50).send({from: sender});
+      // Check events:
       const event = result.events.Transfer;
       expect(event.address).to.be.equal(collectionAddress);
-      expect(event.returnValues.from).to.be.equal(owner);
-      expect(event.returnValues.to).to.be.equal(receiver);
+      expect(event.returnValues.from).to.be.equal(sender);
+      expect(event.returnValues.to).to.be.equal(receiverEth);
       expect(event.returnValues.value).to.be.equal('50');
-    }
-
-    {
-      const balance = await contract.methods.balanceOf(owner).call();
-      expect(+balance).to.equal(150);
-    }
-
-    {
-      const balance = await contract.methods.balanceOf(receiver).call();
-      expect(+balance).to.equal(50);
+      // Sender's balance decreased:
+      const ownerBalance = await collectionEvm.methods.balanceOf(sender).call();
+      expect(+ownerBalance).to.equal(150);
+      // Receiver's balance increased:
+      const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
+      expect(+receiverBalance).to.equal(50);
     }
     
     {
-      const result = await contract.methods.transferCross(toSubstrate, 50).send({from: owner});
-      
+      // Can transferCross to substrate address:
+      const result = await collectionEvm.methods.transferCross(receiverCrossSub, 50).send({from: sender});
+      // Check events:
       const event = result.events.Transfer;
       expect(event.address).to.be.equal(collectionAddress);
-      expect(event.returnValues.from).to.be.equal(owner);
+      expect(event.returnValues.from).to.be.equal(sender);
       expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(donor.address));
       expect(event.returnValues.value).to.be.equal('50');
-    }
-
-    {
-      const balance = await collection.getBalance({Ethereum: owner});
-      expect(balance).to.equal(100n);
-    }
-
-    {
+      // Sender's balance decreased:
+      const senderBalance = await collection.getBalance({Ethereum: sender});
+      expect(senderBalance).to.equal(100n);
+      // Receiver's balance increased:
       const balance = await collection.getBalance({Substrate: donor.address});
       expect(balance).to.equal(50n);
     }
-    
   });
+
+  ['transfer', 'transferCross'].map(testCase => itEth(`Cannot ${testCase} incorrect amount`, async ({helper}) => {
+    const sender = await helper.eth.createAccountWithBalance(donor);
+    const receiverEth = await helper.eth.createAccountWithBalance(donor);
+    const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+    const BALANCE = 200n;
+    const BALANCE_TO_TRANSFER = BALANCE + 100n;
+
+    const collection = await helper.ft.mintCollection(alice);
+    await collection.mint(alice, BALANCE, {Ethereum: sender});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'ft', sender);
+
+    // 1. Cannot transfer more than have
+    const receiver = testCase === 'transfer' ? receiverEth : receiverCrossEth;
+    await expect(collectionEvm.methods[testCase](receiver, BALANCE_TO_TRANSFER).send({from: sender})).to.be.rejected;
+    // 2. Zero transfer allowed (EIP-20):
+    await collectionEvm.methods[testCase](receiver, 0n).send({from: sender});
+  }));
+  
   
   itEth('Can perform transfer()', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
@@ -314,7 +327,7 @@
     }
   });
 
-  itEth('Can perform transferFromCross()', async ({helper, privateKey}) => {
+  itEth('Can perform transferFromCross()', async ({helper}) => {
     const sender = await helper.eth.createAccountWithBalance(donor, 100n);
 
     const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);
@@ -508,7 +521,7 @@
     expect(event.returnValues.value).to.be.equal('51');
   });
 
-  itEth('Events emitted for transferFromCross()', async ({helper, privateKey}) => {
+  itEth('Events emitted for transferFromCross()', async ({helper}) => {
     const sender = await helper.eth.createAccountWithBalance(donor, 100n);
 
     const collection = await helper.ft.mintCollection(owner, {name: 'A', description: 'B', tokenPrefix: 'C'}, 0);
modifiedtests/src/eth/nonFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/nonFungible.test.ts
+++ b/tests/src/eth/nonFungible.test.ts
@@ -17,7 +17,6 @@
 import {itEth, usingEthPlaygrounds, expect, EthUniqueHelper} from './util';
 import {IKeyringPair} from '@polkadot/types/types';
 import {Contract} from 'web3-eth-contract';
-import exp from 'constants';
 
 
 describe('NFT: Information getting', () => {
@@ -252,58 +251,124 @@
 
   itEth('Can perform burnFromCross()', async ({helper}) => {
     const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+    const ownerSub = bob;
+    const ownerCrossSub = helper.ethCrossAccount.fromKeyringPair(ownerSub);
+    const ownerEth = await helper.eth.createAccountWithBalance(donor, 100n);
+    const ownerCrossEth = helper.ethCrossAccount.fromAddress(ownerEth);
 
-    const owner = bob;
-    const spender = await helper.eth.createAccountWithBalance(donor, 100n);
+    const burnerEth = await helper.eth.createAccountWithBalance(donor, 100n);
+    const burnerCrossEth = helper.ethCrossAccount.fromAddress(burnerEth);
 
-    const token = await collection.mintToken(minter, {Substrate: owner.address});
+    const token1 = await collection.mintToken(minter, {Substrate: ownerSub.address});
+    const token2 = await collection.mintToken(minter, {Ethereum: ownerEth});
 
-    const address = helper.ethAddress.fromCollectionId(collection.collectionId);
-    const contract = helper.ethNativeContract.collection(address, 'nft');
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft');
 
-    {
-      await token.approve(owner, {Ethereum: spender});
-      const ownerCross = helper.ethCrossAccount.fromKeyringPair(owner);
-      const result = await contract.methods.burnFromCross(ownerCross, token.tokenId).send({from: spender});
-      const events = result.events.Transfer;
+    // Approve tokens from substrate and ethereum:
+    await token1.approve(ownerSub, {Ethereum: burnerEth});
+    await collectionEvm.methods.approveCross(burnerCrossEth, token2.tokenId).send({from: ownerEth});
 
-      expect(events).to.be.like({
-        address,
+    // can burnFromCross:
+    const result1 = await collectionEvm.methods.burnFromCross(ownerCrossSub, token1.tokenId).send({from: burnerEth});
+    const result2 = await collectionEvm.methods.burnFromCross(ownerCrossEth, token2.tokenId).send({from: burnerEth});
+    const events1 = result1.events.Transfer;
+    const events2 = result2.events.Transfer;
+
+    // Check events for burnFromCross (substrate and ethereum):
+    [
+      [events1, token1, helper.address.substrateToEth(ownerSub.address)], 
+      [events2, token2, ownerEth],
+    ].map(burnData => {
+      expect(burnData[0]).to.be.like({
+        address: collectionAddress,
         event: 'Transfer',
         returnValues: {
-          from: helper.address.substrateToEth(owner.address),
+          from: burnData[2],
           to: '0x0000000000000000000000000000000000000000',
-          tokenId: token.tokenId.toString(),
+          tokenId: burnData[1].tokenId.toString(),
         },
       });
-    }
+    });
+
+    expect(await token1.doesExist()).to.be.false;
+    expect(await token2.doesExist()).to.be.false;
   });
 
   itEth('Can perform approveCross()', async ({helper}) => {
+    // arrange: create accounts
+    const owner = await helper.eth.createAccountWithBalance(donor, 100n);
+    const ownerCross = helper.ethCrossAccount.fromAddress(owner);
+    const receiverSub = charlie;
+    const recieverCrossSub = helper.ethCrossAccount.fromKeyringPair(receiverSub);
+    const receiverEth = await helper.eth.createAccountWithBalance(donor, 100n);
+    const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+
+    // arrange: create collection and tokens:
     const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+    const token1 = await collection.mintToken(minter, {Ethereum: owner});
+    const token2 = await collection.mintToken(minter, {Ethereum: owner});
+
+    const collectionEvm = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
+
+    // Can approveCross substrate and ethereum address:
+    const resultSub = await collectionEvm.methods.approveCross(recieverCrossSub, token1.tokenId).send({from: owner});
+    const resultEth = await collectionEvm.methods.approveCross(receiverCrossEth, token2.tokenId).send({from: owner});
+    const eventSub = resultSub.events.Approval;
+    const eventEth = resultEth.events.Approval;
+    expect(eventSub).to.be.like({
+      address: helper.ethAddress.fromCollectionId(collection.collectionId),
+      event: 'Approval',
+      returnValues: {
+        owner,
+        approved: helper.address.substrateToEth(receiverSub.address),
+        tokenId: token1.tokenId.toString(),
+      },
+    });
+    expect(eventEth).to.be.like({
+      address: helper.ethAddress.fromCollectionId(collection.collectionId),
+      event: 'Approval',
+      returnValues: {
+        owner,
+        approved: receiverEth,
+        tokenId: token2.tokenId.toString(),
+      },
+    });
+
+    // Substrate address can transferFrom approved tokens:
+    await helper.nft.transferTokenFrom(receiverSub, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiverSub.address});
+    expect(await helper.nft.getTokenOwner(collection.collectionId, token1.tokenId)).to.deep.eq({Substrate: receiverSub.address});
+    // Ethereum address can transferFromCross approved tokens:
+    await collectionEvm.methods.transferFromCross(ownerCross, receiverCrossEth, token2.tokenId).send({from: receiverEth});
+    expect(await helper.nft.getTokenOwner(collection.collectionId, token2.tokenId)).to.deep.eq({Ethereum: receiverEth.toLowerCase()});
+  });
 
+  itEth('Can reaffirm approved address', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor, 100n);
-    const receiver = charlie;
+    const ownerCrossEth = helper.ethCrossAccount.fromAddress(owner);
+    const [receiver1, receiver2] = await helper.arrange.createAccounts([100n, 100n], donor);
+    const receiver1Cross = helper.ethCrossAccount.fromKeyringPair(receiver1);
+    const receiver2Cross = helper.ethCrossAccount.fromKeyringPair(receiver2);
+    const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
+    const token1 = await collection.mintToken(minter, {Ethereum: owner});
+    const token2 = await collection.mintToken(minter, {Ethereum: owner});
+    const collectionEvm = helper.ethNativeContract.collection(helper.ethAddress.fromCollectionId(collection.collectionId), 'nft');
 
-    const token = await collection.mintToken(minter, {Ethereum: owner});
+    // Can approve and reaffirm approved address:
+    await collectionEvm.methods.approveCross(receiver1Cross, token1.tokenId).send({from: owner});
+    await collectionEvm.methods.approveCross(receiver2Cross, token1.tokenId).send({from: owner});
 
-    const address = helper.ethAddress.fromCollectionId(collection.collectionId);
-    const contract = helper.ethNativeContract.collection(address, 'nft');
+    // receiver1 cannot transferFrom:
+    await expect(helper.nft.transferTokenFrom(receiver1, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiver1.address})).to.be.rejected;
+    // receiver2 can transferFrom:
+    await helper.nft.transferTokenFrom(receiver2, collection.collectionId, token1.tokenId, {Ethereum: owner}, {Substrate: receiver2.address});
 
-    {
-      const recieverCross = helper.ethCrossAccount.fromKeyringPair(receiver);
-      const result = await contract.methods.approveCross(recieverCross, token.tokenId).send({from: owner});
-      const event = result.events.Approval;
-      expect(event).to.be.like({
-        address: helper.ethAddress.fromCollectionId(collection.collectionId),
-        event: 'Approval',
-        returnValues: {
-          owner,
-          approved: helper.address.substrateToEth(receiver.address),
-          tokenId: token.tokenId.toString(),
-        },
-      });
-    }
+    // can set approved address to self address to remove approval:
+    await collectionEvm.methods.approveCross(receiver1Cross, token2.tokenId).send({from: owner});
+    await collectionEvm.methods.approveCross(ownerCrossEth, token2.tokenId).send({from: owner});
+
+    // receiver1 cannot transfer token anymore:
+    await expect(helper.nft.transferTokenFrom(receiver1, collection.collectionId, token2.tokenId, {Ethereum: owner}, {Substrate: receiver1.address})).to.be.rejected;
   });
 
   itEth('Can perform transferFrom()', async ({helper}) => {
@@ -340,13 +405,11 @@
     }
   });
 
-  itEth('Can perform transferFromCross()', async ({helper, privateKey}) => {
-    const minter = await privateKey('//Alice');
+  itEth('Can perform transferFromCross()', async ({helper}) => {
     const collection = await helper.nft.mintCollection(minter, {name: 'A', description: 'B', tokenPrefix: 'C'});
 
-    const owner = await privateKey('//Bob');
+    const [owner, receiver] = await helper.arrange.createAccounts([100n, 100n], donor);
     const spender = await helper.eth.createAccountWithBalance(donor);
-    const receiver = await privateKey('//Charlie');
 
     const token = await collection.mintToken(minter, {Substrate: owner.address});
 
@@ -408,56 +471,72 @@
   itEth('Can perform transferCross()', async ({helper}) => {
     const collection = await helper.nft.mintCollection(minter, {});
     const owner = await helper.eth.createAccountWithBalance(donor);
-    const receiver = await helper.eth.createAccountWithBalance(donor);
-    const to = helper.ethCrossAccount.fromAddress(receiver);
-    const toSubstrate = helper.ethCrossAccount.fromKeyringPair(minter);
+    const receiverEth = await helper.eth.createAccountWithBalance(donor);
+    const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+    const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
     
     const {tokenId} = await collection.mintToken(minter, {Ethereum: owner});
 
     const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
-    const contract = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', owner);
 
     {
-      const result = await contract.methods.transferCross(to, tokenId).send({from: owner});
-
+      // Can transferCross to ethereum address:
+      const result = await collectionEvm.methods.transferCross(receiverCrossEth, tokenId).send({from: owner});
+      // Check events:
       const event = result.events.Transfer;
       expect(event.address).to.be.equal(collectionAddress);
       expect(event.returnValues.from).to.be.equal(owner);
-      expect(event.returnValues.to).to.be.equal(receiver);
+      expect(event.returnValues.to).to.be.equal(receiverEth);
       expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
-    }
-
-    {
-      const balance = await contract.methods.balanceOf(owner).call();
-      expect(+balance).to.equal(0);
-    }
-
-    {
-      const balance = await contract.methods.balanceOf(receiver).call();
-      expect(+balance).to.equal(1);
+      
+      // owner has balance = 0:
+      const ownerBalance = await collectionEvm.methods.balanceOf(owner).call();
+      expect(+ownerBalance).to.equal(0);
+      // receiver owns token:
+      const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
+      expect(+receiverBalance).to.equal(1);
+      expect(await helper.nft.getTokenOwner(collection.collectionId, tokenId)).to.deep.eq({Ethereum: receiverEth.toLowerCase()});
     }
     
     {
-      const substrateResult = await contract.methods.transferCross(toSubstrate, tokenId).send({from: receiver});
-      
-
+      // Can transferCross to substrate address:
+      const substrateResult = await collectionEvm.methods.transferCross(receiverCrossSub, tokenId).send({from: receiverEth});
+      // Check events:
       const event = substrateResult.events.Transfer;
       expect(event.address).to.be.equal(collectionAddress);
-      expect(event.returnValues.from).to.be.equal(receiver);
+      expect(event.returnValues.from).to.be.equal(receiverEth);
       expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(minter.address));
       expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
+      
+      // owner has balance = 0:
+      const ownerBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
+      expect(+ownerBalance).to.equal(0);
+      // receiver owns token:
+      const receiverBalance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address});
+      expect(receiverBalance).to.contain(tokenId);
     }
+  });
+
+  ['transfer', 'transferCross'].map(testCase => itEth(`Cannot ${testCase} non-owned token`, async ({helper}) => {
+    const sender = await helper.eth.createAccountWithBalance(donor);
+    const tokenOwner = await helper.eth.createAccountWithBalance(donor);
+    const receiverSub = minter;
+    const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
 
-    {
-      const balance = await contract.methods.balanceOf(receiver).call();
-      expect(+balance).to.equal(0);
-    }
+    const collection = await helper.nft.mintCollection(minter, {});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'nft', sender);
 
-    {
-      const balance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address});
-      expect(balance).to.be.contain(tokenId);
-    }
-  });
+    await collection.mintToken(minter, {Ethereum: sender});
+    const nonSendersToken = await collection.mintToken(minter, {Ethereum: tokenOwner});
+
+    // Cannot transferCross someone else's token:
+    const receiver = testCase === 'transfer' ? helper.address.substrateToEth(receiverSub.address) : receiverCrossSub;
+    await expect(collectionEvm.methods[testCase](receiver, nonSendersToken.tokenId).send({from: sender})).to.be.rejected;
+    // Cannot transfer token if it does not exist:
+    await expect(collectionEvm.methods[testCase](receiver, 999999).send({from: sender})).to.be.rejected;
+  }));
 });
 
 describe('NFT: Fees', () => {
@@ -501,7 +580,7 @@
     expect(cost < BigInt(0.2 * Number(helper.balance.getOneTokenNominal())));
   });
 
-  itEth('Can perform transferFromCross()', async ({helper, privateKey}) => {
+  itEth('Can perform transferFromCross()', async ({helper}) => {
     const collectionMinter = alice;
     const owner = bob;
     const receiver = charlie;
modifiedtests/src/eth/reFungible.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungible.test.ts
+++ b/tests/src/eth/reFungible.test.ts
@@ -363,57 +363,75 @@
   });
   
   itEth('Can perform transferCross()', async ({helper}) => {
-    const caller = await helper.eth.createAccountWithBalance(donor);
-    const receiver = await helper.eth.createAccountWithBalance(donor);
-    const to = helper.ethCrossAccount.fromAddress(receiver);
-    const toSubstrate = helper.ethCrossAccount.fromKeyringPair(minter);
+    const sender = await helper.eth.createAccountWithBalance(donor);
+    const receiverEth = await helper.eth.createAccountWithBalance(donor);
+    const receiverCrossEth = helper.ethCrossAccount.fromAddress(receiverEth);
+    const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
+
     const collection = await helper.rft.mintCollection(minter, {});
     const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
-    const contract = helper.ethNativeContract.collection(collectionAddress, 'rft', caller);
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', sender);
 
-    const {tokenId} = await collection.mintToken(minter, 1n, {Ethereum: caller});
+    const token = await collection.mintToken(minter, 50n, {Ethereum: sender});
 
     {
-      const result = await contract.methods.transferCross(to, tokenId).send({from: caller});
-
+      // Can transferCross to ethereum address:
+      const result = await collectionEvm.methods.transferCross(receiverCrossEth, token.tokenId).send({from: sender});
+      // Check events:
       const event = result.events.Transfer;
       expect(event.address).to.equal(collectionAddress);
-      expect(event.returnValues.from).to.equal(caller);
-      expect(event.returnValues.to).to.equal(receiver);
-      expect(event.returnValues.tokenId).to.equal(tokenId.toString());
-    }
-
-    {
-      const balance = await contract.methods.balanceOf(caller).call();
-      expect(+balance).to.equal(0);
+      expect(event.returnValues.from).to.equal(sender);
+      expect(event.returnValues.to).to.equal(receiverEth);
+      expect(event.returnValues.tokenId).to.equal(token.tokenId.toString());
+      // Sender's balance decreased:
+      const senderBalance = await collectionEvm.methods.balanceOf(sender).call();
+      expect(+senderBalance).to.equal(0);
+      expect(await token.getBalance({Ethereum: sender})).to.eq(0n);
+      // Receiver's balance increased:
+      const receiverBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
+      expect(+receiverBalance).to.equal(1);
+      expect(await token.getBalance({Ethereum: receiverEth})).to.eq(50n);
     }
-
-    {
-      const balance = await contract.methods.balanceOf(receiver).call();
-      expect(+balance).to.equal(1);
-    }
     
     {
-      const substrateResult = await contract.methods.transferCross(toSubstrate, tokenId).send({from: receiver});
-      
-
+      // Can transferCross to substrate address:
+      const substrateResult = await collectionEvm.methods.transferCross(receiverCrossSub, token.tokenId).send({from: receiverEth});
+      // Check events:
       const event = substrateResult.events.Transfer;
       expect(event.address).to.be.equal(collectionAddress);
-      expect(event.returnValues.from).to.be.equal(receiver);
+      expect(event.returnValues.from).to.be.equal(receiverEth);
       expect(event.returnValues.to).to.be.equal(helper.address.substrateToEth(minter.address));
-      expect(event.returnValues.tokenId).to.be.equal(`${tokenId}`);
+      expect(event.returnValues.tokenId).to.be.equal(`${token.tokenId}`);
+      // Sender's balance decreased:
+      const senderBalance = await collectionEvm.methods.balanceOf(receiverEth).call();
+      expect(+senderBalance).to.equal(0);
+      expect(await token.getBalance({Ethereum: receiverEth})).to.eq(0n);
+      // Receiver's balance increased:
+      const receiverBalance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address});
+      expect(receiverBalance).to.contain(token.tokenId);
+      expect(await token.getBalance({Substrate: minter.address})).to.eq(50n);
     }
+  });
+
+  ['transfer', 'transferCross'].map(testCase => itEth(`Cannot ${testCase} non-owned token`, async ({helper}) => {
+    const sender = await helper.eth.createAccountWithBalance(donor);
+    const tokenOwner = await helper.eth.createAccountWithBalance(donor);
+    const receiverSub = minter;
+    const receiverCrossSub = helper.ethCrossAccount.fromKeyringPair(minter);
 
-    {
-      const balance = await contract.methods.balanceOf(receiver).call();
-      expect(+balance).to.equal(0);
-    }
+    const collection = await helper.rft.mintCollection(minter, {});
+    const collectionAddress = helper.ethAddress.fromCollectionId(collection.collectionId);
+    const collectionEvm = helper.ethNativeContract.collection(collectionAddress, 'rft', sender);
+
+    await collection.mintToken(minter, 50n, {Ethereum: sender});
+    const nonSendersToken = await collection.mintToken(minter, 50n, {Ethereum: tokenOwner});
 
-    {
-      const balance = await helper.nft.getTokensByAddress(collection.collectionId, {Substrate: minter.address});
-      expect(balance).to.be.contain(tokenId);
-    }
-  });
+    // Cannot transferCross someone else's token:
+    const receiver = testCase === 'transfer' ? helper.address.substrateToEth(receiverSub.address) : receiverCrossSub;
+    await expect(collectionEvm.methods[testCase](receiver, nonSendersToken.tokenId).send({from: sender})).to.be.rejected;
+    // Cannot transfer token if it does not exist:
+    await expect(collectionEvm.methods[testCase](receiver, 999999).send({from: sender})).to.be.rejected;
+  }));
 
   itEth('transfer event on transfer from partial ownership to full ownership', async ({helper}) => {
     const caller = await helper.eth.createAccountWithBalance(donor);
modifiedtests/src/eth/reFungibleToken.test.tsdiffbeforeafterboth
--- a/tests/src/eth/reFungibleToken.test.ts
+++ b/tests/src/eth/reFungibleToken.test.ts
@@ -227,6 +227,46 @@
     }
   });
 
+  [
+    'transfer',
+    // 'transferCross', // TODO
+  ].map(testCase => 
+    itEth(`Cannot ${testCase}() non-owned token`, async ({helper}) => {
+      const owner = await helper.eth.createAccountWithBalance(donor);
+      const receiver = await helper.eth.createAccountWithBalance(donor);
+      const collection = await helper.rft.mintCollection(alice);
+      const rftOwner = await collection.mintToken(alice, 10n, {Ethereum: owner});
+      const rftReceiver = await collection.mintToken(alice, 10n, {Ethereum: receiver});
+      const tokenIdNonExist = 9999999;
+  
+      const tokenAddress1 = helper.ethAddress.fromTokenId(collection.collectionId, rftOwner.tokenId);
+      const tokenAddress2 = helper.ethAddress.fromTokenId(collection.collectionId, rftReceiver.tokenId);
+      const tokenAddressNonExist = helper.ethAddress.fromTokenId(collection.collectionId, tokenIdNonExist);
+      const tokenEvmOwner = helper.ethNativeContract.rftToken(tokenAddress1, owner);
+      const tokenEvmReceiver = helper.ethNativeContract.rftToken(tokenAddress2, owner);
+      const tokenEvmNonExist = helper.ethNativeContract.rftToken(tokenAddressNonExist, owner);
+      
+      // 1. Can transfer zero amount (EIP-20):
+      await tokenEvmOwner.methods[testCase](receiver, 0).send({from: owner});
+      // 2. Cannot transfer non-owned token:
+      await expect(tokenEvmReceiver.methods[testCase](owner, 0).send({from: owner})).to.be.rejected;
+      await expect(tokenEvmReceiver.methods[testCase](owner, 5).send({from: owner})).to.be.rejected;
+      // 3. Cannot transfer non-existing token:
+      await expect(tokenEvmNonExist.methods[testCase](owner, 0).send({from: owner})).to.be.rejected;
+      await expect(tokenEvmNonExist.methods[testCase](owner, 5).send({from: owner})).to.be.rejected;
+
+      // 4. Storage is not corrupted:
+      expect(await rftOwner.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]);
+      expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: receiver.toLowerCase()}]);
+      expect(await helper.rft.getTokenTop10Owners(collection.collectionId, tokenIdNonExist)).to.deep.eq([]); // TODO
+
+      // 4.1 Tokens can be transferred:
+      await tokenEvmOwner.methods[testCase](receiver, 10).send({from: owner});
+      await tokenEvmReceiver.methods[testCase](owner, 10).send({from: receiver});
+      expect(await rftOwner.getTop10Owners()).to.deep.eq([{Ethereum: receiver.toLowerCase()}]);
+      expect(await rftReceiver.getTop10Owners()).to.deep.eq([{Ethereum: owner.toLowerCase()}]);
+    }));
+
   itEth('Can perform repartition()', async ({helper}) => {
     const owner = await helper.eth.createAccountWithBalance(donor);
     const receiver = await helper.eth.createAccountWithBalance(donor);
modifiedtests/src/eth/tokenProperties.test.tsdiffbeforeafterboth
--- a/tests/src/eth/tokenProperties.test.ts
+++ b/tests/src/eth/tokenProperties.test.ts
@@ -120,17 +120,17 @@
     const address = helper.ethAddress.fromCollectionId(collection.collectionId);
     const contract = helper.ethNativeContract.collection(address, mode, caller);
     
-    expect(await contract.methods.tokenProperties(token.tokenId, []).call()).to.be.deep.equal([]);
+    expect(await contract.methods.properties(token.tokenId, []).call()).to.be.deep.equal([]);
 
     await contract.methods.setProperties(token.tokenId, properties).send({from: caller});
 
     const values = await token.getProperties(properties.map(p => p.key));
     expect(values).to.be.deep.equal(properties.map(p => { return {key: p.key, value: p.value.toString()}; }));
     
-    expect(await contract.methods.tokenProperties(token.tokenId, []).call()).to.be.like(properties
+    expect(await contract.methods.properties(token.tokenId, []).call()).to.be.like(properties
       .map(p => { return helper.ethProperty.property(p.key, p.value.toString()); }));
     
-    expect(await contract.methods.tokenProperties(token.tokenId, [properties[0].key]).call())
+    expect(await contract.methods.properties(token.tokenId, [properties[0].key]).call())
       .to.be.like([helper.ethProperty.property(properties[0].key, properties[0].value.toString())]);
   }
   
modifiedtests/src/eth/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/tests/src/eth/util/playgrounds/unique.dev.ts
+++ b/tests/src/eth/util/playgrounds/unique.dev.ts
@@ -103,12 +103,12 @@
 
   contractHelpers(caller: string): Contract {
     const web3 = this.helper.getWeb3();
-    return new web3.eth.Contract(contractHelpersAbi as any, '0x842899ECF380553E8a4de75bF534cdf6fBF64049', {from: caller, gas: this.helper.eth.DEFAULT_GAS});
+    return new web3.eth.Contract(contractHelpersAbi as any, this.helper.getApi().consts.evmContractHelpers.contractAddress.toString(), {from: caller, gas: this.helper.eth.DEFAULT_GAS});
   }
 
   collectionHelpers(caller: string) {
     const web3 = this.helper.getWeb3();
-    return new web3.eth.Contract(collectionHelpersAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, gas: this.helper.eth.DEFAULT_GAS});
+    return new web3.eth.Contract(collectionHelpersAbi as any, this.helper.getApi().consts.common.contractAddress.toString(), {from: caller, gas: this.helper.eth.DEFAULT_GAS});
   }
 
   collection(address: string, mode: TCollectionMode, caller?: string, mergeDeprecated = false): Contract {
@@ -186,11 +186,12 @@
     return await this.helper.callRpc('api.rpc.eth.call', [{from: signer, to: contractAddress, data: abi}]);
   }
 
-  async createCollecion(functionName: string, signer: string, name: string, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
+  async createCollecion(functionName: 'createNFTCollection' | 'createRFTCollection' | 'createFTCollection', signer: string, name: string, description: string, tokenPrefix: string, decimals?: number): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
     const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice();
     const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);
 
-    const result = await collectionHelper.methods[functionName](name, description, tokenPrefix).send({value: Number(collectionCreationPrice)});
+    const functionParams = functionName === 'createFTCollection' ? [name, decimals, description, tokenPrefix] : [name, description, tokenPrefix];
+    const result = await collectionHelper.methods[functionName](...functionParams).send({value: Number(collectionCreationPrice)});
 
     const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
     const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
@@ -217,17 +218,8 @@
     return this.createCollecion('createRFTCollection', signer, name, description, tokenPrefix);
   }
 
-  async createFungibleCollection(signer: string, name: string, decimals: number, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[]}> {
-    const collectionCreationPrice = this.helper.balance.getCollectionCreationPrice();
-    const collectionHelper = this.helper.ethNativeContract.collectionHelpers(signer);
-
-    const result = await collectionHelper.methods.createFTCollection(name, decimals, description, tokenPrefix).send({value: Number(collectionCreationPrice)});
-    const collectionAddress = this.helper.ethAddress.normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
-    const collectionId = this.helper.ethAddress.extractCollectionId(collectionAddress);
-
-    const events = this.helper.eth.normalizeEvents(result.events);
-
-    return {collectionId, collectionAddress, events};
+  createFungibleCollection(signer: string, name: string, decimals: number, description: string, tokenPrefix: string): Promise<{ collectionId: number, collectionAddress: string, events: NormalizedEvent[]}> {
+    return this.createCollecion('createFTCollection', signer, name, description, tokenPrefix, decimals);
   }
 
   async createERC721MetadataCompatibleRFTCollection(signer: string, name: string, description: string, tokenPrefix: string, baseUri: string): Promise<{collectionId: number, collectionAddress: string, events: NormalizedEvent[] }> {
modifiedtests/src/fungible.test.tsdiffbeforeafterboth
--- a/tests/src/fungible.test.ts
+++ b/tests/src/fungible.test.ts
@@ -15,7 +15,7 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import {IKeyringPair} from '@polkadot/types/types';
-import {itSub, usingPlaygrounds, expect} from './util';
+import {itSub, usingPlaygrounds, expect, requirePalletsOrSkip, Pallets} from './util';
 
 const U128_MAX = (1n << 128n) - 1n;
 
@@ -145,3 +145,42 @@
     expect(await collection.getBalance(ethAcc)).to.be.equal(10n);
   });
 });
+
+describe('Fungible negative tests', () => {
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+  let bob: IKeyringPair;
+  let charlie: IKeyringPair;
+
+  before(async function() {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.Fungible]);
+
+      donor = await privateKey({filename: __filename});
+      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+    });
+  });
+
+  itSub('Cannot transfer incorrect amount of tokens', async ({helper}) => {
+    const collection = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+    const nonExistingCollection = helper.ft.getCollectionObject(99999);
+    await collection.mint(alice, 10n, {Substrate: bob.address});
+
+    // 1. Alice cannot transfer more than 0 tokens if balance low:
+    await expect(collection.transfer(alice, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.TokenValueTooLow');
+    await expect(collection.transfer(alice, {Substrate: charlie.address}, 100n)).to.be.rejectedWith('common.TokenValueTooLow');
+    
+    // 2. Alice cannot transfer non-existing token:
+    await expect(nonExistingCollection.transfer(alice, {Substrate: charlie.address}, 0n)).to.be.rejectedWith('common.CollectionNotFound');
+    await expect(nonExistingCollection.transfer(alice, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.CollectionNotFound');
+    
+    // 3. Zero transfer allowed (EIP-20):
+    await collection.transfer(bob, {Substrate: charlie.address}, 0n);
+    // 3.1 even if the balance = 0
+    await collection.transfer(alice, {Substrate: charlie.address}, 0n);
+
+    expect(await collection.getBalance({Substrate: alice.address})).to.eq(0n);
+    expect(await collection.getBalance({Substrate: bob.address})).to.eq(10n);
+    expect(await collection.getBalance({Substrate: charlie.address})).to.eq(0n);
+  });
+});
modifiedtests/src/interfaces/augment-api-consts.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-consts.ts
+++ b/tests/src/interfaces/augment-api-consts.ts
@@ -8,8 +8,8 @@
 import type { ApiTypes, AugmentedConst } from '@polkadot/api-base/types';
 import type { Option, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
 import type { Codec } from '@polkadot/types-codec/types';
-import type { Perbill, Permill, Weight } from '@polkadot/types/interfaces/runtime';
-import type { FrameSupportPalletId, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, XcmV1MultiLocation } from '@polkadot/types/lookup';
+import type { H160, Perbill, Permill, Weight } from '@polkadot/types/interfaces/runtime';
+import type { FrameSupportPalletId, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, UpDataStructsCollectionLimits, XcmV1MultiLocation } from '@polkadot/types/lookup';
 
 export type __AugmentedConst<ApiType extends ApiTypes> = AugmentedConst<ApiType>;
 
@@ -70,6 +70,10 @@
        **/
       collectionCreationPrice: u128 & AugmentedConst<ApiType>;
       /**
+       * Address under which the CollectionHelper contract would be available.
+       **/
+      contractAddress: H160 & AugmentedConst<ApiType>;
+      /**
        * Generic const
        **/
       [key: string]: Codec;
@@ -82,6 +86,16 @@
        **/
       [key: string]: Codec;
     };
+    evmContractHelpers: {
+      /**
+       * Address, under which magic contract will be available
+       **/
+      contractAddress: H160 & AugmentedConst<ApiType>;
+      /**
+       * Generic const
+       **/
+      [key: string]: Codec;
+    };
     inflation: {
       /**
        * Number of blocks that pass between treasury balance updates due to inflation
@@ -94,13 +108,11 @@
     };
     scheduler: {
       /**
-       * The maximum weight that may be scheduled per block for any dispatchables of less
-       * priority than `schedule::HARD_DEADLINE`.
+       * The maximum weight that may be scheduled per block for any dispatchables.
        **/
       maximumWeight: Weight & AugmentedConst<ApiType>;
       /**
        * The maximum number of scheduled calls in the queue for a single block.
-       * Not strictly enforced, but used for weight estimation.
        **/
       maxScheduledPerBlock: u32 & AugmentedConst<ApiType>;
       /**
@@ -233,6 +245,64 @@
        **/
       [key: string]: Codec;
     };
+    unique: {
+      /**
+       * Maximum admins per collection.
+       **/
+      collectionAdminsLimit: u32 & AugmentedConst<ApiType>;
+      /**
+       * Default FT collection limit.
+       **/
+      ftDefaultCollectionLimits: UpDataStructsCollectionLimits & AugmentedConst<ApiType>;
+      /**
+       * Maximal length of a collection description.
+       **/
+      maxCollectionDescriptionLength: u32 & AugmentedConst<ApiType>;
+      /**
+       * Maximal length of a collection name.
+       **/
+      maxCollectionNameLength: u32 & AugmentedConst<ApiType>;
+      /**
+       * Maximum size for all collection properties.
+       **/
+      maxCollectionPropertiesSize: u32 & AugmentedConst<ApiType>;
+      /**
+       * A maximum number of token properties.
+       **/
+      maxPropertiesPerItem: u32 & AugmentedConst<ApiType>;
+      /**
+       * Maximal length of a property key.
+       **/
+      maxPropertyKeyLength: u32 & AugmentedConst<ApiType>;
+      /**
+       * Maximal length of a property value.
+       **/
+      maxPropertyValueLength: u32 & AugmentedConst<ApiType>;
+      /**
+       * Maximal length of a token prefix.
+       **/
+      maxTokenPrefixLength: u32 & AugmentedConst<ApiType>;
+      /**
+       * Maximum size of all token properties.
+       **/
+      maxTokenPropertiesSize: u32 & AugmentedConst<ApiType>;
+      /**
+       * A maximum number of levels of depth in the token nesting tree.
+       **/
+      nestingBudget: u32 & AugmentedConst<ApiType>;
+      /**
+       * Default NFT collection limit.
+       **/
+      nftDefaultCollectionLimits: UpDataStructsCollectionLimits & AugmentedConst<ApiType>;
+      /**
+       * Default RFT collection limit.
+       **/
+      rftDefaultCollectionLimits: UpDataStructsCollectionLimits & AugmentedConst<ApiType>;
+      /**
+       * Generic const
+       **/
+      [key: string]: Codec;
+    };
     vesting: {
       /**
        * The minimum amount transferred to call `vested_transfer`.
modifiedtests/src/interfaces/augment-api-errors.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-errors.ts
+++ b/tests/src/interfaces/augment-api-errors.ts
@@ -265,6 +265,14 @@
        **/
       FeeOverflow: AugmentedError<ApiType>;
       /**
+       * Gas limit is too high.
+       **/
+      GasLimitTooHigh: AugmentedError<ApiType>;
+      /**
+       * Gas limit is too low.
+       **/
+      GasLimitTooLow: AugmentedError<ApiType>;
+      /**
        * Gas price is too low.
        **/
       GasPriceTooLow: AugmentedError<ApiType>;
@@ -277,6 +285,14 @@
        **/
       PaymentOverflow: AugmentedError<ApiType>;
       /**
+       * EVM reentrancy
+       **/
+      Reentrancy: AugmentedError<ApiType>;
+      /**
+       * Undefined error.
+       **/
+      Undefined: AugmentedError<ApiType>;
+      /**
        * Withdraw fee failed
        **/
       WithdrawFailed: AugmentedError<ApiType>;
@@ -321,6 +337,10 @@
        **/
       AccountNotEmpty: AugmentedError<ApiType>;
       /**
+       * Failed to decode event bytes
+       **/
+      BadEvent: AugmentedError<ApiType>;
+      /**
        * Generic error
        **/
       [key: string]: AugmentedError<ApiType>;
@@ -644,22 +664,38 @@
     };
     scheduler: {
       /**
+       * There is no place for a new task in the agenda
+       **/
+      AgendaIsExhausted: AugmentedError<ApiType>;
+      /**
        * Failed to schedule a call
        **/
       FailedToSchedule: AugmentedError<ApiType>;
       /**
+       * Attempt to use a non-named function on a named task.
+       **/
+      Named: AugmentedError<ApiType>;
+      /**
        * Cannot find the scheduled call.
        **/
       NotFound: AugmentedError<ApiType>;
       /**
-       * Reschedule failed because it does not change scheduled time.
+       * Scheduled call preimage is not found
+       **/
+      PreimageNotFound: AugmentedError<ApiType>;
+      /**
+       * Scheduled call is corrupted
        **/
-      RescheduleNoChange: AugmentedError<ApiType>;
+      ScheduledCallCorrupted: AugmentedError<ApiType>;
       /**
        * Given target block number is in the past.
        **/
       TargetBlockNumberInPast: AugmentedError<ApiType>;
       /**
+       * Scheduled call is too big
+       **/
+      TooBigScheduledCall: AugmentedError<ApiType>;
+      /**
        * Generic error
        **/
       [key: string]: AugmentedError<ApiType>;
modifiedtests/src/interfaces/augment-api-events.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-events.ts
+++ b/tests/src/interfaces/augment-api-events.ts
@@ -6,10 +6,10 @@
 import '@polkadot/api-base/types/events';
 
 import type { ApiTypes, AugmentedEvent } from '@polkadot/api-base/types';
-import type { Bytes, Null, Option, Result, U256, U8aFixed, bool, u128, u32, u64, u8 } from '@polkadot/types-codec';
+import type { Bytes, Null, Option, Result, U8aFixed, bool, u128, u32, u64, u8 } from '@polkadot/types-codec';
 import type { ITuple } from '@polkadot/types-codec/types';
 import type { AccountId32, H160, H256, Weight } from '@polkadot/types/interfaces/runtime';
-import type { EthereumLog, EvmCoreErrorExitReason, FrameSupportDispatchDispatchInfo, FrameSupportScheduleLookupError, FrameSupportTokensMiscBalanceStatus, OrmlVestingVestingSchedule, PalletEvmAccountBasicCrossAccountIdRepr, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, RmrkTraitsNftAccountIdOrCollectionNftTuple, SpRuntimeDispatchError, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetMultiAssets, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation } from '@polkadot/types/lookup';
+import type { EthereumLog, EvmCoreErrorExitReason, FrameSupportDispatchDispatchInfo, FrameSupportTokensMiscBalanceStatus, OrmlVestingVestingSchedule, PalletEvmAccountBasicCrossAccountIdRepr, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, RmrkTraitsNftAccountIdOrCollectionNftTuple, SpRuntimeDispatchError, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetMultiAssets, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation } from '@polkadot/types/lookup';
 
 export type __AugmentedEvent<ApiType extends ApiTypes> = AugmentedEvent<ApiType>;
 
@@ -204,9 +204,9 @@
     };
     ethereum: {
       /**
-       * An ethereum transaction was successfully executed. [from, to/contract_address, transaction_hash, exit_reason]
+       * An ethereum transaction was successfully executed.
        **/
-      Executed: AugmentedEvent<ApiType, [H160, H160, H256, EvmCoreErrorExitReason]>;
+      Executed: AugmentedEvent<ApiType, [from: H160, to: H160, transactionHash: H256, exitReason: EvmCoreErrorExitReason], { from: H160, to: H160, transactionHash: H256, exitReason: EvmCoreErrorExitReason }>;
       /**
        * Generic event
        **/
@@ -214,33 +214,25 @@
     };
     evm: {
       /**
-       * A deposit has been made at a given address. \[sender, address, value\]
-       **/
-      BalanceDeposit: AugmentedEvent<ApiType, [AccountId32, H160, U256]>;
-      /**
-       * A withdrawal has been made from a given address. \[sender, address, value\]
-       **/
-      BalanceWithdraw: AugmentedEvent<ApiType, [AccountId32, H160, U256]>;
-      /**
-       * A contract has been created at given \[address\].
+       * A contract has been created at given address.
        **/
-      Created: AugmentedEvent<ApiType, [H160]>;
+      Created: AugmentedEvent<ApiType, [address: H160], { address: H160 }>;
       /**
-       * A \[contract\] was attempted to be created, but the execution failed.
+       * A contract was attempted to be created, but the execution failed.
        **/
-      CreatedFailed: AugmentedEvent<ApiType, [H160]>;
+      CreatedFailed: AugmentedEvent<ApiType, [address: H160], { address: H160 }>;
       /**
-       * A \[contract\] has been executed successfully with states applied.
+       * A contract has been executed successfully with states applied.
        **/
-      Executed: AugmentedEvent<ApiType, [H160]>;
+      Executed: AugmentedEvent<ApiType, [address: H160], { address: H160 }>;
       /**
-       * A \[contract\] has been executed with errors. States are reverted with only gas fees applied.
+       * A contract has been executed with errors. States are reverted with only gas fees applied.
        **/
-      ExecutedFailed: AugmentedEvent<ApiType, [H160]>;
+      ExecutedFailed: AugmentedEvent<ApiType, [address: H160], { address: H160 }>;
       /**
        * Ethereum events from contracts.
        **/
-      Log: AugmentedEvent<ApiType, [EthereumLog]>;
+      Log: AugmentedEvent<ApiType, [log: EthereumLog], { log: EthereumLog }>;
       /**
        * Generic event
        **/
@@ -264,6 +256,16 @@
        **/
       [key: string]: AugmentedEvent<ApiType>;
     };
+    evmMigration: {
+      /**
+       * This event is used in benchmarking and can be used for tests
+       **/
+      TestEvent: AugmentedEvent<ApiType, []>;
+      /**
+       * Generic event
+       **/
+      [key: string]: AugmentedEvent<ApiType>;
+    };
     foreignAssets: {
       /**
        * The asset registered.
@@ -479,7 +481,7 @@
       /**
        * The call for the provided hash was not found so the task has been aborted.
        **/
-      CallLookupFailed: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>, error: FrameSupportScheduleLookupError], { task: ITuple<[u32, u32]>, id: Option<U8aFixed>, error: FrameSupportScheduleLookupError }>;
+      CallUnavailable: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>], { task: ITuple<[u32, u32]>, id: Option<U8aFixed> }>;
       /**
        * Canceled some task.
        **/
@@ -489,9 +491,13 @@
        **/
       Dispatched: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>, result: Result<Null, SpRuntimeDispatchError>], { task: ITuple<[u32, u32]>, id: Option<U8aFixed>, result: Result<Null, SpRuntimeDispatchError> }>;
       /**
+       * The given task can never be executed since it is overweight.
+       **/
+      PermanentlyOverweight: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, id: Option<U8aFixed>], { task: ITuple<[u32, u32]>, id: Option<U8aFixed> }>;
+      /**
        * Scheduled task's priority has changed
        **/
-      PriorityChanged: AugmentedEvent<ApiType, [when: u32, index: u32, priority: u8], { when: u32, index: u32, priority: u8 }>;
+      PriorityChanged: AugmentedEvent<ApiType, [task: ITuple<[u32, u32]>, priority: u8], { task: ITuple<[u32, u32]>, priority: u8 }>;
       /**
        * Scheduled some task.
        **/
@@ -560,6 +566,7 @@
       [key: string]: AugmentedEvent<ApiType>;
     };
     testUtils: {
+      BatchCompleted: AugmentedEvent<ApiType, []>;
       ShouldRollback: AugmentedEvent<ApiType, []>;
       ValueIsSet: AugmentedEvent<ApiType, []>;
       /**
modifiedtests/src/interfaces/augment-api-query.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-query.ts
+++ b/tests/src/interfaces/augment-api-query.ts
@@ -9,7 +9,7 @@
 import type { BTreeMap, Bytes, Option, U256, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
 import type { AnyNumber, ITuple } from '@polkadot/types-codec/types';
 import type { AccountId32, H160, H256, Weight } from '@polkadot/types/interfaces/runtime';
-import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueQueueConfigData, EthereumBlock, EthereumLog, EthereumReceiptReceiptV3, EthereumTransactionTransactionV2, FpRpcTransactionStatus, FrameSupportDispatchPerDispatchClassWeight, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensReserveData, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesReleases, PalletBalancesReserveData, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmContractHelpersSponsoringModeT, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletNonfungibleItemData, PalletRefungibleItemData, PalletTransactionPaymentReleases, PalletTreasuryProposal, PalletUniqueSchedulerScheduledV3, PhantomTypeUpDataStructs, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpRuntimeDigest, SpTrieStorageProof, UpDataStructsCollection, UpDataStructsCollectionStats, UpDataStructsProperties, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, XcmV1MultiLocation } from '@polkadot/types/lookup';
+import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueQueueConfigData, EthereumBlock, EthereumLog, EthereumReceiptReceiptV3, EthereumTransactionTransactionV2, FpRpcTransactionStatus, FrameSupportDispatchPerDispatchClassWeight, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensReserveData, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesReleases, PalletBalancesReserveData, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmContractHelpersSponsoringModeT, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletNonfungibleItemData, PalletRefungibleItemData, PalletTransactionPaymentReleases, PalletTreasuryProposal, PalletUniqueSchedulerV2BlockAgenda, PhantomTypeUpDataStructs, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpRuntimeDigest, SpTrieStorageProof, UpDataStructsCollection, UpDataStructsCollectionStats, UpDataStructsProperties, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, XcmV1MultiLocation } from '@polkadot/types/lookup';
 import type { Observable } from '@polkadot/types/types';
 
 export type __AugmentedQuery<ApiType extends ApiTypes> = AugmentedQuery<ApiType, () => unknown>;
@@ -681,9 +681,14 @@
       /**
        * Items to be executed, indexed by the block number that they should be executed on.
        **/
-      agenda: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<Vec<Option<PalletUniqueSchedulerScheduledV3>>>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
+      agenda: AugmentedQuery<ApiType, (arg: u32 | AnyNumber | Uint8Array) => Observable<PalletUniqueSchedulerV2BlockAgenda>, [u32]> & QueryableStorageEntry<ApiType, [u32]>;
       /**
-       * Lookup from identity to the block number and index of the task.
+       * It contains the block number from which we should service tasks.
+       * It's used for delaying the servicing of future blocks' agendas if we had overweight tasks.
+       **/
+      incompleteSince: AugmentedQuery<ApiType, () => Observable<Option<u32>>, []> & QueryableStorageEntry<ApiType, []>;
+      /**
+       * Lookup from a name to the block number and index of the task.
        **/
       lookup: AugmentedQuery<ApiType, (arg: U8aFixed | string | Uint8Array) => Observable<Option<ITuple<[u32, u32]>>>, [U8aFixed]> & QueryableStorageEntry<ApiType, [U8aFixed]>;
       /**
modifiedtests/src/interfaces/augment-api-tx.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-tx.ts
+++ b/tests/src/interfaces/augment-api-tx.ts
@@ -9,7 +9,7 @@
 import type { Bytes, Compact, Option, U256, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
 import type { AnyNumber, IMethod, ITuple } from '@polkadot/types-codec/types';
 import type { AccountId32, Call, H160, H256, MultiAddress, Perbill, Permill, Weight } from '@polkadot/types/interfaces/runtime';
-import type { CumulusPrimitivesParachainInherentParachainInherentData, EthereumTransactionTransactionV2, FrameSupportScheduleMaybeHashed, OrmlVestingVestingSchedule, PalletEvmAccountBasicCrossAccountIdRepr, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsPartEquippableList, RmrkTraitsPartPartType, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCreateCollectionData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, XcmV1MultiLocation, XcmV2WeightLimit, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
+import type { CumulusPrimitivesParachainInherentParachainInherentData, EthereumLog, EthereumTransactionTransactionV2, OrmlVestingVestingSchedule, PalletEvmAccountBasicCrossAccountIdRepr, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsPartEquippableList, RmrkTraitsPartPartType, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCreateCollectionData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, XcmV1MultiLocation, XcmV2WeightLimit, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
 
 export type __AugmentedSubmittable = AugmentedSubmittable<() => unknown>;
 export type __SubmittableExtrinsic<ApiType extends ApiTypes> = SubmittableExtrinsic<ApiType>;
@@ -295,6 +295,14 @@
        **/
       finish: AugmentedSubmittable<(address: H160 | string | Uint8Array, code: Bytes | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [H160, Bytes]>;
       /**
+       * Create ethereum events attached to the fake transaction
+       **/
+      insertEthLogs: AugmentedSubmittable<(logs: Vec<EthereumLog> | (EthereumLog | { address?: any; topics?: any; data?: any } | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<EthereumLog>]>;
+      /**
+       * Create substrate events
+       **/
+      insertEvents: AugmentedSubmittable<(events: Vec<Bytes> | (Bytes | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Bytes>]>;
+      /**
        * Insert items into contract storage, this method can be called
        * multiple times
        **/
@@ -831,22 +839,56 @@
     };
     scheduler: {
       /**
+       * Cancel an anonymously scheduled task.
+       * 
+       * The `T::OriginPrivilegeCmp` decides whether the given origin is allowed to cancel the task or not.
+       **/
+      cancel: AugmentedSubmittable<(when: u32 | AnyNumber | Uint8Array, index: u32 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, u32]>;
+      /**
        * Cancel a named scheduled task.
+       * 
+       * The `T::OriginPrivilegeCmp` decides whether the given origin is allowed to cancel the task or not.
        **/
       cancelNamed: AugmentedSubmittable<(id: U8aFixed | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [U8aFixed]>;
+      /**
+       * Change a named task's priority.
+       * 
+       * Only the `T::PrioritySetOrigin` is allowed to change the task's priority.
+       **/
       changeNamedPriority: AugmentedSubmittable<(id: U8aFixed | string | Uint8Array, priority: u8 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [U8aFixed, u8]>;
       /**
+       * Anonymously schedule a task.
+       * 
+       * Only `T::ScheduleOrigin` is allowed to schedule a task.
+       * Only `T::PrioritySetOrigin` is allowed to set the task's priority.
+       **/
+      schedule: AugmentedSubmittable<(when: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: Option<u8> | null | Uint8Array | u8 | AnyNumber, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, Option<ITuple<[u32, u32]>>, Option<u8>, Call]>;
+      /**
+       * Anonymously schedule a task after a delay.
+       * 
+       * # <weight>
+       * Same as [`schedule`].
+       * # </weight>
+       **/
+      scheduleAfter: AugmentedSubmittable<(after: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: Option<u8> | null | Uint8Array | u8 | AnyNumber, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [u32, Option<ITuple<[u32, u32]>>, Option<u8>, Call]>;
+      /**
        * Schedule a named task.
+       * 
+       * Only `T::ScheduleOrigin` is allowed to schedule a task.
+       * Only `T::PrioritySetOrigin` is allowed to set the task's priority.
        **/
-      scheduleNamed: AugmentedSubmittable<(id: U8aFixed | string | Uint8Array, when: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: Option<u8> | null | Uint8Array | u8 | AnyNumber, call: FrameSupportScheduleMaybeHashed | { Value: any } | { Hash: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [U8aFixed, u32, Option<ITuple<[u32, u32]>>, Option<u8>, FrameSupportScheduleMaybeHashed]>;
+      scheduleNamed: AugmentedSubmittable<(id: U8aFixed | string | Uint8Array, when: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: Option<u8> | null | Uint8Array | u8 | AnyNumber, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [U8aFixed, u32, Option<ITuple<[u32, u32]>>, Option<u8>, Call]>;
       /**
        * Schedule a named task after a delay.
        * 
+       * Only `T::ScheduleOrigin` is allowed to schedule a task.
+       * Only `T::PrioritySetOrigin` is allowed to set the task's priority.
+       * 
        * # <weight>
        * Same as [`schedule_named`](Self::schedule_named).
        * # </weight>
        **/
-      scheduleNamedAfter: AugmentedSubmittable<(id: U8aFixed | string | Uint8Array, after: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: Option<u8> | null | Uint8Array | u8 | AnyNumber, call: FrameSupportScheduleMaybeHashed | { Value: any } | { Hash: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [U8aFixed, u32, Option<ITuple<[u32, u32]>>, Option<u8>, FrameSupportScheduleMaybeHashed]>;
+      scheduleNamedAfter: AugmentedSubmittable<(id: U8aFixed | string | Uint8Array, after: u32 | AnyNumber | Uint8Array, maybePeriodic: Option<ITuple<[u32, u32]>> | null | Uint8Array | ITuple<[u32, u32]> | [u32 | AnyNumber | Uint8Array, u32 | AnyNumber | Uint8Array], priority: Option<u8> | null | Uint8Array | u8 | AnyNumber, call: Call | IMethod | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [U8aFixed, u32, Option<ITuple<[u32, u32]>>, Option<u8>, Call]>;
       /**
        * Generic tx
        **/
@@ -986,6 +1028,7 @@
       [key: string]: SubmittableExtrinsicFunction<ApiType>;
     };
     testUtils: {
+      batchAll: AugmentedSubmittable<(calls: Vec<Call> | (Call | IMethod | string | Uint8Array)[]) => SubmittableExtrinsic<ApiType>, [Vec<Call>]>;
       enable: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
       incTestValue: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
       justTakeFee: AugmentedSubmittable<() => SubmittableExtrinsic<ApiType>, []>;
modifiedtests/src/interfaces/augment-types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-types.ts
+++ b/tests/src/interfaces/augment-types.ts
@@ -5,7 +5,7 @@
 // this is required to allow for ambient/previous definitions
 import '@polkadot/types/types/registry';
 
-import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportScheduleLookupError, FrameSupportScheduleMaybeHashed, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationCall, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletUniqueSchedulerCall, PalletUniqueSchedulerError, PalletUniqueSchedulerEvent, PalletUniqueSchedulerScheduledV3, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './default';
+import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationCall, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletUniqueSchedulerV2BlockAgenda, PalletUniqueSchedulerV2Call, PalletUniqueSchedulerV2Error, PalletUniqueSchedulerV2Event, PalletUniqueSchedulerV2Scheduled, PalletUniqueSchedulerV2ScheduledCall, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './default';
 import type { Data, StorageKey } from '@polkadot/types';
 import type { BitVec, Bool, Bytes, F32, F64, I128, I16, I256, I32, I64, I8, Json, Null, OptionBool, Raw, Text, Type, U128, U16, U256, U32, U64, U8, USize, bool, f32, f64, i128, i16, i256, i32, i64, i8, u128, u16, u256, u32, u64, u8, usize } from '@polkadot/types-codec';
 import type { AssetApproval, AssetApprovalKey, AssetBalance, AssetDestroyWitness, AssetDetails, AssetMetadata, TAssetBalance, TAssetDepositBalance } from '@polkadot/types/interfaces/assets';
@@ -526,8 +526,6 @@
     FrameSupportDispatchPerDispatchClassWeightsPerClass: FrameSupportDispatchPerDispatchClassWeightsPerClass;
     FrameSupportDispatchRawOrigin: FrameSupportDispatchRawOrigin;
     FrameSupportPalletId: FrameSupportPalletId;
-    FrameSupportScheduleLookupError: FrameSupportScheduleLookupError;
-    FrameSupportScheduleMaybeHashed: FrameSupportScheduleMaybeHashed;
     FrameSupportTokensMiscBalanceStatus: FrameSupportTokensMiscBalanceStatus;
     FrameSystemAccountInfo: FrameSystemAccountInfo;
     FrameSystemCall: FrameSystemCall;
@@ -854,6 +852,7 @@
     PalletEvmEvent: PalletEvmEvent;
     PalletEvmMigrationCall: PalletEvmMigrationCall;
     PalletEvmMigrationError: PalletEvmMigrationError;
+    PalletEvmMigrationEvent: PalletEvmMigrationEvent;
     PalletForeignAssetsAssetIds: PalletForeignAssetsAssetIds;
     PalletForeignAssetsModuleAssetMetadata: PalletForeignAssetsModuleAssetMetadata;
     PalletForeignAssetsModuleCall: PalletForeignAssetsModuleCall;
@@ -902,10 +901,12 @@
     PalletUniqueCall: PalletUniqueCall;
     PalletUniqueError: PalletUniqueError;
     PalletUniqueRawEvent: PalletUniqueRawEvent;
-    PalletUniqueSchedulerCall: PalletUniqueSchedulerCall;
-    PalletUniqueSchedulerError: PalletUniqueSchedulerError;
-    PalletUniqueSchedulerEvent: PalletUniqueSchedulerEvent;
-    PalletUniqueSchedulerScheduledV3: PalletUniqueSchedulerScheduledV3;
+    PalletUniqueSchedulerV2BlockAgenda: PalletUniqueSchedulerV2BlockAgenda;
+    PalletUniqueSchedulerV2Call: PalletUniqueSchedulerV2Call;
+    PalletUniqueSchedulerV2Error: PalletUniqueSchedulerV2Error;
+    PalletUniqueSchedulerV2Event: PalletUniqueSchedulerV2Event;
+    PalletUniqueSchedulerV2Scheduled: PalletUniqueSchedulerV2Scheduled;
+    PalletUniqueSchedulerV2ScheduledCall: PalletUniqueSchedulerV2ScheduledCall;
     PalletVersion: PalletVersion;
     PalletXcmCall: PalletXcmCall;
     PalletXcmError: PalletXcmError;
modifiedtests/src/interfaces/default/types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/default/types.ts
+++ b/tests/src/interfaces/default/types.ts
@@ -556,22 +556,6 @@
 /** @name FrameSupportPalletId */
 export interface FrameSupportPalletId extends U8aFixed {}
 
-/** @name FrameSupportScheduleLookupError */
-export interface FrameSupportScheduleLookupError extends Enum {
-  readonly isUnknown: boolean;
-  readonly isBadFormat: boolean;
-  readonly type: 'Unknown' | 'BadFormat';
-}
-
-/** @name FrameSupportScheduleMaybeHashed */
-export interface FrameSupportScheduleMaybeHashed extends Enum {
-  readonly isValue: boolean;
-  readonly asValue: Call;
-  readonly isHash: boolean;
-  readonly asHash: H256;
-  readonly type: 'Value' | 'Hash';
-}
-
 /** @name FrameSupportTokensMiscBalanceStatus */
 export interface FrameSupportTokensMiscBalanceStatus extends Enum {
   readonly isFree: boolean;
@@ -1347,7 +1331,12 @@
 /** @name PalletEthereumEvent */
 export interface PalletEthereumEvent extends Enum {
   readonly isExecuted: boolean;
-  readonly asExecuted: ITuple<[H160, H160, H256, EvmCoreErrorExitReason]>;
+  readonly asExecuted: {
+    readonly from: H160;
+    readonly to: H160;
+    readonly transactionHash: H256;
+    readonly exitReason: EvmCoreErrorExitReason;
+  } & Struct;
   readonly type: 'Executed';
 }
 
@@ -1457,26 +1446,36 @@
   readonly isWithdrawFailed: boolean;
   readonly isGasPriceTooLow: boolean;
   readonly isInvalidNonce: boolean;
-  readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce';
+  readonly isGasLimitTooLow: boolean;
+  readonly isGasLimitTooHigh: boolean;
+  readonly isUndefined: boolean;
+  readonly isReentrancy: boolean;
+  readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce' | 'GasLimitTooLow' | 'GasLimitTooHigh' | 'Undefined' | 'Reentrancy';
 }
 
 /** @name PalletEvmEvent */
 export interface PalletEvmEvent extends Enum {
   readonly isLog: boolean;
-  readonly asLog: EthereumLog;
+  readonly asLog: {
+    readonly log: EthereumLog;
+  } & Struct;
   readonly isCreated: boolean;
-  readonly asCreated: H160;
+  readonly asCreated: {
+    readonly address: H160;
+  } & Struct;
   readonly isCreatedFailed: boolean;
-  readonly asCreatedFailed: H160;
+  readonly asCreatedFailed: {
+    readonly address: H160;
+  } & Struct;
   readonly isExecuted: boolean;
-  readonly asExecuted: H160;
+  readonly asExecuted: {
+    readonly address: H160;
+  } & Struct;
   readonly isExecutedFailed: boolean;
-  readonly asExecutedFailed: H160;
-  readonly isBalanceDeposit: boolean;
-  readonly asBalanceDeposit: ITuple<[AccountId32, H160, U256]>;
-  readonly isBalanceWithdraw: boolean;
-  readonly asBalanceWithdraw: ITuple<[AccountId32, H160, U256]>;
-  readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed' | 'BalanceDeposit' | 'BalanceWithdraw';
+  readonly asExecutedFailed: {
+    readonly address: H160;
+  } & Struct;
+  readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed';
 }
 
 /** @name PalletEvmMigrationCall */
@@ -1495,16 +1494,31 @@
     readonly address: H160;
     readonly code: Bytes;
   } & Struct;
-  readonly type: 'Begin' | 'SetData' | 'Finish';
+  readonly isInsertEthLogs: boolean;
+  readonly asInsertEthLogs: {
+    readonly logs: Vec<EthereumLog>;
+  } & Struct;
+  readonly isInsertEvents: boolean;
+  readonly asInsertEvents: {
+    readonly events: Vec<Bytes>;
+  } & Struct;
+  readonly type: 'Begin' | 'SetData' | 'Finish' | 'InsertEthLogs' | 'InsertEvents';
 }
 
 /** @name PalletEvmMigrationError */
 export interface PalletEvmMigrationError extends Enum {
   readonly isAccountNotEmpty: boolean;
   readonly isAccountIsNotMigrating: boolean;
-  readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating';
+  readonly isBadEvent: boolean;
+  readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating' | 'BadEvent';
 }
 
+/** @name PalletEvmMigrationEvent */
+export interface PalletEvmMigrationEvent extends Enum {
+  readonly isTestEvent: boolean;
+  readonly type: 'TestEvent';
+}
+
 /** @name PalletForeignAssetsAssetIds */
 export interface PalletForeignAssetsAssetIds extends Enum {
   readonly isForeignAssetId: boolean;
@@ -2004,7 +2018,11 @@
     readonly maxTestValue: u32;
   } & Struct;
   readonly isJustTakeFee: boolean;
-  readonly type: 'Enable' | 'SetTestValue' | 'SetTestValueAndRollback' | 'IncTestValue' | 'SelfCancelingInc' | 'JustTakeFee';
+  readonly isBatchAll: boolean;
+  readonly asBatchAll: {
+    readonly calls: Vec<Call>;
+  } & Struct;
+  readonly type: 'Enable' | 'SetTestValue' | 'SetTestValueAndRollback' | 'IncTestValue' | 'SelfCancelingInc' | 'JustTakeFee' | 'BatchAll';
 }
 
 /** @name PalletTestUtilsError */
@@ -2018,7 +2036,8 @@
 export interface PalletTestUtilsEvent extends Enum {
   readonly isValueIsSet: boolean;
   readonly isShouldRollback: boolean;
-  readonly type: 'ValueIsSet' | 'ShouldRollback';
+  readonly isBatchCompleted: boolean;
+  readonly type: 'ValueIsSet' | 'ShouldRollback' | 'BatchCompleted';
 }
 
 /** @name PalletTimestampCall */
@@ -2327,47 +2346,76 @@
   readonly type: 'CollectionSponsorRemoved' | 'CollectionAdminAdded' | 'CollectionOwnedChanged' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionAdminRemoved' | 'AllowListAddressRemoved' | 'AllowListAddressAdded' | 'CollectionLimitSet' | 'CollectionPermissionSet';
 }
 
-/** @name PalletUniqueSchedulerCall */
-export interface PalletUniqueSchedulerCall extends Enum {
+/** @name PalletUniqueSchedulerV2BlockAgenda */
+export interface PalletUniqueSchedulerV2BlockAgenda extends Struct {
+  readonly agenda: Vec<Option<PalletUniqueSchedulerV2Scheduled>>;
+  readonly freePlaces: u32;
+}
+
+/** @name PalletUniqueSchedulerV2Call */
+export interface PalletUniqueSchedulerV2Call extends Enum {
+  readonly isSchedule: boolean;
+  readonly asSchedule: {
+    readonly when: u32;
+    readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+    readonly priority: Option<u8>;
+    readonly call: Call;
+  } & Struct;
+  readonly isCancel: boolean;
+  readonly asCancel: {
+    readonly when: u32;
+    readonly index: u32;
+  } & Struct;
   readonly isScheduleNamed: boolean;
   readonly asScheduleNamed: {
     readonly id: U8aFixed;
     readonly when: u32;
     readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
     readonly priority: Option<u8>;
-    readonly call: FrameSupportScheduleMaybeHashed;
+    readonly call: Call;
   } & Struct;
   readonly isCancelNamed: boolean;
   readonly asCancelNamed: {
     readonly id: U8aFixed;
   } & Struct;
+  readonly isScheduleAfter: boolean;
+  readonly asScheduleAfter: {
+    readonly after: u32;
+    readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+    readonly priority: Option<u8>;
+    readonly call: Call;
+  } & Struct;
   readonly isScheduleNamedAfter: boolean;
   readonly asScheduleNamedAfter: {
     readonly id: U8aFixed;
     readonly after: u32;
     readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
     readonly priority: Option<u8>;
-    readonly call: FrameSupportScheduleMaybeHashed;
+    readonly call: Call;
   } & Struct;
   readonly isChangeNamedPriority: boolean;
   readonly asChangeNamedPriority: {
     readonly id: U8aFixed;
     readonly priority: u8;
   } & Struct;
-  readonly type: 'ScheduleNamed' | 'CancelNamed' | 'ScheduleNamedAfter' | 'ChangeNamedPriority';
+  readonly type: 'Schedule' | 'Cancel' | 'ScheduleNamed' | 'CancelNamed' | 'ScheduleAfter' | 'ScheduleNamedAfter' | 'ChangeNamedPriority';
 }
 
-/** @name PalletUniqueSchedulerError */
-export interface PalletUniqueSchedulerError extends Enum {
+/** @name PalletUniqueSchedulerV2Error */
+export interface PalletUniqueSchedulerV2Error extends Enum {
   readonly isFailedToSchedule: boolean;
+  readonly isAgendaIsExhausted: boolean;
+  readonly isScheduledCallCorrupted: boolean;
+  readonly isPreimageNotFound: boolean;
+  readonly isTooBigScheduledCall: boolean;
   readonly isNotFound: boolean;
   readonly isTargetBlockNumberInPast: boolean;
-  readonly isRescheduleNoChange: boolean;
-  readonly type: 'FailedToSchedule' | 'NotFound' | 'TargetBlockNumberInPast' | 'RescheduleNoChange';
+  readonly isNamed: boolean;
+  readonly type: 'FailedToSchedule' | 'AgendaIsExhausted' | 'ScheduledCallCorrupted' | 'PreimageNotFound' | 'TooBigScheduledCall' | 'NotFound' | 'TargetBlockNumberInPast' | 'Named';
 }
 
-/** @name PalletUniqueSchedulerEvent */
-export interface PalletUniqueSchedulerEvent extends Enum {
+/** @name PalletUniqueSchedulerV2Event */
+export interface PalletUniqueSchedulerV2Event extends Enum {
   readonly isScheduled: boolean;
   readonly asScheduled: {
     readonly when: u32;
@@ -2378,36 +2426,51 @@
     readonly when: u32;
     readonly index: u32;
   } & Struct;
+  readonly isDispatched: boolean;
+  readonly asDispatched: {
+    readonly task: ITuple<[u32, u32]>;
+    readonly id: Option<U8aFixed>;
+    readonly result: Result<Null, SpRuntimeDispatchError>;
+  } & Struct;
   readonly isPriorityChanged: boolean;
   readonly asPriorityChanged: {
-    readonly when: u32;
-    readonly index: u32;
+    readonly task: ITuple<[u32, u32]>;
     readonly priority: u8;
   } & Struct;
-  readonly isDispatched: boolean;
-  readonly asDispatched: {
+  readonly isCallUnavailable: boolean;
+  readonly asCallUnavailable: {
     readonly task: ITuple<[u32, u32]>;
     readonly id: Option<U8aFixed>;
-    readonly result: Result<Null, SpRuntimeDispatchError>;
   } & Struct;
-  readonly isCallLookupFailed: boolean;
-  readonly asCallLookupFailed: {
+  readonly isPermanentlyOverweight: boolean;
+  readonly asPermanentlyOverweight: {
     readonly task: ITuple<[u32, u32]>;
     readonly id: Option<U8aFixed>;
-    readonly error: FrameSupportScheduleLookupError;
   } & Struct;
-  readonly type: 'Scheduled' | 'Canceled' | 'PriorityChanged' | 'Dispatched' | 'CallLookupFailed';
+  readonly type: 'Scheduled' | 'Canceled' | 'Dispatched' | 'PriorityChanged' | 'CallUnavailable' | 'PermanentlyOverweight';
 }
 
-/** @name PalletUniqueSchedulerScheduledV3 */
-export interface PalletUniqueSchedulerScheduledV3 extends Struct {
+/** @name PalletUniqueSchedulerV2Scheduled */
+export interface PalletUniqueSchedulerV2Scheduled extends Struct {
   readonly maybeId: Option<U8aFixed>;
   readonly priority: u8;
-  readonly call: FrameSupportScheduleMaybeHashed;
+  readonly call: PalletUniqueSchedulerV2ScheduledCall;
   readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
   readonly origin: OpalRuntimeOriginCaller;
 }
 
+/** @name PalletUniqueSchedulerV2ScheduledCall */
+export interface PalletUniqueSchedulerV2ScheduledCall extends Enum {
+  readonly isInline: boolean;
+  readonly asInline: Bytes;
+  readonly isPreimageLookup: boolean;
+  readonly asPreimageLookup: {
+    readonly hash_: H256;
+    readonly unboundedLen: u32;
+  } & Struct;
+  readonly type: 'Inline' | 'PreimageLookup';
+}
+
 /** @name PalletXcmCall */
 export interface PalletXcmCall extends Enum {
   readonly isSend: boolean;
modifiedtests/src/interfaces/lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/lookup.ts
+++ b/tests/src/interfaces/lookup.ts
@@ -1004,9 +1004,9 @@
     }
   },
   /**
-   * Lookup93: pallet_unique_scheduler::pallet::Event<T>
+   * Lookup93: pallet_unique_scheduler_v2::pallet::Event<T>
    **/
-  PalletUniqueSchedulerEvent: {
+  PalletUniqueSchedulerV2Event: {
     _enum: {
       Scheduled: {
         when: 'u32',
@@ -1016,31 +1016,27 @@
         when: 'u32',
         index: 'u32',
       },
+      Dispatched: {
+        task: '(u32,u32)',
+        id: 'Option<[u8;32]>',
+        result: 'Result<Null, SpRuntimeDispatchError>',
+      },
       PriorityChanged: {
-        when: 'u32',
-        index: 'u32',
+        task: '(u32,u32)',
         priority: 'u8',
       },
-      Dispatched: {
+      CallUnavailable: {
         task: '(u32,u32)',
-        id: 'Option<[u8;16]>',
-        result: 'Result<Null, SpRuntimeDispatchError>',
+        id: 'Option<[u8;32]>',
       },
-      CallLookupFailed: {
+      PermanentlyOverweight: {
         task: '(u32,u32)',
-        id: 'Option<[u8;16]>',
-        error: 'FrameSupportScheduleLookupError'
+        id: 'Option<[u8;32]>'
       }
     }
   },
   /**
-   * Lookup96: frame_support::traits::schedule::LookupError
-   **/
-  FrameSupportScheduleLookupError: {
-    _enum: ['Unknown', 'BadFormat']
-  },
-  /**
-   * Lookup97: pallet_common::pallet::Event<T>
+   * Lookup96: pallet_common::pallet::Event<T>
    **/
   PalletCommonEvent: {
     _enum: {
@@ -1058,7 +1054,7 @@
     }
   },
   /**
-   * Lookup100: pallet_structure::pallet::Event<T>
+   * Lookup99: pallet_structure::pallet::Event<T>
    **/
   PalletStructureEvent: {
     _enum: {
@@ -1066,7 +1062,7 @@
     }
   },
   /**
-   * Lookup101: pallet_rmrk_core::pallet::Event<T>
+   * Lookup100: pallet_rmrk_core::pallet::Event<T>
    **/
   PalletRmrkCoreEvent: {
     _enum: {
@@ -1143,7 +1139,7 @@
     }
   },
   /**
-   * Lookup102: rmrk_traits::nft::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>
+   * Lookup101: rmrk_traits::nft::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>
    **/
   RmrkTraitsNftAccountIdOrCollectionNftTuple: {
     _enum: {
@@ -1152,7 +1148,7 @@
     }
   },
   /**
-   * Lookup107: pallet_rmrk_equip::pallet::Event<T>
+   * Lookup106: pallet_rmrk_equip::pallet::Event<T>
    **/
   PalletRmrkEquipEvent: {
     _enum: {
@@ -1167,7 +1163,7 @@
     }
   },
   /**
-   * Lookup108: pallet_app_promotion::pallet::Event<T>
+   * Lookup107: pallet_app_promotion::pallet::Event<T>
    **/
   PalletAppPromotionEvent: {
     _enum: {
@@ -1178,7 +1174,7 @@
     }
   },
   /**
-   * Lookup109: pallet_foreign_assets::module::Event<T>
+   * Lookup108: pallet_foreign_assets::module::Event<T>
    **/
   PalletForeignAssetsModuleEvent: {
     _enum: {
@@ -1203,7 +1199,7 @@
     }
   },
   /**
-   * Lookup110: pallet_foreign_assets::module::AssetMetadata<Balance>
+   * Lookup109: pallet_foreign_assets::module::AssetMetadata<Balance>
    **/
   PalletForeignAssetsModuleAssetMetadata: {
     name: 'Bytes',
@@ -1212,21 +1208,29 @@
     minimalBalance: 'u128'
   },
   /**
-   * Lookup111: pallet_evm::pallet::Event<T>
+   * Lookup110: pallet_evm::pallet::Event<T>
    **/
   PalletEvmEvent: {
     _enum: {
-      Log: 'EthereumLog',
-      Created: 'H160',
-      CreatedFailed: 'H160',
-      Executed: 'H160',
-      ExecutedFailed: 'H160',
-      BalanceDeposit: '(AccountId32,H160,U256)',
-      BalanceWithdraw: '(AccountId32,H160,U256)'
+      Log: {
+        log: 'EthereumLog',
+      },
+      Created: {
+        address: 'H160',
+      },
+      CreatedFailed: {
+        address: 'H160',
+      },
+      Executed: {
+        address: 'H160',
+      },
+      ExecutedFailed: {
+        address: 'H160'
+      }
     }
   },
   /**
-   * Lookup112: ethereum::log::Log
+   * Lookup111: ethereum::log::Log
    **/
   EthereumLog: {
     address: 'H160',
@@ -1234,15 +1238,20 @@
     data: 'Bytes'
   },
   /**
-   * Lookup116: pallet_ethereum::pallet::Event
+   * Lookup113: pallet_ethereum::pallet::Event
    **/
   PalletEthereumEvent: {
     _enum: {
-      Executed: '(H160,H160,H256,EvmCoreErrorExitReason)'
+      Executed: {
+        from: 'H160',
+        to: 'H160',
+        transactionHash: 'H256',
+        exitReason: 'EvmCoreErrorExitReason'
+      }
     }
   },
   /**
-   * Lookup117: evm_core::error::ExitReason
+   * Lookup114: evm_core::error::ExitReason
    **/
   EvmCoreErrorExitReason: {
     _enum: {
@@ -1253,13 +1262,13 @@
     }
   },
   /**
-   * Lookup118: evm_core::error::ExitSucceed
+   * Lookup115: evm_core::error::ExitSucceed
    **/
   EvmCoreErrorExitSucceed: {
     _enum: ['Stopped', 'Returned', 'Suicided']
   },
   /**
-   * Lookup119: evm_core::error::ExitError
+   * Lookup116: evm_core::error::ExitError
    **/
   EvmCoreErrorExitError: {
     _enum: {
@@ -1281,13 +1290,13 @@
     }
   },
   /**
-   * Lookup122: evm_core::error::ExitRevert
+   * Lookup119: evm_core::error::ExitRevert
    **/
   EvmCoreErrorExitRevert: {
     _enum: ['Reverted']
   },
   /**
-   * Lookup123: evm_core::error::ExitFatal
+   * Lookup120: evm_core::error::ExitFatal
    **/
   EvmCoreErrorExitFatal: {
     _enum: {
@@ -1298,7 +1307,7 @@
     }
   },
   /**
-   * Lookup124: pallet_evm_contract_helpers::pallet::Event<T>
+   * Lookup121: pallet_evm_contract_helpers::pallet::Event<T>
    **/
   PalletEvmContractHelpersEvent: {
     _enum: {
@@ -1308,19 +1317,25 @@
     }
   },
   /**
-   * Lookup125: pallet_maintenance::pallet::Event<T>
+   * Lookup122: pallet_evm_migration::pallet::Event<T>
+   **/
+  PalletEvmMigrationEvent: {
+    _enum: ['TestEvent']
+  },
+  /**
+   * Lookup123: pallet_maintenance::pallet::Event<T>
    **/
   PalletMaintenanceEvent: {
     _enum: ['MaintenanceEnabled', 'MaintenanceDisabled']
   },
   /**
-   * Lookup126: pallet_test_utils::pallet::Event<T>
+   * Lookup124: pallet_test_utils::pallet::Event<T>
    **/
   PalletTestUtilsEvent: {
-    _enum: ['ValueIsSet', 'ShouldRollback']
+    _enum: ['ValueIsSet', 'ShouldRollback', 'BatchCompleted']
   },
   /**
-   * Lookup127: frame_system::Phase
+   * Lookup125: frame_system::Phase
    **/
   FrameSystemPhase: {
     _enum: {
@@ -1330,14 +1345,14 @@
     }
   },
   /**
-   * Lookup129: frame_system::LastRuntimeUpgradeInfo
+   * Lookup127: frame_system::LastRuntimeUpgradeInfo
    **/
   FrameSystemLastRuntimeUpgradeInfo: {
     specVersion: 'Compact<u32>',
     specName: 'Text'
   },
   /**
-   * Lookup130: frame_system::pallet::Call<T>
+   * Lookup128: frame_system::pallet::Call<T>
    **/
   FrameSystemCall: {
     _enum: {
@@ -1375,7 +1390,7 @@
     }
   },
   /**
-   * Lookup135: frame_system::limits::BlockWeights
+   * Lookup133: frame_system::limits::BlockWeights
    **/
   FrameSystemLimitsBlockWeights: {
     baseBlock: 'Weight',
@@ -1383,7 +1398,7 @@
     perClass: 'FrameSupportDispatchPerDispatchClassWeightsPerClass'
   },
   /**
-   * Lookup136: frame_support::dispatch::PerDispatchClass<frame_system::limits::WeightsPerClass>
+   * Lookup134: frame_support::dispatch::PerDispatchClass<frame_system::limits::WeightsPerClass>
    **/
   FrameSupportDispatchPerDispatchClassWeightsPerClass: {
     normal: 'FrameSystemLimitsWeightsPerClass',
@@ -1391,7 +1406,7 @@
     mandatory: 'FrameSystemLimitsWeightsPerClass'
   },
   /**
-   * Lookup137: frame_system::limits::WeightsPerClass
+   * Lookup135: frame_system::limits::WeightsPerClass
    **/
   FrameSystemLimitsWeightsPerClass: {
     baseExtrinsic: 'Weight',
@@ -1400,13 +1415,13 @@
     reserved: 'Option<Weight>'
   },
   /**
-   * Lookup139: frame_system::limits::BlockLength
+   * Lookup137: frame_system::limits::BlockLength
    **/
   FrameSystemLimitsBlockLength: {
     max: 'FrameSupportDispatchPerDispatchClassU32'
   },
   /**
-   * Lookup140: frame_support::dispatch::PerDispatchClass<T>
+   * Lookup138: frame_support::dispatch::PerDispatchClass<T>
    **/
   FrameSupportDispatchPerDispatchClassU32: {
     normal: 'u32',
@@ -1414,14 +1429,14 @@
     mandatory: 'u32'
   },
   /**
-   * Lookup141: sp_weights::RuntimeDbWeight
+   * Lookup139: sp_weights::RuntimeDbWeight
    **/
   SpWeightsRuntimeDbWeight: {
     read: 'u64',
     write: 'u64'
   },
   /**
-   * Lookup142: sp_version::RuntimeVersion
+   * Lookup140: sp_version::RuntimeVersion
    **/
   SpVersionRuntimeVersion: {
     specName: 'Text',
@@ -1434,13 +1449,13 @@
     stateVersion: 'u8'
   },
   /**
-   * Lookup147: frame_system::pallet::Error<T>
+   * Lookup145: frame_system::pallet::Error<T>
    **/
   FrameSystemError: {
     _enum: ['InvalidSpecName', 'SpecVersionNeedsToIncrease', 'FailedToExtractRuntimeVersion', 'NonDefaultComposite', 'NonZeroRefCount', 'CallFiltered']
   },
   /**
-   * Lookup148: polkadot_primitives::v2::PersistedValidationData<primitive_types::H256, N>
+   * Lookup146: polkadot_primitives::v2::PersistedValidationData<primitive_types::H256, N>
    **/
   PolkadotPrimitivesV2PersistedValidationData: {
     parentHead: 'Bytes',
@@ -1449,19 +1464,19 @@
     maxPovSize: 'u32'
   },
   /**
-   * Lookup151: polkadot_primitives::v2::UpgradeRestriction
+   * Lookup149: polkadot_primitives::v2::UpgradeRestriction
    **/
   PolkadotPrimitivesV2UpgradeRestriction: {
     _enum: ['Present']
   },
   /**
-   * Lookup152: sp_trie::storage_proof::StorageProof
+   * Lookup150: sp_trie::storage_proof::StorageProof
    **/
   SpTrieStorageProof: {
     trieNodes: 'BTreeSet<Bytes>'
   },
   /**
-   * Lookup154: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot
+   * Lookup152: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot
    **/
   CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot: {
     dmqMqcHead: 'H256',
@@ -1470,7 +1485,7 @@
     egressChannels: 'Vec<(u32,PolkadotPrimitivesV2AbridgedHrmpChannel)>'
   },
   /**
-   * Lookup157: polkadot_primitives::v2::AbridgedHrmpChannel
+   * Lookup155: polkadot_primitives::v2::AbridgedHrmpChannel
    **/
   PolkadotPrimitivesV2AbridgedHrmpChannel: {
     maxCapacity: 'u32',
@@ -1481,7 +1496,7 @@
     mqcHead: 'Option<H256>'
   },
   /**
-   * Lookup158: polkadot_primitives::v2::AbridgedHostConfiguration
+   * Lookup156: polkadot_primitives::v2::AbridgedHostConfiguration
    **/
   PolkadotPrimitivesV2AbridgedHostConfiguration: {
     maxCodeSize: 'u32',
@@ -1495,14 +1510,14 @@
     validationUpgradeDelay: 'u32'
   },
   /**
-   * Lookup164: polkadot_core_primitives::OutboundHrmpMessage<polkadot_parachain::primitives::Id>
+   * Lookup162: polkadot_core_primitives::OutboundHrmpMessage<polkadot_parachain::primitives::Id>
    **/
   PolkadotCorePrimitivesOutboundHrmpMessage: {
     recipient: 'u32',
     data: 'Bytes'
   },
   /**
-   * Lookup165: cumulus_pallet_parachain_system::pallet::Call<T>
+   * Lookup163: cumulus_pallet_parachain_system::pallet::Call<T>
    **/
   CumulusPalletParachainSystemCall: {
     _enum: {
@@ -1521,7 +1536,7 @@
     }
   },
   /**
-   * Lookup166: cumulus_primitives_parachain_inherent::ParachainInherentData
+   * Lookup164: cumulus_primitives_parachain_inherent::ParachainInherentData
    **/
   CumulusPrimitivesParachainInherentParachainInherentData: {
     validationData: 'PolkadotPrimitivesV2PersistedValidationData',
@@ -1530,27 +1545,27 @@
     horizontalMessages: 'BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>'
   },
   /**
-   * Lookup168: polkadot_core_primitives::InboundDownwardMessage<BlockNumber>
+   * Lookup166: polkadot_core_primitives::InboundDownwardMessage<BlockNumber>
    **/
   PolkadotCorePrimitivesInboundDownwardMessage: {
     sentAt: 'u32',
     msg: 'Bytes'
   },
   /**
-   * Lookup171: polkadot_core_primitives::InboundHrmpMessage<BlockNumber>
+   * Lookup169: polkadot_core_primitives::InboundHrmpMessage<BlockNumber>
    **/
   PolkadotCorePrimitivesInboundHrmpMessage: {
     sentAt: 'u32',
     data: 'Bytes'
   },
   /**
-   * Lookup174: cumulus_pallet_parachain_system::pallet::Error<T>
+   * Lookup172: cumulus_pallet_parachain_system::pallet::Error<T>
    **/
   CumulusPalletParachainSystemError: {
     _enum: ['OverlappingUpgrades', 'ProhibitedByPolkadot', 'TooBig', 'ValidationDataNotAvailable', 'HostConfigurationNotAvailable', 'NotScheduled', 'NothingAuthorized', 'Unauthorized']
   },
   /**
-   * Lookup176: pallet_balances::BalanceLock<Balance>
+   * Lookup174: pallet_balances::BalanceLock<Balance>
    **/
   PalletBalancesBalanceLock: {
     id: '[u8;8]',
@@ -1558,26 +1573,26 @@
     reasons: 'PalletBalancesReasons'
   },
   /**
-   * Lookup177: pallet_balances::Reasons
+   * Lookup175: pallet_balances::Reasons
    **/
   PalletBalancesReasons: {
     _enum: ['Fee', 'Misc', 'All']
   },
   /**
-   * Lookup180: pallet_balances::ReserveData<ReserveIdentifier, Balance>
+   * Lookup178: pallet_balances::ReserveData<ReserveIdentifier, Balance>
    **/
   PalletBalancesReserveData: {
     id: '[u8;16]',
     amount: 'u128'
   },
   /**
-   * Lookup182: pallet_balances::Releases
+   * Lookup180: pallet_balances::Releases
    **/
   PalletBalancesReleases: {
     _enum: ['V1_0_0', 'V2_0_0']
   },
   /**
-   * Lookup183: pallet_balances::pallet::Call<T, I>
+   * Lookup181: pallet_balances::pallet::Call<T, I>
    **/
   PalletBalancesCall: {
     _enum: {
@@ -1610,13 +1625,13 @@
     }
   },
   /**
-   * Lookup186: pallet_balances::pallet::Error<T, I>
+   * Lookup184: pallet_balances::pallet::Error<T, I>
    **/
   PalletBalancesError: {
     _enum: ['VestingBalance', 'LiquidityRestrictions', 'InsufficientBalance', 'ExistentialDeposit', 'KeepAlive', 'ExistingVestingSchedule', 'DeadAccount', 'TooManyReserves']
   },
   /**
-   * Lookup188: pallet_timestamp::pallet::Call<T>
+   * Lookup186: pallet_timestamp::pallet::Call<T>
    **/
   PalletTimestampCall: {
     _enum: {
@@ -1626,13 +1641,13 @@
     }
   },
   /**
-   * Lookup190: pallet_transaction_payment::Releases
+   * Lookup188: pallet_transaction_payment::Releases
    **/
   PalletTransactionPaymentReleases: {
     _enum: ['V1Ancient', 'V2']
   },
   /**
-   * Lookup191: pallet_treasury::Proposal<sp_core::crypto::AccountId32, Balance>
+   * Lookup189: pallet_treasury::Proposal<sp_core::crypto::AccountId32, Balance>
    **/
   PalletTreasuryProposal: {
     proposer: 'AccountId32',
@@ -1641,7 +1656,7 @@
     bond: 'u128'
   },
   /**
-   * Lookup194: pallet_treasury::pallet::Call<T, I>
+   * Lookup192: pallet_treasury::pallet::Call<T, I>
    **/
   PalletTreasuryCall: {
     _enum: {
@@ -1665,17 +1680,17 @@
     }
   },
   /**
-   * Lookup197: frame_support::PalletId
+   * Lookup195: frame_support::PalletId
    **/
   FrameSupportPalletId: '[u8;8]',
   /**
-   * Lookup198: pallet_treasury::pallet::Error<T, I>
+   * Lookup196: pallet_treasury::pallet::Error<T, I>
    **/
   PalletTreasuryError: {
     _enum: ['InsufficientProposersBalance', 'InvalidIndex', 'TooManyApprovals', 'InsufficientPermission', 'ProposalNotApproved']
   },
   /**
-   * Lookup199: pallet_sudo::pallet::Call<T>
+   * Lookup197: pallet_sudo::pallet::Call<T>
    **/
   PalletSudoCall: {
     _enum: {
@@ -1699,7 +1714,7 @@
     }
   },
   /**
-   * Lookup201: orml_vesting::module::Call<T>
+   * Lookup199: orml_vesting::module::Call<T>
    **/
   OrmlVestingModuleCall: {
     _enum: {
@@ -1718,7 +1733,7 @@
     }
   },
   /**
-   * Lookup203: orml_xtokens::module::Call<T>
+   * Lookup201: orml_xtokens::module::Call<T>
    **/
   OrmlXtokensModuleCall: {
     _enum: {
@@ -1761,7 +1776,7 @@
     }
   },
   /**
-   * Lookup204: xcm::VersionedMultiAsset
+   * Lookup202: xcm::VersionedMultiAsset
    **/
   XcmVersionedMultiAsset: {
     _enum: {
@@ -1770,7 +1785,7 @@
     }
   },
   /**
-   * Lookup207: orml_tokens::module::Call<T>
+   * Lookup205: orml_tokens::module::Call<T>
    **/
   OrmlTokensModuleCall: {
     _enum: {
@@ -1804,7 +1819,7 @@
     }
   },
   /**
-   * Lookup208: cumulus_pallet_xcmp_queue::pallet::Call<T>
+   * Lookup206: cumulus_pallet_xcmp_queue::pallet::Call<T>
    **/
   CumulusPalletXcmpQueueCall: {
     _enum: {
@@ -1853,7 +1868,7 @@
     }
   },
   /**
-   * Lookup209: pallet_xcm::pallet::Call<T>
+   * Lookup207: pallet_xcm::pallet::Call<T>
    **/
   PalletXcmCall: {
     _enum: {
@@ -1907,7 +1922,7 @@
     }
   },
   /**
-   * Lookup210: xcm::VersionedXcm<RuntimeCall>
+   * Lookup208: xcm::VersionedXcm<RuntimeCall>
    **/
   XcmVersionedXcm: {
     _enum: {
@@ -1917,7 +1932,7 @@
     }
   },
   /**
-   * Lookup211: xcm::v0::Xcm<RuntimeCall>
+   * Lookup209: xcm::v0::Xcm<RuntimeCall>
    **/
   XcmV0Xcm: {
     _enum: {
@@ -1971,7 +1986,7 @@
     }
   },
   /**
-   * Lookup213: xcm::v0::order::Order<RuntimeCall>
+   * Lookup211: xcm::v0::order::Order<RuntimeCall>
    **/
   XcmV0Order: {
     _enum: {
@@ -2014,7 +2029,7 @@
     }
   },
   /**
-   * Lookup215: xcm::v0::Response
+   * Lookup213: xcm::v0::Response
    **/
   XcmV0Response: {
     _enum: {
@@ -2022,7 +2037,7 @@
     }
   },
   /**
-   * Lookup216: xcm::v1::Xcm<RuntimeCall>
+   * Lookup214: xcm::v1::Xcm<RuntimeCall>
    **/
   XcmV1Xcm: {
     _enum: {
@@ -2081,7 +2096,7 @@
     }
   },
   /**
-   * Lookup218: xcm::v1::order::Order<RuntimeCall>
+   * Lookup216: xcm::v1::order::Order<RuntimeCall>
    **/
   XcmV1Order: {
     _enum: {
@@ -2126,7 +2141,7 @@
     }
   },
   /**
-   * Lookup220: xcm::v1::Response
+   * Lookup218: xcm::v1::Response
    **/
   XcmV1Response: {
     _enum: {
@@ -2135,11 +2150,11 @@
     }
   },
   /**
-   * Lookup234: cumulus_pallet_xcm::pallet::Call<T>
+   * Lookup232: cumulus_pallet_xcm::pallet::Call<T>
    **/
   CumulusPalletXcmCall: 'Null',
   /**
-   * Lookup235: cumulus_pallet_dmp_queue::pallet::Call<T>
+   * Lookup233: cumulus_pallet_dmp_queue::pallet::Call<T>
    **/
   CumulusPalletDmpQueueCall: {
     _enum: {
@@ -2150,7 +2165,7 @@
     }
   },
   /**
-   * Lookup236: pallet_inflation::pallet::Call<T>
+   * Lookup234: pallet_inflation::pallet::Call<T>
    **/
   PalletInflationCall: {
     _enum: {
@@ -2160,7 +2175,7 @@
     }
   },
   /**
-   * Lookup237: pallet_unique::Call<T>
+   * Lookup235: pallet_unique::Call<T>
    **/
   PalletUniqueCall: {
     _enum: {
@@ -2292,7 +2307,7 @@
     }
   },
   /**
-   * Lookup242: up_data_structs::CollectionMode
+   * Lookup240: up_data_structs::CollectionMode
    **/
   UpDataStructsCollectionMode: {
     _enum: {
@@ -2302,7 +2317,7 @@
     }
   },
   /**
-   * Lookup243: up_data_structs::CreateCollectionData<sp_core::crypto::AccountId32>
+   * Lookup241: up_data_structs::CreateCollectionData<sp_core::crypto::AccountId32>
    **/
   UpDataStructsCreateCollectionData: {
     mode: 'UpDataStructsCollectionMode',
@@ -2317,13 +2332,13 @@
     properties: 'Vec<UpDataStructsProperty>'
   },
   /**
-   * Lookup245: up_data_structs::AccessMode
+   * Lookup243: up_data_structs::AccessMode
    **/
   UpDataStructsAccessMode: {
     _enum: ['Normal', 'AllowList']
   },
   /**
-   * Lookup247: up_data_structs::CollectionLimits
+   * Lookup245: up_data_structs::CollectionLimits
    **/
   UpDataStructsCollectionLimits: {
     accountTokenOwnershipLimit: 'Option<u32>',
@@ -2337,7 +2352,7 @@
     transfersEnabled: 'Option<bool>'
   },
   /**
-   * Lookup249: up_data_structs::SponsoringRateLimit
+   * Lookup247: up_data_structs::SponsoringRateLimit
    **/
   UpDataStructsSponsoringRateLimit: {
     _enum: {
@@ -2346,7 +2361,7 @@
     }
   },
   /**
-   * Lookup252: up_data_structs::CollectionPermissions
+   * Lookup250: up_data_structs::CollectionPermissions
    **/
   UpDataStructsCollectionPermissions: {
     access: 'Option<UpDataStructsAccessMode>',
@@ -2354,7 +2369,7 @@
     nesting: 'Option<UpDataStructsNestingPermissions>'
   },
   /**
-   * Lookup254: up_data_structs::NestingPermissions
+   * Lookup252: up_data_structs::NestingPermissions
    **/
   UpDataStructsNestingPermissions: {
     tokenOwner: 'bool',
@@ -2362,18 +2377,18 @@
     restricted: 'Option<UpDataStructsOwnerRestrictedSet>'
   },
   /**
-   * Lookup256: up_data_structs::OwnerRestrictedSet
+   * Lookup254: up_data_structs::OwnerRestrictedSet
    **/
   UpDataStructsOwnerRestrictedSet: 'BTreeSet<u32>',
   /**
-   * Lookup261: up_data_structs::PropertyKeyPermission
+   * Lookup259: up_data_structs::PropertyKeyPermission
    **/
   UpDataStructsPropertyKeyPermission: {
     key: 'Bytes',
     permission: 'UpDataStructsPropertyPermission'
   },
   /**
-   * Lookup262: up_data_structs::PropertyPermission
+   * Lookup260: up_data_structs::PropertyPermission
    **/
   UpDataStructsPropertyPermission: {
     mutable: 'bool',
@@ -2381,14 +2396,14 @@
     tokenOwner: 'bool'
   },
   /**
-   * Lookup265: up_data_structs::Property
+   * Lookup263: up_data_structs::Property
    **/
   UpDataStructsProperty: {
     key: 'Bytes',
     value: 'Bytes'
   },
   /**
-   * Lookup268: up_data_structs::CreateItemData
+   * Lookup266: up_data_structs::CreateItemData
    **/
   UpDataStructsCreateItemData: {
     _enum: {
@@ -2398,26 +2413,26 @@
     }
   },
   /**
-   * Lookup269: up_data_structs::CreateNftData
+   * Lookup267: up_data_structs::CreateNftData
    **/
   UpDataStructsCreateNftData: {
     properties: 'Vec<UpDataStructsProperty>'
   },
   /**
-   * Lookup270: up_data_structs::CreateFungibleData
+   * Lookup268: up_data_structs::CreateFungibleData
    **/
   UpDataStructsCreateFungibleData: {
     value: 'u128'
   },
   /**
-   * Lookup271: up_data_structs::CreateReFungibleData
+   * Lookup269: up_data_structs::CreateReFungibleData
    **/
   UpDataStructsCreateReFungibleData: {
     pieces: 'u128',
     properties: 'Vec<UpDataStructsProperty>'
   },
   /**
-   * Lookup274: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup272: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsCreateItemExData: {
     _enum: {
@@ -2428,14 +2443,14 @@
     }
   },
   /**
-   * Lookup276: up_data_structs::CreateNftExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup274: up_data_structs::CreateNftExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsCreateNftExData: {
     properties: 'Vec<UpDataStructsProperty>',
     owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
   },
   /**
-   * Lookup283: up_data_structs::CreateRefungibleExSingleOwner<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup281: up_data_structs::CreateRefungibleExSingleOwner<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsCreateRefungibleExSingleOwner: {
     user: 'PalletEvmAccountBasicCrossAccountIdRepr',
@@ -2443,51 +2458,58 @@
     properties: 'Vec<UpDataStructsProperty>'
   },
   /**
-   * Lookup285: up_data_structs::CreateRefungibleExMultipleOwners<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup283: up_data_structs::CreateRefungibleExMultipleOwners<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsCreateRefungibleExMultipleOwners: {
     users: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>',
     properties: 'Vec<UpDataStructsProperty>'
   },
   /**
-   * Lookup286: pallet_unique_scheduler::pallet::Call<T>
+   * Lookup284: pallet_unique_scheduler_v2::pallet::Call<T>
    **/
-  PalletUniqueSchedulerCall: {
+  PalletUniqueSchedulerV2Call: {
     _enum: {
+      schedule: {
+        when: 'u32',
+        maybePeriodic: 'Option<(u32,u32)>',
+        priority: 'Option<u8>',
+        call: 'Call',
+      },
+      cancel: {
+        when: 'u32',
+        index: 'u32',
+      },
       schedule_named: {
-        id: '[u8;16]',
+        id: '[u8;32]',
         when: 'u32',
         maybePeriodic: 'Option<(u32,u32)>',
         priority: 'Option<u8>',
-        call: 'FrameSupportScheduleMaybeHashed',
+        call: 'Call',
       },
       cancel_named: {
-        id: '[u8;16]',
+        id: '[u8;32]',
       },
+      schedule_after: {
+        after: 'u32',
+        maybePeriodic: 'Option<(u32,u32)>',
+        priority: 'Option<u8>',
+        call: 'Call',
+      },
       schedule_named_after: {
-        id: '[u8;16]',
+        id: '[u8;32]',
         after: 'u32',
         maybePeriodic: 'Option<(u32,u32)>',
         priority: 'Option<u8>',
-        call: 'FrameSupportScheduleMaybeHashed',
+        call: 'Call',
       },
       change_named_priority: {
-        id: '[u8;16]',
+        id: '[u8;32]',
         priority: 'u8'
       }
     }
   },
   /**
-   * Lookup289: frame_support::traits::schedule::MaybeHashed<opal_runtime::RuntimeCall, primitive_types::H256>
-   **/
-  FrameSupportScheduleMaybeHashed: {
-    _enum: {
-      Value: 'Call',
-      Hash: 'H256'
-    }
-  },
-  /**
-   * Lookup290: pallet_configuration::pallet::Call<T>
+   * Lookup287: pallet_configuration::pallet::Call<T>
    **/
   PalletConfigurationCall: {
     _enum: {
@@ -2500,15 +2522,15 @@
     }
   },
   /**
-   * Lookup292: pallet_template_transaction_payment::Call<T>
+   * Lookup289: pallet_template_transaction_payment::Call<T>
    **/
   PalletTemplateTransactionPaymentCall: 'Null',
   /**
-   * Lookup293: pallet_structure::pallet::Call<T>
+   * Lookup290: pallet_structure::pallet::Call<T>
    **/
   PalletStructureCall: 'Null',
   /**
-   * Lookup294: pallet_rmrk_core::pallet::Call<T>
+   * Lookup291: pallet_rmrk_core::pallet::Call<T>
    **/
   PalletRmrkCoreCall: {
     _enum: {
@@ -2599,7 +2621,7 @@
     }
   },
   /**
-   * Lookup300: rmrk_traits::resource::ResourceTypes<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup297: rmrk_traits::resource::ResourceTypes<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsResourceResourceTypes: {
     _enum: {
@@ -2609,7 +2631,7 @@
     }
   },
   /**
-   * Lookup302: rmrk_traits::resource::BasicResource<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup299: rmrk_traits::resource::BasicResource<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsResourceBasicResource: {
     src: 'Option<Bytes>',
@@ -2618,7 +2640,7 @@
     thumb: 'Option<Bytes>'
   },
   /**
-   * Lookup304: rmrk_traits::resource::ComposableResource<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup301: rmrk_traits::resource::ComposableResource<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsResourceComposableResource: {
     parts: 'Vec<u32>',
@@ -2629,7 +2651,7 @@
     thumb: 'Option<Bytes>'
   },
   /**
-   * Lookup305: rmrk_traits::resource::SlotResource<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup302: rmrk_traits::resource::SlotResource<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsResourceSlotResource: {
     base: 'u32',
@@ -2640,7 +2662,7 @@
     thumb: 'Option<Bytes>'
   },
   /**
-   * Lookup308: pallet_rmrk_equip::pallet::Call<T>
+   * Lookup305: pallet_rmrk_equip::pallet::Call<T>
    **/
   PalletRmrkEquipCall: {
     _enum: {
@@ -2661,7 +2683,7 @@
     }
   },
   /**
-   * Lookup311: rmrk_traits::part::PartType<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup308: rmrk_traits::part::PartType<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsPartPartType: {
     _enum: {
@@ -2670,7 +2692,7 @@
     }
   },
   /**
-   * Lookup313: rmrk_traits::part::FixedPart<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup310: rmrk_traits::part::FixedPart<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsPartFixedPart: {
     id: 'u32',
@@ -2678,7 +2700,7 @@
     src: 'Bytes'
   },
   /**
-   * Lookup314: rmrk_traits::part::SlotPart<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup311: rmrk_traits::part::SlotPart<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsPartSlotPart: {
     id: 'u32',
@@ -2687,7 +2709,7 @@
     z: 'u32'
   },
   /**
-   * Lookup315: rmrk_traits::part::EquippableList<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup312: rmrk_traits::part::EquippableList<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsPartEquippableList: {
     _enum: {
@@ -2697,7 +2719,7 @@
     }
   },
   /**
-   * Lookup317: rmrk_traits::theme::Theme<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<rmrk_traits::theme::ThemeProperty<sp_core::bounded::bounded_vec::BoundedVec<T, S>>, S>>
+   * Lookup314: rmrk_traits::theme::Theme<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<rmrk_traits::theme::ThemeProperty<sp_core::bounded::bounded_vec::BoundedVec<T, S>>, S>>
    **/
   RmrkTraitsTheme: {
     name: 'Bytes',
@@ -2705,14 +2727,14 @@
     inherit: 'bool'
   },
   /**
-   * Lookup319: rmrk_traits::theme::ThemeProperty<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup316: rmrk_traits::theme::ThemeProperty<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsThemeThemeProperty: {
     key: 'Bytes',
     value: 'Bytes'
   },
   /**
-   * Lookup321: pallet_app_promotion::pallet::Call<T>
+   * Lookup318: pallet_app_promotion::pallet::Call<T>
    **/
   PalletAppPromotionCall: {
     _enum: {
@@ -2741,7 +2763,7 @@
     }
   },
   /**
-   * Lookup322: pallet_foreign_assets::module::Call<T>
+   * Lookup319: pallet_foreign_assets::module::Call<T>
    **/
   PalletForeignAssetsModuleCall: {
     _enum: {
@@ -2758,7 +2780,7 @@
     }
   },
   /**
-   * Lookup323: pallet_evm::pallet::Call<T>
+   * Lookup320: pallet_evm::pallet::Call<T>
    **/
   PalletEvmCall: {
     _enum: {
@@ -2801,7 +2823,7 @@
     }
   },
   /**
-   * Lookup327: pallet_ethereum::pallet::Call<T>
+   * Lookup326: pallet_ethereum::pallet::Call<T>
    **/
   PalletEthereumCall: {
     _enum: {
@@ -2811,7 +2833,7 @@
     }
   },
   /**
-   * Lookup328: ethereum::transaction::TransactionV2
+   * Lookup327: ethereum::transaction::TransactionV2
    **/
   EthereumTransactionTransactionV2: {
     _enum: {
@@ -2821,7 +2843,7 @@
     }
   },
   /**
-   * Lookup329: ethereum::transaction::LegacyTransaction
+   * Lookup328: ethereum::transaction::LegacyTransaction
    **/
   EthereumTransactionLegacyTransaction: {
     nonce: 'U256',
@@ -2833,7 +2855,7 @@
     signature: 'EthereumTransactionTransactionSignature'
   },
   /**
-   * Lookup330: ethereum::transaction::TransactionAction
+   * Lookup329: ethereum::transaction::TransactionAction
    **/
   EthereumTransactionTransactionAction: {
     _enum: {
@@ -2842,7 +2864,7 @@
     }
   },
   /**
-   * Lookup331: ethereum::transaction::TransactionSignature
+   * Lookup330: ethereum::transaction::TransactionSignature
    **/
   EthereumTransactionTransactionSignature: {
     v: 'u64',
@@ -2850,7 +2872,7 @@
     s: 'H256'
   },
   /**
-   * Lookup333: ethereum::transaction::EIP2930Transaction
+   * Lookup332: ethereum::transaction::EIP2930Transaction
    **/
   EthereumTransactionEip2930Transaction: {
     chainId: 'u64',
@@ -2866,14 +2888,14 @@
     s: 'H256'
   },
   /**
-   * Lookup335: ethereum::transaction::AccessListItem
+   * Lookup334: ethereum::transaction::AccessListItem
    **/
   EthereumTransactionAccessListItem: {
     address: 'H160',
     storageKeys: 'Vec<H256>'
   },
   /**
-   * Lookup336: ethereum::transaction::EIP1559Transaction
+   * Lookup335: ethereum::transaction::EIP1559Transaction
    **/
   EthereumTransactionEip1559Transaction: {
     chainId: 'u64',
@@ -2890,7 +2912,7 @@
     s: 'H256'
   },
   /**
-   * Lookup337: pallet_evm_migration::pallet::Call<T>
+   * Lookup336: pallet_evm_migration::pallet::Call<T>
    **/
   PalletEvmMigrationCall: {
     _enum: {
@@ -2903,7 +2925,13 @@
       },
       finish: {
         address: 'H160',
-        code: 'Bytes'
+        code: 'Bytes',
+      },
+      insert_eth_logs: {
+        logs: 'Vec<EthereumLog>',
+      },
+      insert_events: {
+        events: 'Vec<Bytes>'
       }
     }
   },
@@ -2927,39 +2955,42 @@
       },
       inc_test_value: 'Null',
       self_canceling_inc: {
-        id: '[u8;16]',
+        id: '[u8;32]',
         maxTestValue: 'u32',
       },
-      just_take_fee: 'Null'
+      just_take_fee: 'Null',
+      batch_all: {
+        calls: 'Vec<Call>'
+      }
     }
   },
   /**
-   * Lookup342: pallet_sudo::pallet::Error<T>
+   * Lookup343: pallet_sudo::pallet::Error<T>
    **/
   PalletSudoError: {
     _enum: ['RequireSudo']
   },
   /**
-   * Lookup344: orml_vesting::module::Error<T>
+   * Lookup345: orml_vesting::module::Error<T>
    **/
   OrmlVestingModuleError: {
     _enum: ['ZeroVestingPeriod', 'ZeroVestingPeriodCount', 'InsufficientBalanceToLock', 'TooManyVestingSchedules', 'AmountLow', 'MaxVestingSchedulesExceeded']
   },
   /**
-   * Lookup345: orml_xtokens::module::Error<T>
+   * Lookup346: orml_xtokens::module::Error<T>
    **/
   OrmlXtokensModuleError: {
     _enum: ['AssetHasNoReserve', 'NotCrossChainTransfer', 'InvalidDest', 'NotCrossChainTransferableCurrency', 'UnweighableMessage', 'XcmExecutionFailed', 'CannotReanchor', 'InvalidAncestry', 'InvalidAsset', 'DestinationNotInvertible', 'BadVersion', 'DistinctReserveForAssetAndFee', 'ZeroFee', 'ZeroAmount', 'TooManyAssetsBeingSent', 'AssetIndexNonExistent', 'FeeNotEnough', 'NotSupportedMultiLocation', 'MinXcmFeeNotDefined']
   },
   /**
-   * Lookup348: orml_tokens::BalanceLock<Balance>
+   * Lookup349: orml_tokens::BalanceLock<Balance>
    **/
   OrmlTokensBalanceLock: {
     id: '[u8;8]',
     amount: 'u128'
   },
   /**
-   * Lookup350: orml_tokens::AccountData<Balance>
+   * Lookup351: orml_tokens::AccountData<Balance>
    **/
   OrmlTokensAccountData: {
     free: 'u128',
@@ -2967,20 +2998,20 @@
     frozen: 'u128'
   },
   /**
-   * Lookup352: orml_tokens::ReserveData<ReserveIdentifier, Balance>
+   * Lookup353: orml_tokens::ReserveData<ReserveIdentifier, Balance>
    **/
   OrmlTokensReserveData: {
     id: 'Null',
     amount: 'u128'
   },
   /**
-   * Lookup354: orml_tokens::module::Error<T>
+   * Lookup355: orml_tokens::module::Error<T>
    **/
   OrmlTokensModuleError: {
     _enum: ['BalanceTooLow', 'AmountIntoBalanceFailed', 'LiquidityRestrictions', 'MaxLocksExceeded', 'KeepAlive', 'ExistentialDeposit', 'DeadAccount', 'TooManyReserves']
   },
   /**
-   * Lookup356: cumulus_pallet_xcmp_queue::InboundChannelDetails
+   * Lookup357: cumulus_pallet_xcmp_queue::InboundChannelDetails
    **/
   CumulusPalletXcmpQueueInboundChannelDetails: {
     sender: 'u32',
@@ -2988,19 +3019,19 @@
     messageMetadata: 'Vec<(u32,PolkadotParachainPrimitivesXcmpMessageFormat)>'
   },
   /**
-   * Lookup357: cumulus_pallet_xcmp_queue::InboundState
+   * Lookup358: cumulus_pallet_xcmp_queue::InboundState
    **/
   CumulusPalletXcmpQueueInboundState: {
     _enum: ['Ok', 'Suspended']
   },
   /**
-   * Lookup360: polkadot_parachain::primitives::XcmpMessageFormat
+   * Lookup361: polkadot_parachain::primitives::XcmpMessageFormat
    **/
   PolkadotParachainPrimitivesXcmpMessageFormat: {
     _enum: ['ConcatenatedVersionedXcm', 'ConcatenatedEncodedBlob', 'Signals']
   },
   /**
-   * Lookup363: cumulus_pallet_xcmp_queue::OutboundChannelDetails
+   * Lookup364: cumulus_pallet_xcmp_queue::OutboundChannelDetails
    **/
   CumulusPalletXcmpQueueOutboundChannelDetails: {
     recipient: 'u32',
@@ -3010,13 +3041,13 @@
     lastIndex: 'u16'
   },
   /**
-   * Lookup364: cumulus_pallet_xcmp_queue::OutboundState
+   * Lookup365: cumulus_pallet_xcmp_queue::OutboundState
    **/
   CumulusPalletXcmpQueueOutboundState: {
     _enum: ['Ok', 'Suspended']
   },
   /**
-   * Lookup366: cumulus_pallet_xcmp_queue::QueueConfigData
+   * Lookup367: cumulus_pallet_xcmp_queue::QueueConfigData
    **/
   CumulusPalletXcmpQueueQueueConfigData: {
     suspendThreshold: 'u32',
@@ -3027,29 +3058,29 @@
     xcmpMaxIndividualWeight: 'Weight'
   },
   /**
-   * Lookup368: cumulus_pallet_xcmp_queue::pallet::Error<T>
+   * Lookup369: cumulus_pallet_xcmp_queue::pallet::Error<T>
    **/
   CumulusPalletXcmpQueueError: {
     _enum: ['FailedToSend', 'BadXcmOrigin', 'BadXcm', 'BadOverweightIndex', 'WeightOverLimit']
   },
   /**
-   * Lookup369: pallet_xcm::pallet::Error<T>
+   * Lookup370: pallet_xcm::pallet::Error<T>
    **/
   PalletXcmError: {
     _enum: ['Unreachable', 'SendFailure', 'Filtered', 'UnweighableMessage', 'DestinationNotInvertible', 'Empty', 'CannotReanchor', 'TooManyAssets', 'InvalidOrigin', 'BadVersion', 'BadLocation', 'NoSubscription', 'AlreadySubscribed']
   },
   /**
-   * Lookup370: cumulus_pallet_xcm::pallet::Error<T>
+   * Lookup371: cumulus_pallet_xcm::pallet::Error<T>
    **/
   CumulusPalletXcmError: 'Null',
   /**
-   * Lookup371: cumulus_pallet_dmp_queue::ConfigData
+   * Lookup372: cumulus_pallet_dmp_queue::ConfigData
    **/
   CumulusPalletDmpQueueConfigData: {
     maxIndividual: 'Weight'
   },
   /**
-   * Lookup372: cumulus_pallet_dmp_queue::PageIndexData
+   * Lookup373: cumulus_pallet_dmp_queue::PageIndexData
    **/
   CumulusPalletDmpQueuePageIndexData: {
     beginUsed: 'u32',
@@ -3057,30 +3088,52 @@
     overweightCount: 'u64'
   },
   /**
-   * Lookup375: cumulus_pallet_dmp_queue::pallet::Error<T>
+   * Lookup376: cumulus_pallet_dmp_queue::pallet::Error<T>
    **/
   CumulusPalletDmpQueueError: {
     _enum: ['Unknown', 'OverLimit']
   },
   /**
-   * Lookup379: pallet_unique::Error<T>
+   * Lookup380: pallet_unique::Error<T>
    **/
   PalletUniqueError: {
     _enum: ['CollectionDecimalPointLimitExceeded', 'ConfirmUnsetSponsorFail', 'EmptyArgument', 'RepartitionCalledOnNonRefungibleCollection']
   },
   /**
-   * Lookup382: pallet_unique_scheduler::ScheduledV3<frame_support::traits::schedule::MaybeHashed<opal_runtime::RuntimeCall, primitive_types::H256>, BlockNumber, opal_runtime::OriginCaller, sp_core::crypto::AccountId32>
+   * Lookup381: pallet_unique_scheduler_v2::BlockAgenda<T>
+   **/
+  PalletUniqueSchedulerV2BlockAgenda: {
+    agenda: 'Vec<Option<PalletUniqueSchedulerV2Scheduled>>',
+    freePlaces: 'u32'
+  },
+  /**
+   * Lookup384: pallet_unique_scheduler_v2::Scheduled<Name, pallet_unique_scheduler_v2::ScheduledCall<T>, BlockNumber, opal_runtime::OriginCaller, sp_core::crypto::AccountId32>
    **/
-  PalletUniqueSchedulerScheduledV3: {
-    maybeId: 'Option<[u8;16]>',
+  PalletUniqueSchedulerV2Scheduled: {
+    maybeId: 'Option<[u8;32]>',
     priority: 'u8',
-    call: 'FrameSupportScheduleMaybeHashed',
+    call: 'PalletUniqueSchedulerV2ScheduledCall',
     maybePeriodic: 'Option<(u32,u32)>',
     origin: 'OpalRuntimeOriginCaller'
   },
   /**
-   * Lookup383: opal_runtime::OriginCaller
+   * Lookup385: pallet_unique_scheduler_v2::ScheduledCall<T>
    **/
+  PalletUniqueSchedulerV2ScheduledCall: {
+    _enum: {
+      Inline: 'Bytes',
+      PreimageLookup: {
+        _alias: {
+          hash_: 'hash',
+        },
+        hash_: 'H256',
+        unboundedLen: 'u32'
+      }
+    }
+  },
+  /**
+   * Lookup387: opal_runtime::OriginCaller
+   **/
   OpalRuntimeOriginCaller: {
     _enum: {
       system: 'FrameSupportDispatchRawOrigin',
@@ -3188,7 +3241,7 @@
     }
   },
   /**
-   * Lookup384: frame_support::dispatch::RawOrigin<sp_core::crypto::AccountId32>
+   * Lookup388: frame_support::dispatch::RawOrigin<sp_core::crypto::AccountId32>
    **/
   FrameSupportDispatchRawOrigin: {
     _enum: {
@@ -3198,7 +3251,7 @@
     }
   },
   /**
-   * Lookup385: pallet_xcm::pallet::Origin
+   * Lookup389: pallet_xcm::pallet::Origin
    **/
   PalletXcmOrigin: {
     _enum: {
@@ -3207,7 +3260,7 @@
     }
   },
   /**
-   * Lookup386: cumulus_pallet_xcm::pallet::Origin
+   * Lookup390: cumulus_pallet_xcm::pallet::Origin
    **/
   CumulusPalletXcmOrigin: {
     _enum: {
@@ -3216,7 +3269,7 @@
     }
   },
   /**
-   * Lookup387: pallet_ethereum::RawOrigin
+   * Lookup391: pallet_ethereum::RawOrigin
    **/
   PalletEthereumRawOrigin: {
     _enum: {
@@ -3224,17 +3277,17 @@
     }
   },
   /**
-   * Lookup388: sp_core::Void
+   * Lookup392: sp_core::Void
    **/
   SpCoreVoid: 'Null',
   /**
-   * Lookup389: pallet_unique_scheduler::pallet::Error<T>
+   * Lookup394: pallet_unique_scheduler_v2::pallet::Error<T>
    **/
-  PalletUniqueSchedulerError: {
-    _enum: ['FailedToSchedule', 'NotFound', 'TargetBlockNumberInPast', 'RescheduleNoChange']
+  PalletUniqueSchedulerV2Error: {
+    _enum: ['FailedToSchedule', 'AgendaIsExhausted', 'ScheduledCallCorrupted', 'PreimageNotFound', 'TooBigScheduledCall', 'NotFound', 'TargetBlockNumberInPast', 'Named']
   },
   /**
-   * Lookup390: up_data_structs::Collection<sp_core::crypto::AccountId32>
+   * Lookup395: up_data_structs::Collection<sp_core::crypto::AccountId32>
    **/
   UpDataStructsCollection: {
     owner: 'AccountId32',
@@ -3248,7 +3301,7 @@
     flags: '[u8;1]'
   },
   /**
-   * Lookup391: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>
+   * Lookup396: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>
    **/
   UpDataStructsSponsorshipStateAccountId32: {
     _enum: {
@@ -3258,7 +3311,7 @@
     }
   },
   /**
-   * Lookup393: up_data_structs::Properties
+   * Lookup398: up_data_structs::Properties
    **/
   UpDataStructsProperties: {
     map: 'UpDataStructsPropertiesMapBoundedVec',
@@ -3266,15 +3319,15 @@
     spaceLimit: 'u32'
   },
   /**
-   * Lookup394: up_data_structs::PropertiesMap<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup399: up_data_structs::PropertiesMap<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   UpDataStructsPropertiesMapBoundedVec: 'BTreeMap<Bytes, Bytes>',
   /**
-   * Lookup399: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>
+   * Lookup404: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>
    **/
   UpDataStructsPropertiesMapPropertyPermission: 'BTreeMap<Bytes, UpDataStructsPropertyPermission>',
   /**
-   * Lookup406: up_data_structs::CollectionStats
+   * Lookup411: up_data_structs::CollectionStats
    **/
   UpDataStructsCollectionStats: {
     created: 'u32',
@@ -3282,18 +3335,18 @@
     alive: 'u32'
   },
   /**
-   * Lookup407: up_data_structs::TokenChild
+   * Lookup412: up_data_structs::TokenChild
    **/
   UpDataStructsTokenChild: {
     token: 'u32',
     collection: 'u32'
   },
   /**
-   * Lookup408: PhantomType::up_data_structs<T>
+   * Lookup413: PhantomType::up_data_structs<T>
    **/
   PhantomTypeUpDataStructs: '[(UpDataStructsTokenData,UpDataStructsRpcCollection,RmrkTraitsCollectionCollectionInfo,RmrkTraitsNftNftInfo,RmrkTraitsResourceResourceInfo,RmrkTraitsPropertyPropertyInfo,RmrkTraitsBaseBaseInfo,RmrkTraitsPartPartType,RmrkTraitsTheme,RmrkTraitsNftNftChild);0]',
   /**
-   * Lookup410: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup415: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsTokenData: {
     properties: 'Vec<UpDataStructsProperty>',
@@ -3301,7 +3354,7 @@
     pieces: 'u128'
   },
   /**
-   * Lookup412: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
+   * Lookup417: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
    **/
   UpDataStructsRpcCollection: {
     owner: 'AccountId32',
@@ -3318,14 +3371,14 @@
     flags: 'UpDataStructsRpcCollectionFlags'
   },
   /**
-   * Lookup413: up_data_structs::RpcCollectionFlags
+   * Lookup418: up_data_structs::RpcCollectionFlags
    **/
   UpDataStructsRpcCollectionFlags: {
     foreign: 'bool',
     erc721metadata: 'bool'
   },
   /**
-   * Lookup414: rmrk_traits::collection::CollectionInfo<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>
+   * Lookup419: rmrk_traits::collection::CollectionInfo<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>
    **/
   RmrkTraitsCollectionCollectionInfo: {
     issuer: 'AccountId32',
@@ -3335,7 +3388,7 @@
     nftsCount: 'u32'
   },
   /**
-   * Lookup415: rmrk_traits::nft::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup420: rmrk_traits::nft::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsNftNftInfo: {
     owner: 'RmrkTraitsNftAccountIdOrCollectionNftTuple',
@@ -3345,14 +3398,14 @@
     pending: 'bool'
   },
   /**
-   * Lookup417: rmrk_traits::nft::RoyaltyInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill>
+   * Lookup422: rmrk_traits::nft::RoyaltyInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill>
    **/
   RmrkTraitsNftRoyaltyInfo: {
     recipient: 'AccountId32',
     amount: 'Permill'
   },
   /**
-   * Lookup418: rmrk_traits::resource::ResourceInfo<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup423: rmrk_traits::resource::ResourceInfo<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsResourceResourceInfo: {
     id: 'u32',
@@ -3361,14 +3414,14 @@
     pendingRemoval: 'bool'
   },
   /**
-   * Lookup419: rmrk_traits::property::PropertyInfo<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup424: rmrk_traits::property::PropertyInfo<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsPropertyPropertyInfo: {
     key: 'Bytes',
     value: 'Bytes'
   },
   /**
-   * Lookup420: rmrk_traits::base::BaseInfo<sp_core::crypto::AccountId32, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup425: rmrk_traits::base::BaseInfo<sp_core::crypto::AccountId32, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsBaseBaseInfo: {
     issuer: 'AccountId32',
@@ -3376,92 +3429,92 @@
     symbol: 'Bytes'
   },
   /**
-   * Lookup421: rmrk_traits::nft::NftChild
+   * Lookup426: rmrk_traits::nft::NftChild
    **/
   RmrkTraitsNftNftChild: {
     collectionId: 'u32',
     nftId: 'u32'
   },
   /**
-   * Lookup423: pallet_common::pallet::Error<T>
+   * Lookup428: pallet_common::pallet::Error<T>
    **/
   PalletCommonError: {
     _enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'CantDestroyNotEmptyCollection', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'UserIsNotAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached', 'PropertyKeyIsTooLong', 'InvalidCharacterInPropertyKey', 'EmptyPropertyKey', 'CollectionIsExternal', 'CollectionIsInternal']
   },
   /**
-   * Lookup425: pallet_fungible::pallet::Error<T>
+   * Lookup430: pallet_fungible::pallet::Error<T>
    **/
   PalletFungibleError: {
     _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
   },
   /**
-   * Lookup426: pallet_refungible::ItemData
+   * Lookup431: pallet_refungible::ItemData
    **/
   PalletRefungibleItemData: {
     constData: 'Bytes'
   },
   /**
-   * Lookup431: pallet_refungible::pallet::Error<T>
+   * Lookup436: pallet_refungible::pallet::Error<T>
    **/
   PalletRefungibleError: {
     _enum: ['NotRefungibleDataUsedToMintFungibleCollectionToken', 'WrongRefungiblePieces', 'RepartitionWhileNotOwningAllPieces', 'RefungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
   },
   /**
-   * Lookup432: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup437: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   PalletNonfungibleItemData: {
     owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
   },
   /**
-   * Lookup434: up_data_structs::PropertyScope
+   * Lookup439: up_data_structs::PropertyScope
    **/
   UpDataStructsPropertyScope: {
     _enum: ['None', 'Rmrk']
   },
   /**
-   * Lookup436: pallet_nonfungible::pallet::Error<T>
+   * Lookup441: pallet_nonfungible::pallet::Error<T>
    **/
   PalletNonfungibleError: {
     _enum: ['NotNonfungibleDataUsedToMintFungibleCollectionToken', 'NonfungibleItemsHaveNoAmount', 'CantBurnNftWithChildren']
   },
   /**
-   * Lookup437: pallet_structure::pallet::Error<T>
+   * Lookup442: pallet_structure::pallet::Error<T>
    **/
   PalletStructureError: {
     _enum: ['OuroborosDetected', 'DepthLimit', 'BreadthLimit', 'TokenNotFound']
   },
   /**
-   * Lookup438: pallet_rmrk_core::pallet::Error<T>
+   * Lookup443: pallet_rmrk_core::pallet::Error<T>
    **/
   PalletRmrkCoreError: {
     _enum: ['CorruptedCollectionType', 'RmrkPropertyKeyIsTooLong', 'RmrkPropertyValueIsTooLong', 'RmrkPropertyIsNotFound', 'UnableToDecodeRmrkData', 'CollectionNotEmpty', 'NoAvailableCollectionId', 'NoAvailableNftId', 'CollectionUnknown', 'NoPermission', 'NonTransferable', 'CollectionFullOrLocked', 'ResourceDoesntExist', 'CannotSendToDescendentOrSelf', 'CannotAcceptNonOwnedNft', 'CannotRejectNonOwnedNft', 'CannotRejectNonPendingNft', 'ResourceNotPending', 'NoAvailableResourceId']
   },
   /**
-   * Lookup440: pallet_rmrk_equip::pallet::Error<T>
+   * Lookup445: pallet_rmrk_equip::pallet::Error<T>
    **/
   PalletRmrkEquipError: {
     _enum: ['PermissionError', 'NoAvailableBaseId', 'NoAvailablePartId', 'BaseDoesntExist', 'NeedsDefaultThemeFirst', 'PartDoesntExist', 'NoEquippableOnFixedPart']
   },
   /**
-   * Lookup446: pallet_app_promotion::pallet::Error<T>
+   * Lookup451: pallet_app_promotion::pallet::Error<T>
    **/
   PalletAppPromotionError: {
     _enum: ['AdminNotSet', 'NoPermission', 'NotSufficientFunds', 'PendingForBlockOverflow', 'SponsorNotSet', 'IncorrectLockedBalanceOperation']
   },
   /**
-   * Lookup447: pallet_foreign_assets::module::Error<T>
+   * Lookup452: pallet_foreign_assets::module::Error<T>
    **/
   PalletForeignAssetsModuleError: {
     _enum: ['BadLocation', 'MultiLocationExisted', 'AssetIdNotExists', 'AssetIdExisted']
   },
   /**
-   * Lookup450: pallet_evm::pallet::Error<T>
+   * Lookup454: pallet_evm::pallet::Error<T>
    **/
   PalletEvmError: {
-    _enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce']
+    _enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce', 'GasLimitTooLow', 'GasLimitTooHigh', 'Undefined', 'Reentrancy']
   },
   /**
-   * Lookup453: fp_rpc::TransactionStatus
+   * Lookup457: fp_rpc::TransactionStatus
    **/
   FpRpcTransactionStatus: {
     transactionHash: 'H256',
@@ -3473,11 +3526,11 @@
     logsBloom: 'EthbloomBloom'
   },
   /**
-   * Lookup455: ethbloom::Bloom
+   * Lookup459: ethbloom::Bloom
    **/
   EthbloomBloom: '[u8;256]',
   /**
-   * Lookup457: ethereum::receipt::ReceiptV3
+   * Lookup461: ethereum::receipt::ReceiptV3
    **/
   EthereumReceiptReceiptV3: {
     _enum: {
@@ -3487,7 +3540,7 @@
     }
   },
   /**
-   * Lookup458: ethereum::receipt::EIP658ReceiptData
+   * Lookup462: ethereum::receipt::EIP658ReceiptData
    **/
   EthereumReceiptEip658ReceiptData: {
     statusCode: 'u8',
@@ -3496,7 +3549,7 @@
     logs: 'Vec<EthereumLog>'
   },
   /**
-   * Lookup459: ethereum::block::Block<ethereum::transaction::TransactionV2>
+   * Lookup463: ethereum::block::Block<ethereum::transaction::TransactionV2>
    **/
   EthereumBlock: {
     header: 'EthereumHeader',
@@ -3504,7 +3557,7 @@
     ommers: 'Vec<EthereumHeader>'
   },
   /**
-   * Lookup460: ethereum::header::Header
+   * Lookup464: ethereum::header::Header
    **/
   EthereumHeader: {
     parentHash: 'H256',
@@ -3524,23 +3577,23 @@
     nonce: 'EthereumTypesHashH64'
   },
   /**
-   * Lookup461: ethereum_types::hash::H64
+   * Lookup465: ethereum_types::hash::H64
    **/
   EthereumTypesHashH64: '[u8;8]',
   /**
-   * Lookup466: pallet_ethereum::pallet::Error<T>
+   * Lookup470: pallet_ethereum::pallet::Error<T>
    **/
   PalletEthereumError: {
     _enum: ['InvalidSignature', 'PreLogExists']
   },
   /**
-   * Lookup467: pallet_evm_coder_substrate::pallet::Error<T>
+   * Lookup471: pallet_evm_coder_substrate::pallet::Error<T>
    **/
   PalletEvmCoderSubstrateError: {
     _enum: ['OutOfGas', 'OutOfFund']
   },
   /**
-   * Lookup468: up_data_structs::SponsorshipState<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup472: up_data_structs::SponsorshipState<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsSponsorshipStateBasicCrossAccountIdRepr: {
     _enum: {
@@ -3550,35 +3603,35 @@
     }
   },
   /**
-   * Lookup469: pallet_evm_contract_helpers::SponsoringModeT
+   * Lookup473: pallet_evm_contract_helpers::SponsoringModeT
    **/
   PalletEvmContractHelpersSponsoringModeT: {
     _enum: ['Disabled', 'Allowlisted', 'Generous']
   },
   /**
-   * Lookup475: pallet_evm_contract_helpers::pallet::Error<T>
+   * Lookup479: pallet_evm_contract_helpers::pallet::Error<T>
    **/
   PalletEvmContractHelpersError: {
     _enum: ['NoPermission', 'NoPendingSponsor', 'TooManyMethodsHaveSponsoredLimit']
   },
   /**
-   * Lookup476: pallet_evm_migration::pallet::Error<T>
+   * Lookup480: pallet_evm_migration::pallet::Error<T>
    **/
   PalletEvmMigrationError: {
-    _enum: ['AccountNotEmpty', 'AccountIsNotMigrating']
+    _enum: ['AccountNotEmpty', 'AccountIsNotMigrating', 'BadEvent']
   },
   /**
-   * Lookup477: pallet_maintenance::pallet::Error<T>
+   * Lookup481: pallet_maintenance::pallet::Error<T>
    **/
   PalletMaintenanceError: 'Null',
   /**
-   * Lookup478: pallet_test_utils::pallet::Error<T>
+   * Lookup482: pallet_test_utils::pallet::Error<T>
    **/
   PalletTestUtilsError: {
     _enum: ['TestPalletDisabled', 'TriggerRollback']
   },
   /**
-   * Lookup480: sp_runtime::MultiSignature
+   * Lookup484: sp_runtime::MultiSignature
    **/
   SpRuntimeMultiSignature: {
     _enum: {
@@ -3588,51 +3641,51 @@
     }
   },
   /**
-   * Lookup481: sp_core::ed25519::Signature
+   * Lookup485: sp_core::ed25519::Signature
    **/
   SpCoreEd25519Signature: '[u8;64]',
   /**
-   * Lookup483: sp_core::sr25519::Signature
+   * Lookup487: sp_core::sr25519::Signature
    **/
   SpCoreSr25519Signature: '[u8;64]',
   /**
-   * Lookup484: sp_core::ecdsa::Signature
+   * Lookup488: sp_core::ecdsa::Signature
    **/
   SpCoreEcdsaSignature: '[u8;65]',
   /**
-   * Lookup487: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
+   * Lookup491: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
    **/
   FrameSystemExtensionsCheckSpecVersion: 'Null',
   /**
-   * Lookup488: frame_system::extensions::check_tx_version::CheckTxVersion<T>
+   * Lookup492: frame_system::extensions::check_tx_version::CheckTxVersion<T>
    **/
   FrameSystemExtensionsCheckTxVersion: 'Null',
   /**
-   * Lookup489: frame_system::extensions::check_genesis::CheckGenesis<T>
+   * Lookup493: frame_system::extensions::check_genesis::CheckGenesis<T>
    **/
   FrameSystemExtensionsCheckGenesis: 'Null',
   /**
-   * Lookup492: frame_system::extensions::check_nonce::CheckNonce<T>
+   * Lookup496: frame_system::extensions::check_nonce::CheckNonce<T>
    **/
   FrameSystemExtensionsCheckNonce: 'Compact<u32>',
   /**
-   * Lookup493: frame_system::extensions::check_weight::CheckWeight<T>
+   * Lookup497: frame_system::extensions::check_weight::CheckWeight<T>
    **/
   FrameSystemExtensionsCheckWeight: 'Null',
   /**
-   * Lookup494: opal_runtime::runtime_common::maintenance::CheckMaintenance
+   * Lookup498: opal_runtime::runtime_common::maintenance::CheckMaintenance
    **/
   OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance: 'Null',
   /**
-   * Lookup495: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
+   * Lookup499: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
    **/
   PalletTemplateTransactionPaymentChargeTransactionPayment: 'Compact<u128>',
   /**
-   * Lookup496: opal_runtime::Runtime
+   * Lookup500: opal_runtime::Runtime
    **/
   OpalRuntimeRuntime: 'Null',
   /**
-   * Lookup497: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
+   * Lookup501: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
    **/
   PalletEthereumFakeTransactionFinalizer: 'Null'
 };
modifiedtests/src/interfaces/registry.tsdiffbeforeafterboth
--- a/tests/src/interfaces/registry.ts
+++ b/tests/src/interfaces/registry.ts
@@ -5,7 +5,7 @@
 // this is required to allow for ambient/previous definitions
 import '@polkadot/types/types/registry';
 
-import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportScheduleLookupError, FrameSupportScheduleMaybeHashed, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationCall, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletUniqueSchedulerCall, PalletUniqueSchedulerError, PalletUniqueSchedulerEvent, PalletUniqueSchedulerScheduledV3, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
+import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationCall, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletUniqueSchedulerV2BlockAgenda, PalletUniqueSchedulerV2Call, PalletUniqueSchedulerV2Error, PalletUniqueSchedulerV2Event, PalletUniqueSchedulerV2Scheduled, PalletUniqueSchedulerV2ScheduledCall, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
 
 declare module '@polkadot/types/types/registry' {
   interface InterfaceTypes {
@@ -59,8 +59,6 @@
     FrameSupportDispatchPerDispatchClassWeightsPerClass: FrameSupportDispatchPerDispatchClassWeightsPerClass;
     FrameSupportDispatchRawOrigin: FrameSupportDispatchRawOrigin;
     FrameSupportPalletId: FrameSupportPalletId;
-    FrameSupportScheduleLookupError: FrameSupportScheduleLookupError;
-    FrameSupportScheduleMaybeHashed: FrameSupportScheduleMaybeHashed;
     FrameSupportTokensMiscBalanceStatus: FrameSupportTokensMiscBalanceStatus;
     FrameSystemAccountInfo: FrameSystemAccountInfo;
     FrameSystemCall: FrameSystemCall;
@@ -122,6 +120,7 @@
     PalletEvmEvent: PalletEvmEvent;
     PalletEvmMigrationCall: PalletEvmMigrationCall;
     PalletEvmMigrationError: PalletEvmMigrationError;
+    PalletEvmMigrationEvent: PalletEvmMigrationEvent;
     PalletForeignAssetsAssetIds: PalletForeignAssetsAssetIds;
     PalletForeignAssetsModuleAssetMetadata: PalletForeignAssetsModuleAssetMetadata;
     PalletForeignAssetsModuleCall: PalletForeignAssetsModuleCall;
@@ -164,10 +163,12 @@
     PalletUniqueCall: PalletUniqueCall;
     PalletUniqueError: PalletUniqueError;
     PalletUniqueRawEvent: PalletUniqueRawEvent;
-    PalletUniqueSchedulerCall: PalletUniqueSchedulerCall;
-    PalletUniqueSchedulerError: PalletUniqueSchedulerError;
-    PalletUniqueSchedulerEvent: PalletUniqueSchedulerEvent;
-    PalletUniqueSchedulerScheduledV3: PalletUniqueSchedulerScheduledV3;
+    PalletUniqueSchedulerV2BlockAgenda: PalletUniqueSchedulerV2BlockAgenda;
+    PalletUniqueSchedulerV2Call: PalletUniqueSchedulerV2Call;
+    PalletUniqueSchedulerV2Error: PalletUniqueSchedulerV2Error;
+    PalletUniqueSchedulerV2Event: PalletUniqueSchedulerV2Event;
+    PalletUniqueSchedulerV2Scheduled: PalletUniqueSchedulerV2Scheduled;
+    PalletUniqueSchedulerV2ScheduledCall: PalletUniqueSchedulerV2ScheduledCall;
     PalletXcmCall: PalletXcmCall;
     PalletXcmError: PalletXcmError;
     PalletXcmEvent: PalletXcmEvent;
modifiedtests/src/interfaces/types-lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/types-lookup.ts
+++ b/tests/src/interfaces/types-lookup.ts
@@ -1132,8 +1132,8 @@
     readonly type: 'Substrate' | 'Ethereum';
   }
 
-  /** @name PalletUniqueSchedulerEvent (93) */
-  interface PalletUniqueSchedulerEvent extends Enum {
+  /** @name PalletUniqueSchedulerV2Event (93) */
+  interface PalletUniqueSchedulerV2Event extends Enum {
     readonly isScheduled: boolean;
     readonly asScheduled: {
       readonly when: u32;
@@ -1144,35 +1144,31 @@
       readonly when: u32;
       readonly index: u32;
     } & Struct;
+    readonly isDispatched: boolean;
+    readonly asDispatched: {
+      readonly task: ITuple<[u32, u32]>;
+      readonly id: Option<U8aFixed>;
+      readonly result: Result<Null, SpRuntimeDispatchError>;
+    } & Struct;
     readonly isPriorityChanged: boolean;
     readonly asPriorityChanged: {
-      readonly when: u32;
-      readonly index: u32;
+      readonly task: ITuple<[u32, u32]>;
       readonly priority: u8;
     } & Struct;
-    readonly isDispatched: boolean;
-    readonly asDispatched: {
+    readonly isCallUnavailable: boolean;
+    readonly asCallUnavailable: {
       readonly task: ITuple<[u32, u32]>;
       readonly id: Option<U8aFixed>;
-      readonly result: Result<Null, SpRuntimeDispatchError>;
     } & Struct;
-    readonly isCallLookupFailed: boolean;
-    readonly asCallLookupFailed: {
+    readonly isPermanentlyOverweight: boolean;
+    readonly asPermanentlyOverweight: {
       readonly task: ITuple<[u32, u32]>;
       readonly id: Option<U8aFixed>;
-      readonly error: FrameSupportScheduleLookupError;
     } & Struct;
-    readonly type: 'Scheduled' | 'Canceled' | 'PriorityChanged' | 'Dispatched' | 'CallLookupFailed';
+    readonly type: 'Scheduled' | 'Canceled' | 'Dispatched' | 'PriorityChanged' | 'CallUnavailable' | 'PermanentlyOverweight';
   }
 
-  /** @name FrameSupportScheduleLookupError (96) */
-  interface FrameSupportScheduleLookupError extends Enum {
-    readonly isUnknown: boolean;
-    readonly isBadFormat: boolean;
-    readonly type: 'Unknown' | 'BadFormat';
-  }
-
-  /** @name PalletCommonEvent (97) */
+  /** @name PalletCommonEvent (96) */
   interface PalletCommonEvent extends Enum {
     readonly isCollectionCreated: boolean;
     readonly asCollectionCreated: ITuple<[u32, u8, AccountId32]>;
@@ -1199,14 +1195,14 @@
     readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet';
   }
 
-  /** @name PalletStructureEvent (100) */
+  /** @name PalletStructureEvent (99) */
   interface PalletStructureEvent extends Enum {
     readonly isExecuted: boolean;
     readonly asExecuted: Result<Null, SpRuntimeDispatchError>;
     readonly type: 'Executed';
   }
 
-  /** @name PalletRmrkCoreEvent (101) */
+  /** @name PalletRmrkCoreEvent (100) */
   interface PalletRmrkCoreEvent extends Enum {
     readonly isCollectionCreated: boolean;
     readonly asCollectionCreated: {
@@ -1296,7 +1292,7 @@
     readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'IssuerChanged' | 'CollectionLocked' | 'NftMinted' | 'NftBurned' | 'NftSent' | 'NftAccepted' | 'NftRejected' | 'PropertySet' | 'ResourceAdded' | 'ResourceRemoval' | 'ResourceAccepted' | 'ResourceRemovalAccepted' | 'PrioritySet';
   }
 
-  /** @name RmrkTraitsNftAccountIdOrCollectionNftTuple (102) */
+  /** @name RmrkTraitsNftAccountIdOrCollectionNftTuple (101) */
   interface RmrkTraitsNftAccountIdOrCollectionNftTuple extends Enum {
     readonly isAccountId: boolean;
     readonly asAccountId: AccountId32;
@@ -1305,7 +1301,7 @@
     readonly type: 'AccountId' | 'CollectionAndNftTuple';
   }
 
-  /** @name PalletRmrkEquipEvent (107) */
+  /** @name PalletRmrkEquipEvent (106) */
   interface PalletRmrkEquipEvent extends Enum {
     readonly isBaseCreated: boolean;
     readonly asBaseCreated: {
@@ -1320,7 +1316,7 @@
     readonly type: 'BaseCreated' | 'EquippablesUpdated';
   }
 
-  /** @name PalletAppPromotionEvent (108) */
+  /** @name PalletAppPromotionEvent (107) */
   interface PalletAppPromotionEvent extends Enum {
     readonly isStakingRecalculation: boolean;
     readonly asStakingRecalculation: ITuple<[AccountId32, u128, u128]>;
@@ -1333,7 +1329,7 @@
     readonly type: 'StakingRecalculation' | 'Stake' | 'Unstake' | 'SetAdmin';
   }
 
-  /** @name PalletForeignAssetsModuleEvent (109) */
+  /** @name PalletForeignAssetsModuleEvent (108) */
   interface PalletForeignAssetsModuleEvent extends Enum {
     readonly isForeignAssetRegistered: boolean;
     readonly asForeignAssetRegistered: {
@@ -1360,7 +1356,7 @@
     readonly type: 'ForeignAssetRegistered' | 'ForeignAssetUpdated' | 'AssetRegistered' | 'AssetUpdated';
   }
 
-  /** @name PalletForeignAssetsModuleAssetMetadata (110) */
+  /** @name PalletForeignAssetsModuleAssetMetadata (109) */
   interface PalletForeignAssetsModuleAssetMetadata extends Struct {
     readonly name: Bytes;
     readonly symbol: Bytes;
@@ -1368,40 +1364,51 @@
     readonly minimalBalance: u128;
   }
 
-  /** @name PalletEvmEvent (111) */
+  /** @name PalletEvmEvent (110) */
   interface PalletEvmEvent extends Enum {
     readonly isLog: boolean;
-    readonly asLog: EthereumLog;
+    readonly asLog: {
+      readonly log: EthereumLog;
+    } & Struct;
     readonly isCreated: boolean;
-    readonly asCreated: H160;
+    readonly asCreated: {
+      readonly address: H160;
+    } & Struct;
     readonly isCreatedFailed: boolean;
-    readonly asCreatedFailed: H160;
+    readonly asCreatedFailed: {
+      readonly address: H160;
+    } & Struct;
     readonly isExecuted: boolean;
-    readonly asExecuted: H160;
+    readonly asExecuted: {
+      readonly address: H160;
+    } & Struct;
     readonly isExecutedFailed: boolean;
-    readonly asExecutedFailed: H160;
-    readonly isBalanceDeposit: boolean;
-    readonly asBalanceDeposit: ITuple<[AccountId32, H160, U256]>;
-    readonly isBalanceWithdraw: boolean;
-    readonly asBalanceWithdraw: ITuple<[AccountId32, H160, U256]>;
-    readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed' | 'BalanceDeposit' | 'BalanceWithdraw';
+    readonly asExecutedFailed: {
+      readonly address: H160;
+    } & Struct;
+    readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed';
   }
 
-  /** @name EthereumLog (112) */
+  /** @name EthereumLog (111) */
   interface EthereumLog extends Struct {
     readonly address: H160;
     readonly topics: Vec<H256>;
     readonly data: Bytes;
   }
 
-  /** @name PalletEthereumEvent (116) */
+  /** @name PalletEthereumEvent (113) */
   interface PalletEthereumEvent extends Enum {
     readonly isExecuted: boolean;
-    readonly asExecuted: ITuple<[H160, H160, H256, EvmCoreErrorExitReason]>;
+    readonly asExecuted: {
+      readonly from: H160;
+      readonly to: H160;
+      readonly transactionHash: H256;
+      readonly exitReason: EvmCoreErrorExitReason;
+    } & Struct;
     readonly type: 'Executed';
   }
 
-  /** @name EvmCoreErrorExitReason (117) */
+  /** @name EvmCoreErrorExitReason (114) */
   interface EvmCoreErrorExitReason extends Enum {
     readonly isSucceed: boolean;
     readonly asSucceed: EvmCoreErrorExitSucceed;
@@ -1414,7 +1421,7 @@
     readonly type: 'Succeed' | 'Error' | 'Revert' | 'Fatal';
   }
 
-  /** @name EvmCoreErrorExitSucceed (118) */
+  /** @name EvmCoreErrorExitSucceed (115) */
   interface EvmCoreErrorExitSucceed extends Enum {
     readonly isStopped: boolean;
     readonly isReturned: boolean;
@@ -1422,7 +1429,7 @@
     readonly type: 'Stopped' | 'Returned' | 'Suicided';
   }
 
-  /** @name EvmCoreErrorExitError (119) */
+  /** @name EvmCoreErrorExitError (116) */
   interface EvmCoreErrorExitError extends Enum {
     readonly isStackUnderflow: boolean;
     readonly isStackOverflow: boolean;
@@ -1443,13 +1450,13 @@
     readonly type: 'StackUnderflow' | 'StackOverflow' | 'InvalidJump' | 'InvalidRange' | 'DesignatedInvalid' | 'CallTooDeep' | 'CreateCollision' | 'CreateContractLimit' | 'OutOfOffset' | 'OutOfGas' | 'OutOfFund' | 'PcUnderflow' | 'CreateEmpty' | 'Other' | 'InvalidCode';
   }
 
-  /** @name EvmCoreErrorExitRevert (122) */
+  /** @name EvmCoreErrorExitRevert (119) */
   interface EvmCoreErrorExitRevert extends Enum {
     readonly isReverted: boolean;
     readonly type: 'Reverted';
   }
 
-  /** @name EvmCoreErrorExitFatal (123) */
+  /** @name EvmCoreErrorExitFatal (120) */
   interface EvmCoreErrorExitFatal extends Enum {
     readonly isNotSupported: boolean;
     readonly isUnhandledInterrupt: boolean;
@@ -1460,7 +1467,7 @@
     readonly type: 'NotSupported' | 'UnhandledInterrupt' | 'CallErrorAsFatal' | 'Other';
   }
 
-  /** @name PalletEvmContractHelpersEvent (124) */
+  /** @name PalletEvmContractHelpersEvent (121) */
   interface PalletEvmContractHelpersEvent extends Enum {
     readonly isContractSponsorSet: boolean;
     readonly asContractSponsorSet: ITuple<[H160, AccountId32]>;
@@ -1471,21 +1478,28 @@
     readonly type: 'ContractSponsorSet' | 'ContractSponsorshipConfirmed' | 'ContractSponsorRemoved';
   }
 
-  /** @name PalletMaintenanceEvent (125) */
+  /** @name PalletEvmMigrationEvent (122) */
+  interface PalletEvmMigrationEvent extends Enum {
+    readonly isTestEvent: boolean;
+    readonly type: 'TestEvent';
+  }
+
+  /** @name PalletMaintenanceEvent (123) */
   interface PalletMaintenanceEvent extends Enum {
     readonly isMaintenanceEnabled: boolean;
     readonly isMaintenanceDisabled: boolean;
     readonly type: 'MaintenanceEnabled' | 'MaintenanceDisabled';
   }
 
-  /** @name PalletTestUtilsEvent (126) */
+  /** @name PalletTestUtilsEvent (124) */
   interface PalletTestUtilsEvent extends Enum {
     readonly isValueIsSet: boolean;
     readonly isShouldRollback: boolean;
-    readonly type: 'ValueIsSet' | 'ShouldRollback';
+    readonly isBatchCompleted: boolean;
+    readonly type: 'ValueIsSet' | 'ShouldRollback' | 'BatchCompleted';
   }
 
-  /** @name FrameSystemPhase (127) */
+  /** @name FrameSystemPhase (125) */
   interface FrameSystemPhase extends Enum {
     readonly isApplyExtrinsic: boolean;
     readonly asApplyExtrinsic: u32;
@@ -1494,13 +1508,13 @@
     readonly type: 'ApplyExtrinsic' | 'Finalization' | 'Initialization';
   }
 
-  /** @name FrameSystemLastRuntimeUpgradeInfo (129) */
+  /** @name FrameSystemLastRuntimeUpgradeInfo (127) */
   interface FrameSystemLastRuntimeUpgradeInfo extends Struct {
     readonly specVersion: Compact<u32>;
     readonly specName: Text;
   }
 
-  /** @name FrameSystemCall (130) */
+  /** @name FrameSystemCall (128) */
   interface FrameSystemCall extends Enum {
     readonly isFillBlock: boolean;
     readonly asFillBlock: {
@@ -1542,21 +1556,21 @@
     readonly type: 'FillBlock' | 'Remark' | 'SetHeapPages' | 'SetCode' | 'SetCodeWithoutChecks' | 'SetStorage' | 'KillStorage' | 'KillPrefix' | 'RemarkWithEvent';
   }
 
-  /** @name FrameSystemLimitsBlockWeights (135) */
+  /** @name FrameSystemLimitsBlockWeights (133) */
   interface FrameSystemLimitsBlockWeights extends Struct {
     readonly baseBlock: Weight;
     readonly maxBlock: Weight;
     readonly perClass: FrameSupportDispatchPerDispatchClassWeightsPerClass;
   }
 
-  /** @name FrameSupportDispatchPerDispatchClassWeightsPerClass (136) */
+  /** @name FrameSupportDispatchPerDispatchClassWeightsPerClass (134) */
   interface FrameSupportDispatchPerDispatchClassWeightsPerClass extends Struct {
     readonly normal: FrameSystemLimitsWeightsPerClass;
     readonly operational: FrameSystemLimitsWeightsPerClass;
     readonly mandatory: FrameSystemLimitsWeightsPerClass;
   }
 
-  /** @name FrameSystemLimitsWeightsPerClass (137) */
+  /** @name FrameSystemLimitsWeightsPerClass (135) */
   interface FrameSystemLimitsWeightsPerClass extends Struct {
     readonly baseExtrinsic: Weight;
     readonly maxExtrinsic: Option<Weight>;
@@ -1564,25 +1578,25 @@
     readonly reserved: Option<Weight>;
   }
 
-  /** @name FrameSystemLimitsBlockLength (139) */
+  /** @name FrameSystemLimitsBlockLength (137) */
   interface FrameSystemLimitsBlockLength extends Struct {
     readonly max: FrameSupportDispatchPerDispatchClassU32;
   }
 
-  /** @name FrameSupportDispatchPerDispatchClassU32 (140) */
+  /** @name FrameSupportDispatchPerDispatchClassU32 (138) */
   interface FrameSupportDispatchPerDispatchClassU32 extends Struct {
     readonly normal: u32;
     readonly operational: u32;
     readonly mandatory: u32;
   }
 
-  /** @name SpWeightsRuntimeDbWeight (141) */
+  /** @name SpWeightsRuntimeDbWeight (139) */
   interface SpWeightsRuntimeDbWeight extends Struct {
     readonly read: u64;
     readonly write: u64;
   }
 
-  /** @name SpVersionRuntimeVersion (142) */
+  /** @name SpVersionRuntimeVersion (140) */
   interface SpVersionRuntimeVersion extends Struct {
     readonly specName: Text;
     readonly implName: Text;
@@ -1594,7 +1608,7 @@
     readonly stateVersion: u8;
   }
 
-  /** @name FrameSystemError (147) */
+  /** @name FrameSystemError (145) */
   interface FrameSystemError extends Enum {
     readonly isInvalidSpecName: boolean;
     readonly isSpecVersionNeedsToIncrease: boolean;
@@ -1605,7 +1619,7 @@
     readonly type: 'InvalidSpecName' | 'SpecVersionNeedsToIncrease' | 'FailedToExtractRuntimeVersion' | 'NonDefaultComposite' | 'NonZeroRefCount' | 'CallFiltered';
   }
 
-  /** @name PolkadotPrimitivesV2PersistedValidationData (148) */
+  /** @name PolkadotPrimitivesV2PersistedValidationData (146) */
   interface PolkadotPrimitivesV2PersistedValidationData extends Struct {
     readonly parentHead: Bytes;
     readonly relayParentNumber: u32;
@@ -1613,18 +1627,18 @@
     readonly maxPovSize: u32;
   }
 
-  /** @name PolkadotPrimitivesV2UpgradeRestriction (151) */
+  /** @name PolkadotPrimitivesV2UpgradeRestriction (149) */
   interface PolkadotPrimitivesV2UpgradeRestriction extends Enum {
     readonly isPresent: boolean;
     readonly type: 'Present';
   }
 
-  /** @name SpTrieStorageProof (152) */
+  /** @name SpTrieStorageProof (150) */
   interface SpTrieStorageProof extends Struct {
     readonly trieNodes: BTreeSet<Bytes>;
   }
 
-  /** @name CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot (154) */
+  /** @name CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot (152) */
   interface CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot extends Struct {
     readonly dmqMqcHead: H256;
     readonly relayDispatchQueueSize: ITuple<[u32, u32]>;
@@ -1632,7 +1646,7 @@
     readonly egressChannels: Vec<ITuple<[u32, PolkadotPrimitivesV2AbridgedHrmpChannel]>>;
   }
 
-  /** @name PolkadotPrimitivesV2AbridgedHrmpChannel (157) */
+  /** @name PolkadotPrimitivesV2AbridgedHrmpChannel (155) */
   interface PolkadotPrimitivesV2AbridgedHrmpChannel extends Struct {
     readonly maxCapacity: u32;
     readonly maxTotalSize: u32;
@@ -1642,7 +1656,7 @@
     readonly mqcHead: Option<H256>;
   }
 
-  /** @name PolkadotPrimitivesV2AbridgedHostConfiguration (158) */
+  /** @name PolkadotPrimitivesV2AbridgedHostConfiguration (156) */
   interface PolkadotPrimitivesV2AbridgedHostConfiguration extends Struct {
     readonly maxCodeSize: u32;
     readonly maxHeadDataSize: u32;
@@ -1655,13 +1669,13 @@
     readonly validationUpgradeDelay: u32;
   }
 
-  /** @name PolkadotCorePrimitivesOutboundHrmpMessage (164) */
+  /** @name PolkadotCorePrimitivesOutboundHrmpMessage (162) */
   interface PolkadotCorePrimitivesOutboundHrmpMessage extends Struct {
     readonly recipient: u32;
     readonly data: Bytes;
   }
 
-  /** @name CumulusPalletParachainSystemCall (165) */
+  /** @name CumulusPalletParachainSystemCall (163) */
   interface CumulusPalletParachainSystemCall extends Enum {
     readonly isSetValidationData: boolean;
     readonly asSetValidationData: {
@@ -1682,7 +1696,7 @@
     readonly type: 'SetValidationData' | 'SudoSendUpwardMessage' | 'AuthorizeUpgrade' | 'EnactAuthorizedUpgrade';
   }
 
-  /** @name CumulusPrimitivesParachainInherentParachainInherentData (166) */
+  /** @name CumulusPrimitivesParachainInherentParachainInherentData (164) */
   interface CumulusPrimitivesParachainInherentParachainInherentData extends Struct {
     readonly validationData: PolkadotPrimitivesV2PersistedValidationData;
     readonly relayChainState: SpTrieStorageProof;
@@ -1690,19 +1704,19 @@
     readonly horizontalMessages: BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>;
   }
 
-  /** @name PolkadotCorePrimitivesInboundDownwardMessage (168) */
+  /** @name PolkadotCorePrimitivesInboundDownwardMessage (166) */
   interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct {
     readonly sentAt: u32;
     readonly msg: Bytes;
   }
 
-  /** @name PolkadotCorePrimitivesInboundHrmpMessage (171) */
+  /** @name PolkadotCorePrimitivesInboundHrmpMessage (169) */
   interface PolkadotCorePrimitivesInboundHrmpMessage extends Struct {
     readonly sentAt: u32;
     readonly data: Bytes;
   }
 
-  /** @name CumulusPalletParachainSystemError (174) */
+  /** @name CumulusPalletParachainSystemError (172) */
   interface CumulusPalletParachainSystemError extends Enum {
     readonly isOverlappingUpgrades: boolean;
     readonly isProhibitedByPolkadot: boolean;
@@ -1715,14 +1729,14 @@
     readonly type: 'OverlappingUpgrades' | 'ProhibitedByPolkadot' | 'TooBig' | 'ValidationDataNotAvailable' | 'HostConfigurationNotAvailable' | 'NotScheduled' | 'NothingAuthorized' | 'Unauthorized';
   }
 
-  /** @name PalletBalancesBalanceLock (176) */
+  /** @name PalletBalancesBalanceLock (174) */
   interface PalletBalancesBalanceLock extends Struct {
     readonly id: U8aFixed;
     readonly amount: u128;
     readonly reasons: PalletBalancesReasons;
   }
 
-  /** @name PalletBalancesReasons (177) */
+  /** @name PalletBalancesReasons (175) */
   interface PalletBalancesReasons extends Enum {
     readonly isFee: boolean;
     readonly isMisc: boolean;
@@ -1730,20 +1744,20 @@
     readonly type: 'Fee' | 'Misc' | 'All';
   }
 
-  /** @name PalletBalancesReserveData (180) */
+  /** @name PalletBalancesReserveData (178) */
   interface PalletBalancesReserveData extends Struct {
     readonly id: U8aFixed;
     readonly amount: u128;
   }
 
-  /** @name PalletBalancesReleases (182) */
+  /** @name PalletBalancesReleases (180) */
   interface PalletBalancesReleases extends Enum {
     readonly isV100: boolean;
     readonly isV200: boolean;
     readonly type: 'V100' | 'V200';
   }
 
-  /** @name PalletBalancesCall (183) */
+  /** @name PalletBalancesCall (181) */
   interface PalletBalancesCall extends Enum {
     readonly isTransfer: boolean;
     readonly asTransfer: {
@@ -1780,7 +1794,7 @@
     readonly type: 'Transfer' | 'SetBalance' | 'ForceTransfer' | 'TransferKeepAlive' | 'TransferAll' | 'ForceUnreserve';
   }
 
-  /** @name PalletBalancesError (186) */
+  /** @name PalletBalancesError (184) */
   interface PalletBalancesError extends Enum {
     readonly isVestingBalance: boolean;
     readonly isLiquidityRestrictions: boolean;
@@ -1793,7 +1807,7 @@
     readonly type: 'VestingBalance' | 'LiquidityRestrictions' | 'InsufficientBalance' | 'ExistentialDeposit' | 'KeepAlive' | 'ExistingVestingSchedule' | 'DeadAccount' | 'TooManyReserves';
   }
 
-  /** @name PalletTimestampCall (188) */
+  /** @name PalletTimestampCall (186) */
   interface PalletTimestampCall extends Enum {
     readonly isSet: boolean;
     readonly asSet: {
@@ -1802,14 +1816,14 @@
     readonly type: 'Set';
   }
 
-  /** @name PalletTransactionPaymentReleases (190) */
+  /** @name PalletTransactionPaymentReleases (188) */
   interface PalletTransactionPaymentReleases extends Enum {
     readonly isV1Ancient: boolean;
     readonly isV2: boolean;
     readonly type: 'V1Ancient' | 'V2';
   }
 
-  /** @name PalletTreasuryProposal (191) */
+  /** @name PalletTreasuryProposal (189) */
   interface PalletTreasuryProposal extends Struct {
     readonly proposer: AccountId32;
     readonly value: u128;
@@ -1817,7 +1831,7 @@
     readonly bond: u128;
   }
 
-  /** @name PalletTreasuryCall (194) */
+  /** @name PalletTreasuryCall (192) */
   interface PalletTreasuryCall extends Enum {
     readonly isProposeSpend: boolean;
     readonly asProposeSpend: {
@@ -1844,10 +1858,10 @@
     readonly type: 'ProposeSpend' | 'RejectProposal' | 'ApproveProposal' | 'Spend' | 'RemoveApproval';
   }
 
-  /** @name FrameSupportPalletId (197) */
+  /** @name FrameSupportPalletId (195) */
   interface FrameSupportPalletId extends U8aFixed {}
 
-  /** @name PalletTreasuryError (198) */
+  /** @name PalletTreasuryError (196) */
   interface PalletTreasuryError extends Enum {
     readonly isInsufficientProposersBalance: boolean;
     readonly isInvalidIndex: boolean;
@@ -1857,7 +1871,7 @@
     readonly type: 'InsufficientProposersBalance' | 'InvalidIndex' | 'TooManyApprovals' | 'InsufficientPermission' | 'ProposalNotApproved';
   }
 
-  /** @name PalletSudoCall (199) */
+  /** @name PalletSudoCall (197) */
   interface PalletSudoCall extends Enum {
     readonly isSudo: boolean;
     readonly asSudo: {
@@ -1880,7 +1894,7 @@
     readonly type: 'Sudo' | 'SudoUncheckedWeight' | 'SetKey' | 'SudoAs';
   }
 
-  /** @name OrmlVestingModuleCall (201) */
+  /** @name OrmlVestingModuleCall (199) */
   interface OrmlVestingModuleCall extends Enum {
     readonly isClaim: boolean;
     readonly isVestedTransfer: boolean;
@@ -1900,7 +1914,7 @@
     readonly type: 'Claim' | 'VestedTransfer' | 'UpdateVestingSchedules' | 'ClaimFor';
   }
 
-  /** @name OrmlXtokensModuleCall (203) */
+  /** @name OrmlXtokensModuleCall (201) */
   interface OrmlXtokensModuleCall extends Enum {
     readonly isTransfer: boolean;
     readonly asTransfer: {
@@ -1947,7 +1961,7 @@
     readonly type: 'Transfer' | 'TransferMultiasset' | 'TransferWithFee' | 'TransferMultiassetWithFee' | 'TransferMulticurrencies' | 'TransferMultiassets';
   }
 
-  /** @name XcmVersionedMultiAsset (204) */
+  /** @name XcmVersionedMultiAsset (202) */
   interface XcmVersionedMultiAsset extends Enum {
     readonly isV0: boolean;
     readonly asV0: XcmV0MultiAsset;
@@ -1956,7 +1970,7 @@
     readonly type: 'V0' | 'V1';
   }
 
-  /** @name OrmlTokensModuleCall (207) */
+  /** @name OrmlTokensModuleCall (205) */
   interface OrmlTokensModuleCall extends Enum {
     readonly isTransfer: boolean;
     readonly asTransfer: {
@@ -1993,7 +2007,7 @@
     readonly type: 'Transfer' | 'TransferAll' | 'TransferKeepAlive' | 'ForceTransfer' | 'SetBalance';
   }
 
-  /** @name CumulusPalletXcmpQueueCall (208) */
+  /** @name CumulusPalletXcmpQueueCall (206) */
   interface CumulusPalletXcmpQueueCall extends Enum {
     readonly isServiceOverweight: boolean;
     readonly asServiceOverweight: {
@@ -2029,7 +2043,7 @@
     readonly type: 'ServiceOverweight' | 'SuspendXcmExecution' | 'ResumeXcmExecution' | 'UpdateSuspendThreshold' | 'UpdateDropThreshold' | 'UpdateResumeThreshold' | 'UpdateThresholdWeight' | 'UpdateWeightRestrictDecay' | 'UpdateXcmpMaxIndividualWeight';
   }
 
-  /** @name PalletXcmCall (209) */
+  /** @name PalletXcmCall (207) */
   interface PalletXcmCall extends Enum {
     readonly isSend: boolean;
     readonly asSend: {
@@ -2091,7 +2105,7 @@
     readonly type: 'Send' | 'TeleportAssets' | 'ReserveTransferAssets' | 'Execute' | 'ForceXcmVersion' | 'ForceDefaultXcmVersion' | 'ForceSubscribeVersionNotify' | 'ForceUnsubscribeVersionNotify' | 'LimitedReserveTransferAssets' | 'LimitedTeleportAssets';
   }
 
-  /** @name XcmVersionedXcm (210) */
+  /** @name XcmVersionedXcm (208) */
   interface XcmVersionedXcm extends Enum {
     readonly isV0: boolean;
     readonly asV0: XcmV0Xcm;
@@ -2102,7 +2116,7 @@
     readonly type: 'V0' | 'V1' | 'V2';
   }
 
-  /** @name XcmV0Xcm (211) */
+  /** @name XcmV0Xcm (209) */
   interface XcmV0Xcm extends Enum {
     readonly isWithdrawAsset: boolean;
     readonly asWithdrawAsset: {
@@ -2165,7 +2179,7 @@
     readonly type: 'WithdrawAsset' | 'ReserveAssetDeposit' | 'TeleportAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'RelayedFrom';
   }
 
-  /** @name XcmV0Order (213) */
+  /** @name XcmV0Order (211) */
   interface XcmV0Order extends Enum {
     readonly isNull: boolean;
     readonly isDepositAsset: boolean;
@@ -2213,14 +2227,14 @@
     readonly type: 'Null' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'QueryHolding' | 'BuyExecution';
   }
 
-  /** @name XcmV0Response (215) */
+  /** @name XcmV0Response (213) */
   interface XcmV0Response extends Enum {
     readonly isAssets: boolean;
     readonly asAssets: Vec<XcmV0MultiAsset>;
     readonly type: 'Assets';
   }
 
-  /** @name XcmV1Xcm (216) */
+  /** @name XcmV1Xcm (214) */
   interface XcmV1Xcm extends Enum {
     readonly isWithdrawAsset: boolean;
     readonly asWithdrawAsset: {
@@ -2289,7 +2303,7 @@
     readonly type: 'WithdrawAsset' | 'ReserveAssetDeposited' | 'ReceiveTeleportedAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'RelayedFrom' | 'SubscribeVersion' | 'UnsubscribeVersion';
   }
 
-  /** @name XcmV1Order (218) */
+  /** @name XcmV1Order (216) */
   interface XcmV1Order extends Enum {
     readonly isNoop: boolean;
     readonly isDepositAsset: boolean;
@@ -2339,7 +2353,7 @@
     readonly type: 'Noop' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'QueryHolding' | 'BuyExecution';
   }
 
-  /** @name XcmV1Response (220) */
+  /** @name XcmV1Response (218) */
   interface XcmV1Response extends Enum {
     readonly isAssets: boolean;
     readonly asAssets: XcmV1MultiassetMultiAssets;
@@ -2348,10 +2362,10 @@
     readonly type: 'Assets' | 'Version';
   }
 
-  /** @name CumulusPalletXcmCall (234) */
+  /** @name CumulusPalletXcmCall (232) */
   type CumulusPalletXcmCall = Null;
 
-  /** @name CumulusPalletDmpQueueCall (235) */
+  /** @name CumulusPalletDmpQueueCall (233) */
   interface CumulusPalletDmpQueueCall extends Enum {
     readonly isServiceOverweight: boolean;
     readonly asServiceOverweight: {
@@ -2361,7 +2375,7 @@
     readonly type: 'ServiceOverweight';
   }
 
-  /** @name PalletInflationCall (236) */
+  /** @name PalletInflationCall (234) */
   interface PalletInflationCall extends Enum {
     readonly isStartInflation: boolean;
     readonly asStartInflation: {
@@ -2370,7 +2384,7 @@
     readonly type: 'StartInflation';
   }
 
-  /** @name PalletUniqueCall (237) */
+  /** @name PalletUniqueCall (235) */
   interface PalletUniqueCall extends Enum {
     readonly isCreateCollection: boolean;
     readonly asCreateCollection: {
@@ -2528,7 +2542,7 @@
     readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition';
   }
 
-  /** @name UpDataStructsCollectionMode (242) */
+  /** @name UpDataStructsCollectionMode (240) */
   interface UpDataStructsCollectionMode extends Enum {
     readonly isNft: boolean;
     readonly isFungible: boolean;
@@ -2537,7 +2551,7 @@
     readonly type: 'Nft' | 'Fungible' | 'ReFungible';
   }
 
-  /** @name UpDataStructsCreateCollectionData (243) */
+  /** @name UpDataStructsCreateCollectionData (241) */
   interface UpDataStructsCreateCollectionData extends Struct {
     readonly mode: UpDataStructsCollectionMode;
     readonly access: Option<UpDataStructsAccessMode>;
@@ -2551,14 +2565,14 @@
     readonly properties: Vec<UpDataStructsProperty>;
   }
 
-  /** @name UpDataStructsAccessMode (245) */
+  /** @name UpDataStructsAccessMode (243) */
   interface UpDataStructsAccessMode extends Enum {
     readonly isNormal: boolean;
     readonly isAllowList: boolean;
     readonly type: 'Normal' | 'AllowList';
   }
 
-  /** @name UpDataStructsCollectionLimits (247) */
+  /** @name UpDataStructsCollectionLimits (245) */
   interface UpDataStructsCollectionLimits extends Struct {
     readonly accountTokenOwnershipLimit: Option<u32>;
     readonly sponsoredDataSize: Option<u32>;
@@ -2571,7 +2585,7 @@
     readonly transfersEnabled: Option<bool>;
   }
 
-  /** @name UpDataStructsSponsoringRateLimit (249) */
+  /** @name UpDataStructsSponsoringRateLimit (247) */
   interface UpDataStructsSponsoringRateLimit extends Enum {
     readonly isSponsoringDisabled: boolean;
     readonly isBlocks: boolean;
@@ -2579,43 +2593,43 @@
     readonly type: 'SponsoringDisabled' | 'Blocks';
   }
 
-  /** @name UpDataStructsCollectionPermissions (252) */
+  /** @name UpDataStructsCollectionPermissions (250) */
   interface UpDataStructsCollectionPermissions extends Struct {
     readonly access: Option<UpDataStructsAccessMode>;
     readonly mintMode: Option<bool>;
     readonly nesting: Option<UpDataStructsNestingPermissions>;
   }
 
-  /** @name UpDataStructsNestingPermissions (254) */
+  /** @name UpDataStructsNestingPermissions (252) */
   interface UpDataStructsNestingPermissions extends Struct {
     readonly tokenOwner: bool;
     readonly collectionAdmin: bool;
     readonly restricted: Option<UpDataStructsOwnerRestrictedSet>;
   }
 
-  /** @name UpDataStructsOwnerRestrictedSet (256) */
+  /** @name UpDataStructsOwnerRestrictedSet (254) */
   interface UpDataStructsOwnerRestrictedSet extends BTreeSet<u32> {}
 
-  /** @name UpDataStructsPropertyKeyPermission (261) */
+  /** @name UpDataStructsPropertyKeyPermission (259) */
   interface UpDataStructsPropertyKeyPermission extends Struct {
     readonly key: Bytes;
     readonly permission: UpDataStructsPropertyPermission;
   }
 
-  /** @name UpDataStructsPropertyPermission (262) */
+  /** @name UpDataStructsPropertyPermission (260) */
   interface UpDataStructsPropertyPermission extends Struct {
     readonly mutable: bool;
     readonly collectionAdmin: bool;
     readonly tokenOwner: bool;
   }
 
-  /** @name UpDataStructsProperty (265) */
+  /** @name UpDataStructsProperty (263) */
   interface UpDataStructsProperty extends Struct {
     readonly key: Bytes;
     readonly value: Bytes;
   }
 
-  /** @name UpDataStructsCreateItemData (268) */
+  /** @name UpDataStructsCreateItemData (266) */
   interface UpDataStructsCreateItemData extends Enum {
     readonly isNft: boolean;
     readonly asNft: UpDataStructsCreateNftData;
@@ -2626,23 +2640,23 @@
     readonly type: 'Nft' | 'Fungible' | 'ReFungible';
   }
 
-  /** @name UpDataStructsCreateNftData (269) */
+  /** @name UpDataStructsCreateNftData (267) */
   interface UpDataStructsCreateNftData extends Struct {
     readonly properties: Vec<UpDataStructsProperty>;
   }
 
-  /** @name UpDataStructsCreateFungibleData (270) */
+  /** @name UpDataStructsCreateFungibleData (268) */
   interface UpDataStructsCreateFungibleData extends Struct {
     readonly value: u128;
   }
 
-  /** @name UpDataStructsCreateReFungibleData (271) */
+  /** @name UpDataStructsCreateReFungibleData (269) */
   interface UpDataStructsCreateReFungibleData extends Struct {
     readonly pieces: u128;
     readonly properties: Vec<UpDataStructsProperty>;
   }
 
-  /** @name UpDataStructsCreateItemExData (274) */
+  /** @name UpDataStructsCreateItemExData (272) */
   interface UpDataStructsCreateItemExData extends Enum {
     readonly isNft: boolean;
     readonly asNft: Vec<UpDataStructsCreateNftExData>;
@@ -2655,65 +2669,75 @@
     readonly type: 'Nft' | 'Fungible' | 'RefungibleMultipleItems' | 'RefungibleMultipleOwners';
   }
 
-  /** @name UpDataStructsCreateNftExData (276) */
+  /** @name UpDataStructsCreateNftExData (274) */
   interface UpDataStructsCreateNftExData extends Struct {
     readonly properties: Vec<UpDataStructsProperty>;
     readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
   }
 
-  /** @name UpDataStructsCreateRefungibleExSingleOwner (283) */
+  /** @name UpDataStructsCreateRefungibleExSingleOwner (281) */
   interface UpDataStructsCreateRefungibleExSingleOwner extends Struct {
     readonly user: PalletEvmAccountBasicCrossAccountIdRepr;
     readonly pieces: u128;
     readonly properties: Vec<UpDataStructsProperty>;
   }
 
-  /** @name UpDataStructsCreateRefungibleExMultipleOwners (285) */
+  /** @name UpDataStructsCreateRefungibleExMultipleOwners (283) */
   interface UpDataStructsCreateRefungibleExMultipleOwners extends Struct {
     readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
     readonly properties: Vec<UpDataStructsProperty>;
   }
 
-  /** @name PalletUniqueSchedulerCall (286) */
-  interface PalletUniqueSchedulerCall extends Enum {
+  /** @name PalletUniqueSchedulerV2Call (284) */
+  interface PalletUniqueSchedulerV2Call extends Enum {
+    readonly isSchedule: boolean;
+    readonly asSchedule: {
+      readonly when: u32;
+      readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+      readonly priority: Option<u8>;
+      readonly call: Call;
+    } & Struct;
+    readonly isCancel: boolean;
+    readonly asCancel: {
+      readonly when: u32;
+      readonly index: u32;
+    } & Struct;
     readonly isScheduleNamed: boolean;
     readonly asScheduleNamed: {
       readonly id: U8aFixed;
       readonly when: u32;
       readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
       readonly priority: Option<u8>;
-      readonly call: FrameSupportScheduleMaybeHashed;
+      readonly call: Call;
     } & Struct;
     readonly isCancelNamed: boolean;
     readonly asCancelNamed: {
       readonly id: U8aFixed;
     } & Struct;
+    readonly isScheduleAfter: boolean;
+    readonly asScheduleAfter: {
+      readonly after: u32;
+      readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
+      readonly priority: Option<u8>;
+      readonly call: Call;
+    } & Struct;
     readonly isScheduleNamedAfter: boolean;
     readonly asScheduleNamedAfter: {
       readonly id: U8aFixed;
       readonly after: u32;
       readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
       readonly priority: Option<u8>;
-      readonly call: FrameSupportScheduleMaybeHashed;
+      readonly call: Call;
     } & Struct;
     readonly isChangeNamedPriority: boolean;
     readonly asChangeNamedPriority: {
       readonly id: U8aFixed;
       readonly priority: u8;
     } & Struct;
-    readonly type: 'ScheduleNamed' | 'CancelNamed' | 'ScheduleNamedAfter' | 'ChangeNamedPriority';
-  }
-
-  /** @name FrameSupportScheduleMaybeHashed (289) */
-  interface FrameSupportScheduleMaybeHashed extends Enum {
-    readonly isValue: boolean;
-    readonly asValue: Call;
-    readonly isHash: boolean;
-    readonly asHash: H256;
-    readonly type: 'Value' | 'Hash';
+    readonly type: 'Schedule' | 'Cancel' | 'ScheduleNamed' | 'CancelNamed' | 'ScheduleAfter' | 'ScheduleNamedAfter' | 'ChangeNamedPriority';
   }
 
-  /** @name PalletConfigurationCall (290) */
+  /** @name PalletConfigurationCall (287) */
   interface PalletConfigurationCall extends Enum {
     readonly isSetWeightToFeeCoefficientOverride: boolean;
     readonly asSetWeightToFeeCoefficientOverride: {
@@ -2726,13 +2750,13 @@
     readonly type: 'SetWeightToFeeCoefficientOverride' | 'SetMinGasPriceOverride';
   }
 
-  /** @name PalletTemplateTransactionPaymentCall (292) */
+  /** @name PalletTemplateTransactionPaymentCall (289) */
   type PalletTemplateTransactionPaymentCall = Null;
 
-  /** @name PalletStructureCall (293) */
+  /** @name PalletStructureCall (290) */
   type PalletStructureCall = Null;
 
-  /** @name PalletRmrkCoreCall (294) */
+  /** @name PalletRmrkCoreCall (291) */
   interface PalletRmrkCoreCall extends Enum {
     readonly isCreateCollection: boolean;
     readonly asCreateCollection: {
@@ -2838,7 +2862,7 @@
     readonly type: 'CreateCollection' | 'DestroyCollection' | 'ChangeCollectionIssuer' | 'LockCollection' | 'MintNft' | 'BurnNft' | 'Send' | 'AcceptNft' | 'RejectNft' | 'AcceptResource' | 'AcceptResourceRemoval' | 'SetProperty' | 'SetPriority' | 'AddBasicResource' | 'AddComposableResource' | 'AddSlotResource' | 'RemoveResource';
   }
 
-  /** @name RmrkTraitsResourceResourceTypes (300) */
+  /** @name RmrkTraitsResourceResourceTypes (297) */
   interface RmrkTraitsResourceResourceTypes extends Enum {
     readonly isBasic: boolean;
     readonly asBasic: RmrkTraitsResourceBasicResource;
@@ -2849,7 +2873,7 @@
     readonly type: 'Basic' | 'Composable' | 'Slot';
   }
 
-  /** @name RmrkTraitsResourceBasicResource (302) */
+  /** @name RmrkTraitsResourceBasicResource (299) */
   interface RmrkTraitsResourceBasicResource extends Struct {
     readonly src: Option<Bytes>;
     readonly metadata: Option<Bytes>;
@@ -2857,7 +2881,7 @@
     readonly thumb: Option<Bytes>;
   }
 
-  /** @name RmrkTraitsResourceComposableResource (304) */
+  /** @name RmrkTraitsResourceComposableResource (301) */
   interface RmrkTraitsResourceComposableResource extends Struct {
     readonly parts: Vec<u32>;
     readonly base: u32;
@@ -2867,7 +2891,7 @@
     readonly thumb: Option<Bytes>;
   }
 
-  /** @name RmrkTraitsResourceSlotResource (305) */
+  /** @name RmrkTraitsResourceSlotResource (302) */
   interface RmrkTraitsResourceSlotResource extends Struct {
     readonly base: u32;
     readonly src: Option<Bytes>;
@@ -2877,7 +2901,7 @@
     readonly thumb: Option<Bytes>;
   }
 
-  /** @name PalletRmrkEquipCall (308) */
+  /** @name PalletRmrkEquipCall (305) */
   interface PalletRmrkEquipCall extends Enum {
     readonly isCreateBase: boolean;
     readonly asCreateBase: {
@@ -2899,7 +2923,7 @@
     readonly type: 'CreateBase' | 'ThemeAdd' | 'Equippable';
   }
 
-  /** @name RmrkTraitsPartPartType (311) */
+  /** @name RmrkTraitsPartPartType (308) */
   interface RmrkTraitsPartPartType extends Enum {
     readonly isFixedPart: boolean;
     readonly asFixedPart: RmrkTraitsPartFixedPart;
@@ -2908,14 +2932,14 @@
     readonly type: 'FixedPart' | 'SlotPart';
   }
 
-  /** @name RmrkTraitsPartFixedPart (313) */
+  /** @name RmrkTraitsPartFixedPart (310) */
   interface RmrkTraitsPartFixedPart extends Struct {
     readonly id: u32;
     readonly z: u32;
     readonly src: Bytes;
   }
 
-  /** @name RmrkTraitsPartSlotPart (314) */
+  /** @name RmrkTraitsPartSlotPart (311) */
   interface RmrkTraitsPartSlotPart extends Struct {
     readonly id: u32;
     readonly equippable: RmrkTraitsPartEquippableList;
@@ -2923,7 +2947,7 @@
     readonly z: u32;
   }
 
-  /** @name RmrkTraitsPartEquippableList (315) */
+  /** @name RmrkTraitsPartEquippableList (312) */
   interface RmrkTraitsPartEquippableList extends Enum {
     readonly isAll: boolean;
     readonly isEmpty: boolean;
@@ -2932,20 +2956,20 @@
     readonly type: 'All' | 'Empty' | 'Custom';
   }
 
-  /** @name RmrkTraitsTheme (317) */
+  /** @name RmrkTraitsTheme (314) */
   interface RmrkTraitsTheme extends Struct {
     readonly name: Bytes;
     readonly properties: Vec<RmrkTraitsThemeThemeProperty>;
     readonly inherit: bool;
   }
 
-  /** @name RmrkTraitsThemeThemeProperty (319) */
+  /** @name RmrkTraitsThemeThemeProperty (316) */
   interface RmrkTraitsThemeThemeProperty extends Struct {
     readonly key: Bytes;
     readonly value: Bytes;
   }
 
-  /** @name PalletAppPromotionCall (321) */
+  /** @name PalletAppPromotionCall (318) */
   interface PalletAppPromotionCall extends Enum {
     readonly isSetAdminAddress: boolean;
     readonly asSetAdminAddress: {
@@ -2979,7 +3003,7 @@
     readonly type: 'SetAdminAddress' | 'Stake' | 'Unstake' | 'SponsorCollection' | 'StopSponsoringCollection' | 'SponsorContract' | 'StopSponsoringContract' | 'PayoutStakers';
   }
 
-  /** @name PalletForeignAssetsModuleCall (322) */
+  /** @name PalletForeignAssetsModuleCall (319) */
   interface PalletForeignAssetsModuleCall extends Enum {
     readonly isRegisterForeignAsset: boolean;
     readonly asRegisterForeignAsset: {
@@ -2996,7 +3020,7 @@
     readonly type: 'RegisterForeignAsset' | 'UpdateForeignAsset';
   }
 
-  /** @name PalletEvmCall (323) */
+  /** @name PalletEvmCall (320) */
   interface PalletEvmCall extends Enum {
     readonly isWithdraw: boolean;
     readonly asWithdraw: {
@@ -3041,7 +3065,7 @@
     readonly type: 'Withdraw' | 'Call' | 'Create' | 'Create2';
   }
 
-  /** @name PalletEthereumCall (327) */
+  /** @name PalletEthereumCall (326) */
   interface PalletEthereumCall extends Enum {
     readonly isTransact: boolean;
     readonly asTransact: {
@@ -3050,7 +3074,7 @@
     readonly type: 'Transact';
   }
 
-  /** @name EthereumTransactionTransactionV2 (328) */
+  /** @name EthereumTransactionTransactionV2 (327) */
   interface EthereumTransactionTransactionV2 extends Enum {
     readonly isLegacy: boolean;
     readonly asLegacy: EthereumTransactionLegacyTransaction;
@@ -3061,7 +3085,7 @@
     readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
   }
 
-  /** @name EthereumTransactionLegacyTransaction (329) */
+  /** @name EthereumTransactionLegacyTransaction (328) */
   interface EthereumTransactionLegacyTransaction extends Struct {
     readonly nonce: U256;
     readonly gasPrice: U256;
@@ -3072,7 +3096,7 @@
     readonly signature: EthereumTransactionTransactionSignature;
   }
 
-  /** @name EthereumTransactionTransactionAction (330) */
+  /** @name EthereumTransactionTransactionAction (329) */
   interface EthereumTransactionTransactionAction extends Enum {
     readonly isCall: boolean;
     readonly asCall: H160;
@@ -3080,14 +3104,14 @@
     readonly type: 'Call' | 'Create';
   }
 
-  /** @name EthereumTransactionTransactionSignature (331) */
+  /** @name EthereumTransactionTransactionSignature (330) */
   interface EthereumTransactionTransactionSignature extends Struct {
     readonly v: u64;
     readonly r: H256;
     readonly s: H256;
   }
 
-  /** @name EthereumTransactionEip2930Transaction (333) */
+  /** @name EthereumTransactionEip2930Transaction (332) */
   interface EthereumTransactionEip2930Transaction extends Struct {
     readonly chainId: u64;
     readonly nonce: U256;
@@ -3102,13 +3126,13 @@
     readonly s: H256;
   }
 
-  /** @name EthereumTransactionAccessListItem (335) */
+  /** @name EthereumTransactionAccessListItem (334) */
   interface EthereumTransactionAccessListItem extends Struct {
     readonly address: H160;
     readonly storageKeys: Vec<H256>;
   }
 
-  /** @name EthereumTransactionEip1559Transaction (336) */
+  /** @name EthereumTransactionEip1559Transaction (335) */
   interface EthereumTransactionEip1559Transaction extends Struct {
     readonly chainId: u64;
     readonly nonce: U256;
@@ -3124,7 +3148,7 @@
     readonly s: H256;
   }
 
-  /** @name PalletEvmMigrationCall (337) */
+  /** @name PalletEvmMigrationCall (336) */
   interface PalletEvmMigrationCall extends Enum {
     readonly isBegin: boolean;
     readonly asBegin: {
@@ -3140,7 +3164,15 @@
       readonly address: H160;
       readonly code: Bytes;
     } & Struct;
-    readonly type: 'Begin' | 'SetData' | 'Finish';
+    readonly isInsertEthLogs: boolean;
+    readonly asInsertEthLogs: {
+      readonly logs: Vec<EthereumLog>;
+    } & Struct;
+    readonly isInsertEvents: boolean;
+    readonly asInsertEvents: {
+      readonly events: Vec<Bytes>;
+    } & Struct;
+    readonly type: 'Begin' | 'SetData' | 'Finish' | 'InsertEthLogs' | 'InsertEvents';
   }
 
   /** @name PalletMaintenanceCall (340) */
@@ -3168,16 +3200,20 @@
       readonly maxTestValue: u32;
     } & Struct;
     readonly isJustTakeFee: boolean;
-    readonly type: 'Enable' | 'SetTestValue' | 'SetTestValueAndRollback' | 'IncTestValue' | 'SelfCancelingInc' | 'JustTakeFee';
+    readonly isBatchAll: boolean;
+    readonly asBatchAll: {
+      readonly calls: Vec<Call>;
+    } & Struct;
+    readonly type: 'Enable' | 'SetTestValue' | 'SetTestValueAndRollback' | 'IncTestValue' | 'SelfCancelingInc' | 'JustTakeFee' | 'BatchAll';
   }
 
-  /** @name PalletSudoError (342) */
+  /** @name PalletSudoError (343) */
   interface PalletSudoError extends Enum {
     readonly isRequireSudo: boolean;
     readonly type: 'RequireSudo';
   }
 
-  /** @name OrmlVestingModuleError (344) */
+  /** @name OrmlVestingModuleError (345) */
   interface OrmlVestingModuleError extends Enum {
     readonly isZeroVestingPeriod: boolean;
     readonly isZeroVestingPeriodCount: boolean;
@@ -3188,7 +3224,7 @@
     readonly type: 'ZeroVestingPeriod' | 'ZeroVestingPeriodCount' | 'InsufficientBalanceToLock' | 'TooManyVestingSchedules' | 'AmountLow' | 'MaxVestingSchedulesExceeded';
   }
 
-  /** @name OrmlXtokensModuleError (345) */
+  /** @name OrmlXtokensModuleError (346) */
   interface OrmlXtokensModuleError extends Enum {
     readonly isAssetHasNoReserve: boolean;
     readonly isNotCrossChainTransfer: boolean;
@@ -3212,26 +3248,26 @@
     readonly type: 'AssetHasNoReserve' | 'NotCrossChainTransfer' | 'InvalidDest' | 'NotCrossChainTransferableCurrency' | 'UnweighableMessage' | 'XcmExecutionFailed' | 'CannotReanchor' | 'InvalidAncestry' | 'InvalidAsset' | 'DestinationNotInvertible' | 'BadVersion' | 'DistinctReserveForAssetAndFee' | 'ZeroFee' | 'ZeroAmount' | 'TooManyAssetsBeingSent' | 'AssetIndexNonExistent' | 'FeeNotEnough' | 'NotSupportedMultiLocation' | 'MinXcmFeeNotDefined';
   }
 
-  /** @name OrmlTokensBalanceLock (348) */
+  /** @name OrmlTokensBalanceLock (349) */
   interface OrmlTokensBalanceLock extends Struct {
     readonly id: U8aFixed;
     readonly amount: u128;
   }
 
-  /** @name OrmlTokensAccountData (350) */
+  /** @name OrmlTokensAccountData (351) */
   interface OrmlTokensAccountData extends Struct {
     readonly free: u128;
     readonly reserved: u128;
     readonly frozen: u128;
   }
 
-  /** @name OrmlTokensReserveData (352) */
+  /** @name OrmlTokensReserveData (353) */
   interface OrmlTokensReserveData extends Struct {
     readonly id: Null;
     readonly amount: u128;
   }
 
-  /** @name OrmlTokensModuleError (354) */
+  /** @name OrmlTokensModuleError (355) */
   interface OrmlTokensModuleError extends Enum {
     readonly isBalanceTooLow: boolean;
     readonly isAmountIntoBalanceFailed: boolean;
@@ -3244,21 +3280,21 @@
     readonly type: 'BalanceTooLow' | 'AmountIntoBalanceFailed' | 'LiquidityRestrictions' | 'MaxLocksExceeded' | 'KeepAlive' | 'ExistentialDeposit' | 'DeadAccount' | 'TooManyReserves';
   }
 
-  /** @name CumulusPalletXcmpQueueInboundChannelDetails (356) */
+  /** @name CumulusPalletXcmpQueueInboundChannelDetails (357) */
   interface CumulusPalletXcmpQueueInboundChannelDetails extends Struct {
     readonly sender: u32;
     readonly state: CumulusPalletXcmpQueueInboundState;
     readonly messageMetadata: Vec<ITuple<[u32, PolkadotParachainPrimitivesXcmpMessageFormat]>>;
   }
 
-  /** @name CumulusPalletXcmpQueueInboundState (357) */
+  /** @name CumulusPalletXcmpQueueInboundState (358) */
   interface CumulusPalletXcmpQueueInboundState extends Enum {
     readonly isOk: boolean;
     readonly isSuspended: boolean;
     readonly type: 'Ok' | 'Suspended';
   }
 
-  /** @name PolkadotParachainPrimitivesXcmpMessageFormat (360) */
+  /** @name PolkadotParachainPrimitivesXcmpMessageFormat (361) */
   interface PolkadotParachainPrimitivesXcmpMessageFormat extends Enum {
     readonly isConcatenatedVersionedXcm: boolean;
     readonly isConcatenatedEncodedBlob: boolean;
@@ -3266,7 +3302,7 @@
     readonly type: 'ConcatenatedVersionedXcm' | 'ConcatenatedEncodedBlob' | 'Signals';
   }
 
-  /** @name CumulusPalletXcmpQueueOutboundChannelDetails (363) */
+  /** @name CumulusPalletXcmpQueueOutboundChannelDetails (364) */
   interface CumulusPalletXcmpQueueOutboundChannelDetails extends Struct {
     readonly recipient: u32;
     readonly state: CumulusPalletXcmpQueueOutboundState;
@@ -3275,14 +3311,14 @@
     readonly lastIndex: u16;
   }
 
-  /** @name CumulusPalletXcmpQueueOutboundState (364) */
+  /** @name CumulusPalletXcmpQueueOutboundState (365) */
   interface CumulusPalletXcmpQueueOutboundState extends Enum {
     readonly isOk: boolean;
     readonly isSuspended: boolean;
     readonly type: 'Ok' | 'Suspended';
   }
 
-  /** @name CumulusPalletXcmpQueueQueueConfigData (366) */
+  /** @name CumulusPalletXcmpQueueQueueConfigData (367) */
   interface CumulusPalletXcmpQueueQueueConfigData extends Struct {
     readonly suspendThreshold: u32;
     readonly dropThreshold: u32;
@@ -3292,7 +3328,7 @@
     readonly xcmpMaxIndividualWeight: Weight;
   }
 
-  /** @name CumulusPalletXcmpQueueError (368) */
+  /** @name CumulusPalletXcmpQueueError (369) */
   interface CumulusPalletXcmpQueueError extends Enum {
     readonly isFailedToSend: boolean;
     readonly isBadXcmOrigin: boolean;
@@ -3302,7 +3338,7 @@
     readonly type: 'FailedToSend' | 'BadXcmOrigin' | 'BadXcm' | 'BadOverweightIndex' | 'WeightOverLimit';
   }
 
-  /** @name PalletXcmError (369) */
+  /** @name PalletXcmError (370) */
   interface PalletXcmError extends Enum {
     readonly isUnreachable: boolean;
     readonly isSendFailure: boolean;
@@ -3320,29 +3356,29 @@
     readonly type: 'Unreachable' | 'SendFailure' | 'Filtered' | 'UnweighableMessage' | 'DestinationNotInvertible' | 'Empty' | 'CannotReanchor' | 'TooManyAssets' | 'InvalidOrigin' | 'BadVersion' | 'BadLocation' | 'NoSubscription' | 'AlreadySubscribed';
   }
 
-  /** @name CumulusPalletXcmError (370) */
+  /** @name CumulusPalletXcmError (371) */
   type CumulusPalletXcmError = Null;
 
-  /** @name CumulusPalletDmpQueueConfigData (371) */
+  /** @name CumulusPalletDmpQueueConfigData (372) */
   interface CumulusPalletDmpQueueConfigData extends Struct {
     readonly maxIndividual: Weight;
   }
 
-  /** @name CumulusPalletDmpQueuePageIndexData (372) */
+  /** @name CumulusPalletDmpQueuePageIndexData (373) */
   interface CumulusPalletDmpQueuePageIndexData extends Struct {
     readonly beginUsed: u32;
     readonly endUsed: u32;
     readonly overweightCount: u64;
   }
 
-  /** @name CumulusPalletDmpQueueError (375) */
+  /** @name CumulusPalletDmpQueueError (376) */
   interface CumulusPalletDmpQueueError extends Enum {
     readonly isUnknown: boolean;
     readonly isOverLimit: boolean;
     readonly type: 'Unknown' | 'OverLimit';
   }
 
-  /** @name PalletUniqueError (379) */
+  /** @name PalletUniqueError (380) */
   interface PalletUniqueError extends Enum {
     readonly isCollectionDecimalPointLimitExceeded: boolean;
     readonly isConfirmUnsetSponsorFail: boolean;
@@ -3351,16 +3387,34 @@
     readonly type: 'CollectionDecimalPointLimitExceeded' | 'ConfirmUnsetSponsorFail' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection';
   }
 
-  /** @name PalletUniqueSchedulerScheduledV3 (382) */
-  interface PalletUniqueSchedulerScheduledV3 extends Struct {
+  /** @name PalletUniqueSchedulerV2BlockAgenda (381) */
+  interface PalletUniqueSchedulerV2BlockAgenda extends Struct {
+    readonly agenda: Vec<Option<PalletUniqueSchedulerV2Scheduled>>;
+    readonly freePlaces: u32;
+  }
+
+  /** @name PalletUniqueSchedulerV2Scheduled (384) */
+  interface PalletUniqueSchedulerV2Scheduled extends Struct {
     readonly maybeId: Option<U8aFixed>;
     readonly priority: u8;
-    readonly call: FrameSupportScheduleMaybeHashed;
+    readonly call: PalletUniqueSchedulerV2ScheduledCall;
     readonly maybePeriodic: Option<ITuple<[u32, u32]>>;
     readonly origin: OpalRuntimeOriginCaller;
   }
 
-  /** @name OpalRuntimeOriginCaller (383) */
+  /** @name PalletUniqueSchedulerV2ScheduledCall (385) */
+  interface PalletUniqueSchedulerV2ScheduledCall extends Enum {
+    readonly isInline: boolean;
+    readonly asInline: Bytes;
+    readonly isPreimageLookup: boolean;
+    readonly asPreimageLookup: {
+      readonly hash_: H256;
+      readonly unboundedLen: u32;
+    } & Struct;
+    readonly type: 'Inline' | 'PreimageLookup';
+  }
+
+  /** @name OpalRuntimeOriginCaller (387) */
   interface OpalRuntimeOriginCaller extends Enum {
     readonly isSystem: boolean;
     readonly asSystem: FrameSupportDispatchRawOrigin;
@@ -3374,7 +3428,7 @@
     readonly type: 'System' | 'Void' | 'PolkadotXcm' | 'CumulusXcm' | 'Ethereum';
   }
 
-  /** @name FrameSupportDispatchRawOrigin (384) */
+  /** @name FrameSupportDispatchRawOrigin (388) */
   interface FrameSupportDispatchRawOrigin extends Enum {
     readonly isRoot: boolean;
     readonly isSigned: boolean;
@@ -3383,7 +3437,7 @@
     readonly type: 'Root' | 'Signed' | 'None';
   }
 
-  /** @name PalletXcmOrigin (385) */
+  /** @name PalletXcmOrigin (389) */
   interface PalletXcmOrigin extends Enum {
     readonly isXcm: boolean;
     readonly asXcm: XcmV1MultiLocation;
@@ -3392,7 +3446,7 @@
     readonly type: 'Xcm' | 'Response';
   }
 
-  /** @name CumulusPalletXcmOrigin (386) */
+  /** @name CumulusPalletXcmOrigin (390) */
   interface CumulusPalletXcmOrigin extends Enum {
     readonly isRelay: boolean;
     readonly isSiblingParachain: boolean;
@@ -3400,26 +3454,30 @@
     readonly type: 'Relay' | 'SiblingParachain';
   }
 
-  /** @name PalletEthereumRawOrigin (387) */
+  /** @name PalletEthereumRawOrigin (391) */
   interface PalletEthereumRawOrigin extends Enum {
     readonly isEthereumTransaction: boolean;
     readonly asEthereumTransaction: H160;
     readonly type: 'EthereumTransaction';
   }
 
-  /** @name SpCoreVoid (388) */
+  /** @name SpCoreVoid (392) */
   type SpCoreVoid = Null;
 
-  /** @name PalletUniqueSchedulerError (389) */
-  interface PalletUniqueSchedulerError extends Enum {
+  /** @name PalletUniqueSchedulerV2Error (394) */
+  interface PalletUniqueSchedulerV2Error extends Enum {
     readonly isFailedToSchedule: boolean;
+    readonly isAgendaIsExhausted: boolean;
+    readonly isScheduledCallCorrupted: boolean;
+    readonly isPreimageNotFound: boolean;
+    readonly isTooBigScheduledCall: boolean;
     readonly isNotFound: boolean;
     readonly isTargetBlockNumberInPast: boolean;
-    readonly isRescheduleNoChange: boolean;
-    readonly type: 'FailedToSchedule' | 'NotFound' | 'TargetBlockNumberInPast' | 'RescheduleNoChange';
+    readonly isNamed: boolean;
+    readonly type: 'FailedToSchedule' | 'AgendaIsExhausted' | 'ScheduledCallCorrupted' | 'PreimageNotFound' | 'TooBigScheduledCall' | 'NotFound' | 'TargetBlockNumberInPast' | 'Named';
   }
 
-  /** @name UpDataStructsCollection (390) */
+  /** @name UpDataStructsCollection (395) */
   interface UpDataStructsCollection extends Struct {
     readonly owner: AccountId32;
     readonly mode: UpDataStructsCollectionMode;
@@ -3432,7 +3490,7 @@
     readonly flags: U8aFixed;
   }
 
-  /** @name UpDataStructsSponsorshipStateAccountId32 (391) */
+  /** @name UpDataStructsSponsorshipStateAccountId32 (396) */
   interface UpDataStructsSponsorshipStateAccountId32 extends Enum {
     readonly isDisabled: boolean;
     readonly isUnconfirmed: boolean;
@@ -3442,43 +3500,43 @@
     readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
   }
 
-  /** @name UpDataStructsProperties (393) */
+  /** @name UpDataStructsProperties (398) */
   interface UpDataStructsProperties extends Struct {
     readonly map: UpDataStructsPropertiesMapBoundedVec;
     readonly consumedSpace: u32;
     readonly spaceLimit: u32;
   }
 
-  /** @name UpDataStructsPropertiesMapBoundedVec (394) */
+  /** @name UpDataStructsPropertiesMapBoundedVec (399) */
   interface UpDataStructsPropertiesMapBoundedVec extends BTreeMap<Bytes, Bytes> {}
 
-  /** @name UpDataStructsPropertiesMapPropertyPermission (399) */
+  /** @name UpDataStructsPropertiesMapPropertyPermission (404) */
   interface UpDataStructsPropertiesMapPropertyPermission extends BTreeMap<Bytes, UpDataStructsPropertyPermission> {}
 
-  /** @name UpDataStructsCollectionStats (406) */
+  /** @name UpDataStructsCollectionStats (411) */
   interface UpDataStructsCollectionStats extends Struct {
     readonly created: u32;
     readonly destroyed: u32;
     readonly alive: u32;
   }
 
-  /** @name UpDataStructsTokenChild (407) */
+  /** @name UpDataStructsTokenChild (412) */
   interface UpDataStructsTokenChild extends Struct {
     readonly token: u32;
     readonly collection: u32;
   }
 
-  /** @name PhantomTypeUpDataStructs (408) */
+  /** @name PhantomTypeUpDataStructs (413) */
   interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftNftInfo, RmrkTraitsResourceResourceInfo, RmrkTraitsPropertyPropertyInfo, RmrkTraitsBaseBaseInfo, RmrkTraitsPartPartType, RmrkTraitsTheme, RmrkTraitsNftNftChild]>> {}
 
-  /** @name UpDataStructsTokenData (410) */
+  /** @name UpDataStructsTokenData (415) */
   interface UpDataStructsTokenData extends Struct {
     readonly properties: Vec<UpDataStructsProperty>;
     readonly owner: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
     readonly pieces: u128;
   }
 
-  /** @name UpDataStructsRpcCollection (412) */
+  /** @name UpDataStructsRpcCollection (417) */
   interface UpDataStructsRpcCollection extends Struct {
     readonly owner: AccountId32;
     readonly mode: UpDataStructsCollectionMode;
@@ -3494,13 +3552,13 @@
     readonly flags: UpDataStructsRpcCollectionFlags;
   }
 
-  /** @name UpDataStructsRpcCollectionFlags (413) */
+  /** @name UpDataStructsRpcCollectionFlags (418) */
   interface UpDataStructsRpcCollectionFlags extends Struct {
     readonly foreign: bool;
     readonly erc721metadata: bool;
   }
 
-  /** @name RmrkTraitsCollectionCollectionInfo (414) */
+  /** @name RmrkTraitsCollectionCollectionInfo (419) */
   interface RmrkTraitsCollectionCollectionInfo extends Struct {
     readonly issuer: AccountId32;
     readonly metadata: Bytes;
@@ -3509,7 +3567,7 @@
     readonly nftsCount: u32;
   }
 
-  /** @name RmrkTraitsNftNftInfo (415) */
+  /** @name RmrkTraitsNftNftInfo (420) */
   interface RmrkTraitsNftNftInfo extends Struct {
     readonly owner: RmrkTraitsNftAccountIdOrCollectionNftTuple;
     readonly royalty: Option<RmrkTraitsNftRoyaltyInfo>;
@@ -3518,13 +3576,13 @@
     readonly pending: bool;
   }
 
-  /** @name RmrkTraitsNftRoyaltyInfo (417) */
+  /** @name RmrkTraitsNftRoyaltyInfo (422) */
   interface RmrkTraitsNftRoyaltyInfo extends Struct {
     readonly recipient: AccountId32;
     readonly amount: Permill;
   }
 
-  /** @name RmrkTraitsResourceResourceInfo (418) */
+  /** @name RmrkTraitsResourceResourceInfo (423) */
   interface RmrkTraitsResourceResourceInfo extends Struct {
     readonly id: u32;
     readonly resource: RmrkTraitsResourceResourceTypes;
@@ -3532,26 +3590,26 @@
     readonly pendingRemoval: bool;
   }
 
-  /** @name RmrkTraitsPropertyPropertyInfo (419) */
+  /** @name RmrkTraitsPropertyPropertyInfo (424) */
   interface RmrkTraitsPropertyPropertyInfo extends Struct {
     readonly key: Bytes;
     readonly value: Bytes;
   }
 
-  /** @name RmrkTraitsBaseBaseInfo (420) */
+  /** @name RmrkTraitsBaseBaseInfo (425) */
   interface RmrkTraitsBaseBaseInfo extends Struct {
     readonly issuer: AccountId32;
     readonly baseType: Bytes;
     readonly symbol: Bytes;
   }
 
-  /** @name RmrkTraitsNftNftChild (421) */
+  /** @name RmrkTraitsNftNftChild (426) */
   interface RmrkTraitsNftNftChild extends Struct {
     readonly collectionId: u32;
     readonly nftId: u32;
   }
 
-  /** @name PalletCommonError (423) */
+  /** @name PalletCommonError (428) */
   interface PalletCommonError extends Enum {
     readonly isCollectionNotFound: boolean;
     readonly isMustBeTokenOwner: boolean;
@@ -3590,7 +3648,7 @@
     readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal';
   }
 
-  /** @name PalletFungibleError (425) */
+  /** @name PalletFungibleError (430) */
   interface PalletFungibleError extends Enum {
     readonly isNotFungibleDataUsedToMintFungibleCollectionToken: boolean;
     readonly isFungibleItemsHaveNoId: boolean;
@@ -3600,12 +3658,12 @@
     readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
   }
 
-  /** @name PalletRefungibleItemData (426) */
+  /** @name PalletRefungibleItemData (431) */
   interface PalletRefungibleItemData extends Struct {
     readonly constData: Bytes;
   }
 
-  /** @name PalletRefungibleError (431) */
+  /** @name PalletRefungibleError (436) */
   interface PalletRefungibleError extends Enum {
     readonly isNotRefungibleDataUsedToMintFungibleCollectionToken: boolean;
     readonly isWrongRefungiblePieces: boolean;
@@ -3615,19 +3673,19 @@
     readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RepartitionWhileNotOwningAllPieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
   }
 
-  /** @name PalletNonfungibleItemData (432) */
+  /** @name PalletNonfungibleItemData (437) */
   interface PalletNonfungibleItemData extends Struct {
     readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
   }
 
-  /** @name UpDataStructsPropertyScope (434) */
+  /** @name UpDataStructsPropertyScope (439) */
   interface UpDataStructsPropertyScope extends Enum {
     readonly isNone: boolean;
     readonly isRmrk: boolean;
     readonly type: 'None' | 'Rmrk';
   }
 
-  /** @name PalletNonfungibleError (436) */
+  /** @name PalletNonfungibleError (441) */
   interface PalletNonfungibleError extends Enum {
     readonly isNotNonfungibleDataUsedToMintFungibleCollectionToken: boolean;
     readonly isNonfungibleItemsHaveNoAmount: boolean;
@@ -3635,7 +3693,7 @@
     readonly type: 'NotNonfungibleDataUsedToMintFungibleCollectionToken' | 'NonfungibleItemsHaveNoAmount' | 'CantBurnNftWithChildren';
   }
 
-  /** @name PalletStructureError (437) */
+  /** @name PalletStructureError (442) */
   interface PalletStructureError extends Enum {
     readonly isOuroborosDetected: boolean;
     readonly isDepthLimit: boolean;
@@ -3644,7 +3702,7 @@
     readonly type: 'OuroborosDetected' | 'DepthLimit' | 'BreadthLimit' | 'TokenNotFound';
   }
 
-  /** @name PalletRmrkCoreError (438) */
+  /** @name PalletRmrkCoreError (443) */
   interface PalletRmrkCoreError extends Enum {
     readonly isCorruptedCollectionType: boolean;
     readonly isRmrkPropertyKeyIsTooLong: boolean;
@@ -3668,7 +3726,7 @@
     readonly type: 'CorruptedCollectionType' | 'RmrkPropertyKeyIsTooLong' | 'RmrkPropertyValueIsTooLong' | 'RmrkPropertyIsNotFound' | 'UnableToDecodeRmrkData' | 'CollectionNotEmpty' | 'NoAvailableCollectionId' | 'NoAvailableNftId' | 'CollectionUnknown' | 'NoPermission' | 'NonTransferable' | 'CollectionFullOrLocked' | 'ResourceDoesntExist' | 'CannotSendToDescendentOrSelf' | 'CannotAcceptNonOwnedNft' | 'CannotRejectNonOwnedNft' | 'CannotRejectNonPendingNft' | 'ResourceNotPending' | 'NoAvailableResourceId';
   }
 
-  /** @name PalletRmrkEquipError (440) */
+  /** @name PalletRmrkEquipError (445) */
   interface PalletRmrkEquipError extends Enum {
     readonly isPermissionError: boolean;
     readonly isNoAvailableBaseId: boolean;
@@ -3680,7 +3738,7 @@
     readonly type: 'PermissionError' | 'NoAvailableBaseId' | 'NoAvailablePartId' | 'BaseDoesntExist' | 'NeedsDefaultThemeFirst' | 'PartDoesntExist' | 'NoEquippableOnFixedPart';
   }
 
-  /** @name PalletAppPromotionError (446) */
+  /** @name PalletAppPromotionError (451) */
   interface PalletAppPromotionError extends Enum {
     readonly isAdminNotSet: boolean;
     readonly isNoPermission: boolean;
@@ -3691,7 +3749,7 @@
     readonly type: 'AdminNotSet' | 'NoPermission' | 'NotSufficientFunds' | 'PendingForBlockOverflow' | 'SponsorNotSet' | 'IncorrectLockedBalanceOperation';
   }
 
-  /** @name PalletForeignAssetsModuleError (447) */
+  /** @name PalletForeignAssetsModuleError (452) */
   interface PalletForeignAssetsModuleError extends Enum {
     readonly isBadLocation: boolean;
     readonly isMultiLocationExisted: boolean;
@@ -3700,7 +3758,7 @@
     readonly type: 'BadLocation' | 'MultiLocationExisted' | 'AssetIdNotExists' | 'AssetIdExisted';
   }
 
-  /** @name PalletEvmError (450) */
+  /** @name PalletEvmError (454) */
   interface PalletEvmError extends Enum {
     readonly isBalanceLow: boolean;
     readonly isFeeOverflow: boolean;
@@ -3708,10 +3766,14 @@
     readonly isWithdrawFailed: boolean;
     readonly isGasPriceTooLow: boolean;
     readonly isInvalidNonce: boolean;
-    readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce';
+    readonly isGasLimitTooLow: boolean;
+    readonly isGasLimitTooHigh: boolean;
+    readonly isUndefined: boolean;
+    readonly isReentrancy: boolean;
+    readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce' | 'GasLimitTooLow' | 'GasLimitTooHigh' | 'Undefined' | 'Reentrancy';
   }
 
-  /** @name FpRpcTransactionStatus (453) */
+  /** @name FpRpcTransactionStatus (457) */
   interface FpRpcTransactionStatus extends Struct {
     readonly transactionHash: H256;
     readonly transactionIndex: u32;
@@ -3722,10 +3784,10 @@
     readonly logsBloom: EthbloomBloom;
   }
 
-  /** @name EthbloomBloom (455) */
+  /** @name EthbloomBloom (459) */
   interface EthbloomBloom extends U8aFixed {}
 
-  /** @name EthereumReceiptReceiptV3 (457) */
+  /** @name EthereumReceiptReceiptV3 (461) */
   interface EthereumReceiptReceiptV3 extends Enum {
     readonly isLegacy: boolean;
     readonly asLegacy: EthereumReceiptEip658ReceiptData;
@@ -3736,7 +3798,7 @@
     readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
   }
 
-  /** @name EthereumReceiptEip658ReceiptData (458) */
+  /** @name EthereumReceiptEip658ReceiptData (462) */
   interface EthereumReceiptEip658ReceiptData extends Struct {
     readonly statusCode: u8;
     readonly usedGas: U256;
@@ -3744,14 +3806,14 @@
     readonly logs: Vec<EthereumLog>;
   }
 
-  /** @name EthereumBlock (459) */
+  /** @name EthereumBlock (463) */
   interface EthereumBlock extends Struct {
     readonly header: EthereumHeader;
     readonly transactions: Vec<EthereumTransactionTransactionV2>;
     readonly ommers: Vec<EthereumHeader>;
   }
 
-  /** @name EthereumHeader (460) */
+  /** @name EthereumHeader (464) */
   interface EthereumHeader extends Struct {
     readonly parentHash: H256;
     readonly ommersHash: H256;
@@ -3770,24 +3832,24 @@
     readonly nonce: EthereumTypesHashH64;
   }
 
-  /** @name EthereumTypesHashH64 (461) */
+  /** @name EthereumTypesHashH64 (465) */
   interface EthereumTypesHashH64 extends U8aFixed {}
 
-  /** @name PalletEthereumError (466) */
+  /** @name PalletEthereumError (470) */
   interface PalletEthereumError extends Enum {
     readonly isInvalidSignature: boolean;
     readonly isPreLogExists: boolean;
     readonly type: 'InvalidSignature' | 'PreLogExists';
   }
 
-  /** @name PalletEvmCoderSubstrateError (467) */
+  /** @name PalletEvmCoderSubstrateError (471) */
   interface PalletEvmCoderSubstrateError extends Enum {
     readonly isOutOfGas: boolean;
     readonly isOutOfFund: boolean;
     readonly type: 'OutOfGas' | 'OutOfFund';
   }
 
-  /** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr (468) */
+  /** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr (472) */
   interface UpDataStructsSponsorshipStateBasicCrossAccountIdRepr extends Enum {
     readonly isDisabled: boolean;
     readonly isUnconfirmed: boolean;
@@ -3797,7 +3859,7 @@
     readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
   }
 
-  /** @name PalletEvmContractHelpersSponsoringModeT (469) */
+  /** @name PalletEvmContractHelpersSponsoringModeT (473) */
   interface PalletEvmContractHelpersSponsoringModeT extends Enum {
     readonly isDisabled: boolean;
     readonly isAllowlisted: boolean;
@@ -3805,7 +3867,7 @@
     readonly type: 'Disabled' | 'Allowlisted' | 'Generous';
   }
 
-  /** @name PalletEvmContractHelpersError (475) */
+  /** @name PalletEvmContractHelpersError (479) */
   interface PalletEvmContractHelpersError extends Enum {
     readonly isNoPermission: boolean;
     readonly isNoPendingSponsor: boolean;
@@ -3813,24 +3875,25 @@
     readonly type: 'NoPermission' | 'NoPendingSponsor' | 'TooManyMethodsHaveSponsoredLimit';
   }
 
-  /** @name PalletEvmMigrationError (476) */
+  /** @name PalletEvmMigrationError (480) */
   interface PalletEvmMigrationError extends Enum {
     readonly isAccountNotEmpty: boolean;
     readonly isAccountIsNotMigrating: boolean;
-    readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating';
+    readonly isBadEvent: boolean;
+    readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating' | 'BadEvent';
   }
 
-  /** @name PalletMaintenanceError (477) */
+  /** @name PalletMaintenanceError (481) */
   type PalletMaintenanceError = Null;
 
-  /** @name PalletTestUtilsError (478) */
+  /** @name PalletTestUtilsError (482) */
   interface PalletTestUtilsError extends Enum {
     readonly isTestPalletDisabled: boolean;
     readonly isTriggerRollback: boolean;
     readonly type: 'TestPalletDisabled' | 'TriggerRollback';
   }
 
-  /** @name SpRuntimeMultiSignature (480) */
+  /** @name SpRuntimeMultiSignature (484) */
   interface SpRuntimeMultiSignature extends Enum {
     readonly isEd25519: boolean;
     readonly asEd25519: SpCoreEd25519Signature;
@@ -3841,40 +3904,40 @@
     readonly type: 'Ed25519' | 'Sr25519' | 'Ecdsa';
   }
 
-  /** @name SpCoreEd25519Signature (481) */
+  /** @name SpCoreEd25519Signature (485) */
   interface SpCoreEd25519Signature extends U8aFixed {}
 
-  /** @name SpCoreSr25519Signature (483) */
+  /** @name SpCoreSr25519Signature (487) */
   interface SpCoreSr25519Signature extends U8aFixed {}
 
-  /** @name SpCoreEcdsaSignature (484) */
+  /** @name SpCoreEcdsaSignature (488) */
   interface SpCoreEcdsaSignature extends U8aFixed {}
 
-  /** @name FrameSystemExtensionsCheckSpecVersion (487) */
+  /** @name FrameSystemExtensionsCheckSpecVersion (491) */
   type FrameSystemExtensionsCheckSpecVersion = Null;
 
-  /** @name FrameSystemExtensionsCheckTxVersion (488) */
+  /** @name FrameSystemExtensionsCheckTxVersion (492) */
   type FrameSystemExtensionsCheckTxVersion = Null;
 
-  /** @name FrameSystemExtensionsCheckGenesis (489) */
+  /** @name FrameSystemExtensionsCheckGenesis (493) */
   type FrameSystemExtensionsCheckGenesis = Null;
 
-  /** @name FrameSystemExtensionsCheckNonce (492) */
+  /** @name FrameSystemExtensionsCheckNonce (496) */
   interface FrameSystemExtensionsCheckNonce extends Compact<u32> {}
 
-  /** @name FrameSystemExtensionsCheckWeight (493) */
+  /** @name FrameSystemExtensionsCheckWeight (497) */
   type FrameSystemExtensionsCheckWeight = Null;
 
-  /** @name OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance (494) */
+  /** @name OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance (498) */
   type OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance = Null;
 
-  /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (495) */
+  /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (499) */
   interface PalletTemplateTransactionPaymentChargeTransactionPayment extends Compact<u128> {}
 
-  /** @name OpalRuntimeRuntime (496) */
+  /** @name OpalRuntimeRuntime (500) */
   type OpalRuntimeRuntime = Null;
 
-  /** @name PalletEthereumFakeTransactionFinalizer (497) */
+  /** @name PalletEthereumFakeTransactionFinalizer (501) */
   type PalletEthereumFakeTransactionFinalizer = Null;
 
 } // declare module
modifiedtests/src/maintenanceMode.seqtest.tsdiffbeforeafterboth
--- a/tests/src/maintenanceMode.seqtest.ts
+++ b/tests/src/maintenanceMode.seqtest.ts
@@ -237,7 +237,7 @@
     expect(tokenId).to.be.equal('1');
 
     await expect(contract.methods.mintWithTokenURI(receiver, 'Test URI').send())
-      .to.be.rejectedWith(/submit transaction to pool failed: Pool\(InvalidTransaction\(InvalidTransaction::Call\)\)/);
+      .to.be.rejectedWith(/Returned error: unknown error/);
 
     await expect(contract.methods.ownerOf(tokenId).call()).rejectedWith(/token not found/);
 
modifiedtests/src/refungible.test.tsdiffbeforeafterboth
--- a/tests/src/refungible.test.ts
+++ b/tests/src/refungible.test.ts
@@ -255,3 +255,43 @@
   });
 });
 
+describe('Refungible negative tests', () => {
+  let donor: IKeyringPair;
+  let alice: IKeyringPair;
+  let bob: IKeyringPair;
+  let charlie: IKeyringPair;
+
+  before(async function() {
+    await usingPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+
+      donor = await privateKey({filename: __filename});
+      [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);
+    });
+  });
+
+  itSub('Cannot transfer incorrect amount of token pieces', async ({helper}) => {
+    const collection = await helper.rft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+    const tokenAlice = await collection.mintToken(alice, 10n, {Substrate: alice.address});
+    const tokenBob = await collection.mintToken(alice, 10n, {Substrate: bob.address});
+
+    // 1. Alice cannot transfer Bob's token:
+    await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 0n)).to.be.rejectedWith('common.TokenValueTooLow');
+    await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.TokenValueTooLow');
+    await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 10n)).to.be.rejectedWith('common.TokenValueTooLow');
+    await expect(tokenBob.transfer(alice, {Substrate: charlie.address}, 100n)).to.be.rejectedWith('common.TokenValueTooLow');
+    
+    // 2. Alice cannot transfer non-existing token:
+    await expect(collection.transferToken(alice, 100, {Substrate: charlie.address}, 0n)).to.be.rejectedWith('common.TokenValueTooLow');
+    await expect(collection.transferToken(alice, 100, {Substrate: charlie.address}, 1n)).to.be.rejectedWith('common.TokenValueTooLow');
+
+    // 3. Zero transfer allowed (EIP-20):
+    await tokenAlice.transfer(alice, {Substrate: charlie.address}, 0n);
+
+    expect(await tokenAlice.getTop10Owners()).to.deep.eq([{Substrate: alice.address}]);
+    expect(await tokenBob.getTop10Owners()).to.deep.eq([{Substrate: bob.address}]);
+    expect(await tokenAlice.getBalance({Substrate: alice.address})).to.eq(10n);
+    expect(await tokenBob.getBalance({Substrate: bob.address})).to.eq(10n);
+    expect(await tokenBob.getBalance({Substrate: charlie.address})).to.eq(0n);
+  });
+});
modifiedtests/src/transfer.test.tsdiffbeforeafterboth
--- a/tests/src/transfer.test.ts
+++ b/tests/src/transfer.test.ts
@@ -122,6 +122,7 @@
     });
   });
 
+
   itSub('[nft] Transfer with not existed collection_id', async ({helper}) => {
     const collectionId = (1 << 32) - 1;
     await expect(helper.nft.transferToken(alice, collectionId, 1, {Substrate: bob.address}))
@@ -191,6 +192,25 @@
       .to.be.rejectedWith(/common\.TokenValueTooLow/);
   });
 
+  itSub('Zero transfer NFT', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-3-NFT', description: '', tokenPrefix: 'T'});
+    const tokenAlice = await collection.mintToken(alice, {Substrate: alice.address});
+    const tokenBob = await collection.mintToken(alice, {Substrate: bob.address});
+    // 1. Zero transfer of own tokens allowed:
+    await helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: bob.address}, collection.collectionId, tokenAlice.tokenId, 0]);
+    // 2. Zero transfer of non-owned tokens not allowed:
+    await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: alice.address}, collection.collectionId, tokenBob.tokenId, 0])).to.be.rejectedWith('common.NoPermission');
+    // 3. Zero transfer of non-existing tokens not allowed:
+    await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transfer', [{Substrate: alice.address}, collection.collectionId, 10, 0])).to.be.rejectedWith('common.TokenNotFound');
+    expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: alice.address});
+    expect(await tokenBob.getOwner()).to.deep.eq({Substrate: bob.address});
+    // 4. Storage is not corrupted:
+    await tokenAlice.transfer(alice, {Substrate: bob.address});
+    await tokenBob.transfer(bob, {Substrate: alice.address});
+    expect(await tokenAlice.getOwner()).to.deep.eq({Substrate: bob.address});
+    expect(await tokenBob.getOwner()).to.deep.eq({Substrate: alice.address});
+  });
+
   itSub('[nft] Transfer with deleted item_id', async ({helper}) => {
     const collection = await helper.nft.mintCollection(alice, {name: 'Transfer-Neg-3-NFT', description: '', tokenPrefix: 'T'});
     const nft = await collection.mintToken(alice);
modifiedtests/src/transferFrom.test.tsdiffbeforeafterboth
--- a/tests/src/transferFrom.test.ts
+++ b/tests/src/transferFrom.test.ts
@@ -349,4 +349,27 @@
       {Substrate: charlie.address},
     )).to.be.rejectedWith(/common\.ApprovedValueTooLow/);
   });
+
+  itSub('zero transfer NFT', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {name: 'Zero', description: 'Zero transfer', tokenPrefix: 'TF'});
+    const notApprovedNft = await collection.mintToken(alice, {Substrate: bob.address});
+    const approvedNft = await collection.mintToken(alice, {Substrate: bob.address});
+    await approvedNft.approve(bob, {Substrate: alice.address});
+
+    // 1. Cannot zero transferFrom (non-existing token)
+    await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transferFrom', [{Substrate: bob.address}, {Substrate: alice.address}, collection.collectionId, 9999, 0])).to.be.rejectedWith('common.ApprovedValueTooLow');
+    // 2. Cannot zero transferFrom (not approved token)
+    await expect(helper.executeExtrinsic(alice, 'api.tx.unique.transferFrom', [{Substrate: bob.address}, {Substrate: alice.address}, collection.collectionId, notApprovedNft.tokenId, 0])).to.be.rejectedWith('common.ApprovedValueTooLow');
+    // 3. Can zero transferFrom (approved token):
+    await helper.executeExtrinsic(alice, 'api.tx.unique.transferFrom', [{Substrate: bob.address}, {Substrate: alice.address}, collection.collectionId, approvedNft.tokenId, 0]);
+
+    // 4.1 approvedNft still approved:
+    expect(await approvedNft.isApproved({Substrate: alice.address})).to.be.true;
+    // 4.2 bob is still the owner:
+    expect(await approvedNft.getOwner()).to.deep.eq({Substrate: bob.address});
+    expect(await notApprovedNft.getOwner()).to.deep.eq({Substrate: bob.address});
+    // 4.3 Alice can transfer approved nft:
+    await approvedNft.transferFrom(alice, {Substrate: bob.address}, {Substrate: alice.address});
+    expect(await approvedNft.getOwner()).to.deep.eq({Substrate: alice.address});
+  });
 });
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -2484,7 +2484,7 @@
    * @param ethCrossAccount etherium cross account
    * @returns substrate cross account id
    */
-  convertCrossAccountFromEthCrossAcoount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId {
+  convertCrossAccountFromEthCrossAccount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId {
     if (ethCrossAccount.sub === '0') {
       return {Ethereum: ethCrossAccount.eth.toLocaleLowerCase()};
     }