difftreelog
Merge branch 'develop' into tests/vesting
in: master
144 files changed
.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
.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
.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:
.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"
]
},
{
.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"
]
}
]
.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"
]
},
{
.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
.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
.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
Cargo.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",
]
client/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" }
crates/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
crates/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]
crates/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"
crates/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(())
+}
crates/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
+ }
+ }
+ })
+}
crates/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()
+}
crates/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()
+}
crates/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)) }
crates/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);
crates/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))
crates/evm-coder/src/abi/test.rsdiffbeforeafterboth--- a/crates/evm-coder/src/abi/test.rs
+++ b/crates/evm-coder/src/abi/test.rs
@@ -6,36 +6,25 @@
use super::{AbiReader, AbiWriter};
use hex_literal::hex;
use primitive_types::{H160, U256};
-use concat_idents::concat_idents;
-macro_rules! test_impl {
- ($name:ident, $type:ty, $function_identifier:expr, $decoded_data:expr, $encoded_data:expr) => {
- concat_idents!(test_name = encode_decode_, $name {
- #[test]
- fn test_name() {
- let function_identifier: u32 = $function_identifier;
- let decoded_data = $decoded_data;
- let encoded_data = $encoded_data;
-
- let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();
- assert_eq!(call, u32::to_be_bytes(function_identifier));
- let data = <$type>::abi_read(&mut decoder).unwrap();
- assert_eq!(data, decoded_data);
+fn test_impl<T>(function_identifier: u32, decoded_data: T, encoded_data: &[u8])
+where
+ T: AbiWrite + AbiRead + std::cmp::PartialEq + std::fmt::Debug,
+{
+ let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();
+ assert_eq!(call, u32::to_be_bytes(function_identifier));
+ let data = <T>::abi_read(&mut decoder).unwrap();
+ assert_eq!(data, decoded_data);
- let mut writer = AbiWriter::new_call(function_identifier);
- decoded_data.abi_write(&mut writer);
- let ed = writer.finish();
- similar_asserts::assert_eq!(encoded_data, ed.as_slice());
- }
- });
- };
+ let mut writer = AbiWriter::new_call(function_identifier);
+ decoded_data.abi_write(&mut writer);
+ let ed = writer.finish();
+ similar_asserts::assert_eq!(encoded_data, ed.as_slice());
}
macro_rules! test_impl_uint {
($type:ident) => {
- test_impl!(
- $type,
- $type,
+ test_impl::<$type>(
0xdeadbeef,
255 as $type,
&hex!(
@@ -43,101 +32,148 @@
deadbeef
00000000000000000000000000000000000000000000000000000000000000ff
"
- )
+ ),
);
};
}
-test_impl_uint!(uint8);
-test_impl_uint!(uint32);
-test_impl_uint!(uint128);
+#[test]
+fn encode_decode_uint8() {
+ test_impl_uint!(uint8);
+}
-test_impl!(
- uint256,
- uint256,
- 0xdeadbeef,
- U256([255, 0, 0, 0]),
- &hex!(
- "
- deadbeef
- 00000000000000000000000000000000000000000000000000000000000000ff
- "
- )
-);
+#[test]
+fn encode_decode_uint32() {
+ test_impl_uint!(uint32);
+}
-test_impl!(
- vec_tuple_address_uint256,
- Vec<(address, uint256)>,
- 0x1ACF2D55,
- vec![
- (
- H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),
- U256([10, 0, 0, 0]),
- ),
- (
- H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),
- U256([20, 0, 0, 0]),
- ),
- (
- H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),
- U256([30, 0, 0, 0]),
- ),
- ],
- &hex!(
- "
- 1ACF2D55
- 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]
- 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]
+#[test]
+fn encode_decode_uint128() {
+ test_impl_uint!(uint128);
+}
- 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address
- 000000000000000000000000000000000000000000000000000000000000000A // uint256
+#[test]
+fn encode_decode_uint256() {
+ test_impl::<uint256>(
+ 0xdeadbeef,
+ U256([255, 0, 0, 0]),
+ &hex!(
+ "
+ deadbeef
+ 00000000000000000000000000000000000000000000000000000000000000ff
+ "
+ ),
+ );
+}
- 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address
- 0000000000000000000000000000000000000000000000000000000000000014 // uint256
+#[test]
+fn encode_decode_string() {
+ test_impl::<String>(
+ 0xdeadbeef,
+ "some string".to_string(),
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 736f6d6520737472696e67000000000000000000000000000000000000000000
+ "
+ ),
+ );
+}
- 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address
- 000000000000000000000000000000000000000000000000000000000000001E // uint256
- "
- )
-);
+#[test]
+fn encode_decode_tuple_string() {
+ test_impl::<(String,)>(
+ 0xdeadbeef,
+ ("some string".to_string(),),
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 736f6d6520737472696e67000000000000000000000000000000000000000000
+ "
+ ),
+ );
+}
-test_impl!(
- vec_tuple_uint256_string,
- Vec<(uint256, string)>,
- 0xdeadbeef,
- vec![
- (1.into(), "Test URI 0".to_string()),
- (11.into(), "Test URI 1".to_string()),
- (12.into(), "Test URI 2".to_string()),
- ],
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]
- 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]
+#[test]
+fn encode_decode_vec_tuple_address_uint256() {
+ test_impl::<Vec<(address, uint256)>>(
+ 0x1ACF2D55,
+ vec![
+ (
+ H160(hex!("2D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC")),
+ U256([10, 0, 0, 0]),
+ ),
+ (
+ H160(hex!("AB8E3D9134955566483B11E6825C9223B6737B10")),
+ U256([20, 0, 0, 0]),
+ ),
+ (
+ H160(hex!("8C582BDF2953046705FC56F189385255EFC1BE18")),
+ U256([30, 0, 0, 0]),
+ ),
+ ],
+ &hex!(
+ "
+ 1ACF2D55
+ 0000000000000000000000000000000000000000000000000000000000000020 // offset of (address, uint256)[]
+ 0000000000000000000000000000000000000000000000000000000000000003 // length of (address, uint256)[]
- 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem
- 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem
- 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem
+ 0000000000000000000000002D2FF76104B7BACB2E8F6731D5BFC184EBECDDBC // address
+ 000000000000000000000000000000000000000000000000000000000000000A // uint256
- 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60
- 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
- 000000000000000000000000000000000000000000000000000000000000000a // size of string
- 5465737420555249203000000000000000000000000000000000000000000000 // string
+ 000000000000000000000000AB8E3D9134955566483B11E6825C9223B6737B10 // address
+ 0000000000000000000000000000000000000000000000000000000000000014 // uint256
- 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0
- 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
- 000000000000000000000000000000000000000000000000000000000000000a // size of string
- 5465737420555249203100000000000000000000000000000000000000000000 // string
+ 0000000000000000000000008C582BDF2953046705FC56F189385255EFC1BE18 // address
+ 000000000000000000000000000000000000000000000000000000000000001E // uint256
+ "
+ )
+ );
+}
- 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160
- 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
- 000000000000000000000000000000000000000000000000000000000000000a // size of string
- 5465737420555249203200000000000000000000000000000000000000000000 // string
- "
- )
-);
+#[test]
+fn encode_decode_vec_tuple_uint256_string() {
+ test_impl::<Vec<(uint256, string)>>(
+ 0xdeadbeef,
+ vec![
+ (1.into(), "Test URI 0".to_string()),
+ (11.into(), "Test URI 1".to_string()),
+ (12.into(), "Test URI 2".to_string()),
+ ],
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020 // offset of (uint256, string)[]
+ 0000000000000000000000000000000000000000000000000000000000000003 // length of (uint256, string)[]
+ 0000000000000000000000000000000000000000000000000000000000000060 // offset of first elem
+ 00000000000000000000000000000000000000000000000000000000000000e0 // offset of second elem
+ 0000000000000000000000000000000000000000000000000000000000000160 // offset of third elem
+
+ 0000000000000000000000000000000000000000000000000000000000000001 // first token id? #60
+ 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+ 000000000000000000000000000000000000000000000000000000000000000a // size of string
+ 5465737420555249203000000000000000000000000000000000000000000000 // string
+
+ 000000000000000000000000000000000000000000000000000000000000000b // second token id? Why ==11? #e0
+ 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+ 000000000000000000000000000000000000000000000000000000000000000a // size of string
+ 5465737420555249203100000000000000000000000000000000000000000000 // string
+
+ 000000000000000000000000000000000000000000000000000000000000000c // third token id? Why ==12? #160
+ 0000000000000000000000000000000000000000000000000000000000000040 // offset of string
+ 000000000000000000000000000000000000000000000000000000000000000a // size of string
+ 5465737420555249203200000000000000000000000000000000000000000000 // string
+ "
+ )
+ );
+}
+
#[test]
fn dynamic_after_static() {
let mut encoder = AbiWriter::new();
@@ -235,63 +271,270 @@
similar_asserts::assert_eq!(encoded_data, ed.as_slice());
}
-test_impl!(
- vec_tuple_string_bytes,
- Vec<(string, bytes)>,
- 0xdeadbeef,
- vec![
- (
- "Test URI 0".to_string(),
- bytes(vec![
- 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
- 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
- 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
- 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
- ])
+#[test]
+fn encode_decode_vec_tuple_string_bytes() {
+ test_impl::<Vec<(string, bytes)>>(
+ 0xdeadbeef,
+ vec![
+ (
+ "Test URI 0".to_string(),
+ bytes(vec![
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ ]),
+ ),
+ (
+ "Test URI 1".to_string(),
+ bytes(vec![
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ ]),
+ ),
+ ("Test URI 2".to_string(), bytes(vec![0x33, 0x33])),
+ ],
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000003
+
+ 0000000000000000000000000000000000000000000000000000000000000060
+ 0000000000000000000000000000000000000000000000000000000000000140
+ 0000000000000000000000000000000000000000000000000000000000000220
+
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000080
+ 000000000000000000000000000000000000000000000000000000000000000a
+ 5465737420555249203000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000030
+ 1111111111111111111111111111111111111111111111111111111111111111
+ 1111111111111111111111111111111100000000000000000000000000000000
+
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000080
+ 000000000000000000000000000000000000000000000000000000000000000a
+ 5465737420555249203100000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000002f
+ 2222222222222222222222222222222222222222222222222222222222222222
+ 2222222222222222222222222222220000000000000000000000000000000000
+
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000080
+ 000000000000000000000000000000000000000000000000000000000000000a
+ 5465737420555249203200000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000002
+ 3333000000000000000000000000000000000000000000000000000000000000
+ "
+ ),
+ );
+}
+
+#[test]
+// #[ignore = "reason"]
+fn encode_decode_tuple0_tuple1_uint8_tuple1_string_bytes_tuple1_uint8_bytes() {
+ let int = 0xff;
+ let by = bytes(vec![0x11, 0x22, 0x33]);
+ let string = "some string".to_string();
+
+ test_impl::<((u8,), (String, bytes), (u8, bytes))>(
+ 0xdeadbeef,
+ ((int,), (string.clone(), by.clone()), (int, by)),
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 00000000000000000000000000000000000000000000000000000000000000ff
+ 0000000000000000000000000000000000000000000000000000000000000060
+ 0000000000000000000000000000000000000000000000000000000000000120
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000080
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 736f6d6520737472696e67000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000003
+ 1122330000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000000000000000000000000000000000000000000ff
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000003
+ 1122330000000000000000000000000000000000000000000000000000000000
+ "
+ ),
+ );
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_tuple1_uint8_uint8_tuple1_uint8_uint8() {
+ test_impl::<((u8,), (u8, u8), (u8, u8))>(
+ 0xdeadbeef,
+ ((43,), (44, 45), (46, 47)),
+ &hex!(
+ "
+ deadbeef
+ 000000000000000000000000000000000000000000000000000000000000002b
+ 000000000000000000000000000000000000000000000000000000000000002c
+ 000000000000000000000000000000000000000000000000000000000000002d
+ 000000000000000000000000000000000000000000000000000000000000002e
+ 000000000000000000000000000000000000000000000000000000000000002f
+ "
+ ),
+ );
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_tuple1_uint8() {
+ test_impl::<((u8,), (u8,))>(
+ 0xdeadbeef,
+ ((43,), (44,)),
+ &hex!(
+ "
+ deadbeef
+ 000000000000000000000000000000000000000000000000000000000000002b
+ 000000000000000000000000000000000000000000000000000000000000002c
+ "
+ ),
+ );
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_uint8() {
+ test_impl::<((u8, u8),)>(
+ 0xdeadbeef,
+ ((43, 44),),
+ &hex!(
+ "
+ deadbeef
+ 000000000000000000000000000000000000000000000000000000000000002b
+ 000000000000000000000000000000000000000000000000000000000000002c
+ "
+ ),
+ );
+}
+
+#[test]
+fn encode_decode_tuple_uint8_uint8() {
+ test_impl::<(u8, u8)>(
+ 0xdeadbeef,
+ (43, 44),
+ &hex!(
+ "
+ deadbeef
+ 000000000000000000000000000000000000000000000000000000000000002b
+ 000000000000000000000000000000000000000000000000000000000000002c
+ "
+ ),
+ );
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_uint8_tuple1_uint8_uint8_and_uint8() {
+ test_impl::<((u8, u8), (u8, u8), u8)>(
+ 0xdeadbeef,
+ ((10, 11), (12, 13), 14),
+ &hex!(
+ "
+ deadbeef
+ 000000000000000000000000000000000000000000000000000000000000000a
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 000000000000000000000000000000000000000000000000000000000000000c
+ 000000000000000000000000000000000000000000000000000000000000000d
+ 000000000000000000000000000000000000000000000000000000000000000e
+ "
),
- (
- "Test URI 1".to_string(),
- bytes(vec![
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
- 0x22, 0x22, 0x22, 0x22, 0x22
- ])
+ );
+}
+
+#[test]
+fn encode_decode_tuple0_tuple1_string() {
+ test_impl::<((String,),)>(
+ 0xdeadbeef,
+ (("some string".to_string(),),),
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 736f6d6520737472696e67000000000000000000000000000000000000000000
+ "
),
- ("Test URI 2".to_string(), bytes(vec![0x33, 0x33])),
- ],
- &hex!(
- "
- deadbeef
- 0000000000000000000000000000000000000000000000000000000000000020
- 0000000000000000000000000000000000000000000000000000000000000003
-
- 0000000000000000000000000000000000000000000000000000000000000060
- 0000000000000000000000000000000000000000000000000000000000000140
- 0000000000000000000000000000000000000000000000000000000000000220
+ );
+}
- 0000000000000000000000000000000000000000000000000000000000000040
- 0000000000000000000000000000000000000000000000000000000000000080
- 000000000000000000000000000000000000000000000000000000000000000a
- 5465737420555249203000000000000000000000000000000000000000000000
- 0000000000000000000000000000000000000000000000000000000000000030
- 1111111111111111111111111111111111111111111111111111111111111111
- 1111111111111111111111111111111100000000000000000000000000000000
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_string() {
+ test_impl::<((u8, String),)>(
+ 0xdeadbeef,
+ ((0xff, "some string".to_string()),),
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 00000000000000000000000000000000000000000000000000000000000000ff
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 736f6d6520737472696e67000000000000000000000000000000000000000000
+ "
+ ),
+ );
+}
- 0000000000000000000000000000000000000000000000000000000000000040
- 0000000000000000000000000000000000000000000000000000000000000080
- 000000000000000000000000000000000000000000000000000000000000000a
- 5465737420555249203100000000000000000000000000000000000000000000
- 000000000000000000000000000000000000000000000000000000000000002f
- 2222222222222222222222222222222222222222222222222222222222222222
- 2222222222222222222222222222220000000000000000000000000000000000
+#[test]
+fn encode_decode_tuple0_tuple1_string_bytes() {
+ test_impl::<((String, bytes),)>(
+ 0xdeadbeef,
+ (("some string".to_string(), bytes(vec![1, 2, 3])),),
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000080
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 736f6d6520737472696e67000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000003
+ 0102030000000000000000000000000000000000000000000000000000000000
+ "
+ ),
+ );
+}
- 0000000000000000000000000000000000000000000000000000000000000040
- 0000000000000000000000000000000000000000000000000000000000000080
+#[test]
+fn encode_decode_tuple0_tuple1_uint8_tuple1_string() {
+ test_impl::<((u8,), (String,))>(
+ 0xdeadbeef,
+ ((0xff,), ("some string".to_string(),)),
+ &hex!(
+ "
+ deadbeef
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 00000000000000000000000000000000000000000000000000000000000000ff
+ 0000000000000000000000000000000000000000000000000000000000000040
+ 0000000000000000000000000000000000000000000000000000000000000020
+ 000000000000000000000000000000000000000000000000000000000000000b
+ 736f6d6520737472696e67000000000000000000000000000000000000000000
+ "
+ ),
+ );
+}
+
+#[test]
+fn parse_multiple_params() {
+ let encoded_data = hex!(
+ "
+ deadbeef
000000000000000000000000000000000000000000000000000000000000000a
- 5465737420555249203200000000000000000000000000000000000000000000
- 0000000000000000000000000000000000000000000000000000000000000002
- 3333000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000000b
"
- )
-);
+ );
+ let (_, mut decoder) = AbiReader::new_call(&encoded_data).unwrap();
+ let p1 = <u8>::abi_read(&mut decoder).unwrap();
+ let p2 = <u8>::abi_read(&mut decoder).unwrap();
+ assert_eq!(p1, 0x0a);
+ assert_eq!(p2, 0x0b);
+}
crates/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);
}
}
crates/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)]
crates/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, ");")
- }
-}
crates/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
+ }
+}
crates/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, ");")
+ }
+}
crates/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;
+}
crates/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
+}
+"#
+ );
+ }
+}
crates/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);
+}
crates/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,
+ | ^
crates/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);
+}
crates/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();
+ | ^^^^^^^^^^^^^^^^
node/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',
+]
node/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;
}
node/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"
}
node/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(),
node/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" }
node/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(),
)?;
pallets/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]
pallets/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)
}
pallets/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
pallets/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 = [
pallets/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.
pallets/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())
+ }
+ }
+}
pallets/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.
pallets/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]
pallets/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" }
pallets/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
pallets/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,
pallets/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
pallets/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
pallets/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>;
}
pallets/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",
] }
pallets/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)]
pallets/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());
pallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/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 {}
pallets/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' }
pallets/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())
}
}
pallets/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| {
pallets/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.
pallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterbothbinary blob — no preview
pallets/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
pallets/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 = [
pallets/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>;
pallets/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 = [
pallets/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' }
pallets/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| {
pallets/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);
pallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterbothbinary blob — no preview
pallets/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
pallets/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"]
pallets/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' }
pallets/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`]
pallets/unique/src/eth/stubs/CollectionHelpers.rawdiffbeforeafterbothbinary blob — no preview
pallets/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;
+ }
}
pallets/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 {
primitives/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"]
primitives/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"
primitives/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`.
primitives/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"]
primitives/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> {
primitives/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"]
runtime/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>;
runtime/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;
runtime/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,
}
}
runtime/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())
}
runtime/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" }
runtime/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;
}
runtime/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" }
runtime/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' }
runtime/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 {
runtime/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" }
tests/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",
tests/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
+}
tests/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
tests/scripts/types_template/.gitignorediffbeforeafterboth--- /dev/null
+++ b/tests/scripts/types_template/.gitignore
@@ -0,0 +1,5 @@
+*.js
+*.map
+*.d.ts
+/node_modules
+metadata.json
tests/scripts/types_template/.npmignorediffbeforeafterboth--- /dev/null
+++ b/tests/scripts/types_template/.npmignore
@@ -0,0 +1 @@
+/src
tests/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';
+```
tests/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"
+ }
+}
tests/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"
+ ],
+}
tests/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
tests/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
tests/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;
+ });
});
tests/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" },
tests/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": [
{
tests/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"
},
tests/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"
},
tests/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}) => {
tests/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);
}
tests/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 {}
tests/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
tests/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
tests/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}) => {
tests/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}) => {
tests/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);
+ });
+
+});
tests/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
tests/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
tests/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
tests/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;
});
});
tests/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;
+ }));
});
tests/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);
tests/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;
tests/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);
tests/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);
tests/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())]);
}
tests/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[] }> {
tests/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);
+ });
+});
tests/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`.
tests/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>;
tests/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, []>;
/**
tests/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]>;
/**
tests/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>, []>;
tests/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;
tests/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;
tests/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'
};
tests/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;
tests/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
tests/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/);
tests/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);
+ });
+});
tests/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);
tests/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});
+ });
});
tests/src/util/playgrounds/unique.tsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034/* eslint-disable @typescript-eslint/no-var-requires */5/* eslint-disable function-call-argument-newline */6/* eslint-disable no-prototype-builtins */78import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';9import {ApiInterfaceEvents, SignerOptions} from '@polkadot/api/types';10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto';11import {IKeyringPair} from '@polkadot/types/types';12import {hexToU8a} from '@polkadot/util/hex';13import {u8aConcat} from '@polkadot/util/u8a';14import {15 IApiListeners,16 IBlock,17 IEvent,18 IChainProperties,19 ICollectionCreationOptions,20 ICollectionLimits,21 ICollectionPermissions,22 ICrossAccountId,23 ICrossAccountIdLower,24 ILogger,25 INestingPermissions,26 IProperty,27 IStakingInfo,28 ISchedulerOptions,29 ISubstrateBalance,30 IToken,31 ITokenPropertyPermission,32 ITransactionResult,33 IUniqueHelperLog,34 TApiAllowedListeners,35 TEthereumAccount,36 TSigner,37 TSubstrateAccount,38 TNetworks,39 IForeignAssetMetadata,40 AcalaAssetMetadata,41 MoonbeamAssetInfo,42 DemocracyStandardAccountVote,43 IEthCrossAccountId,44} from './types';45import {RuntimeDispatchInfo} from '@polkadot/types/interfaces';4647export class CrossAccountId implements ICrossAccountId {48 Substrate?: TSubstrateAccount;49 Ethereum?: TEthereumAccount;5051 constructor(account: ICrossAccountId) {52 if (account.Substrate) this.Substrate = account.Substrate;53 if (account.Ethereum) this.Ethereum = account.Ethereum;54 }5556 static fromKeyring(account: IKeyringPair, domain: 'Substrate' | 'Ethereum' = 'Substrate') {57 switch (domain) {58 case 'Substrate': return new CrossAccountId({Substrate: account.address});59 case 'Ethereum': return new CrossAccountId({Substrate: account.address}).toEthereum();60 }61 }6263 static fromLowerCaseKeys(address: ICrossAccountIdLower): CrossAccountId {64 return new CrossAccountId({Substrate: address.substrate, Ethereum: address.ethereum});65 }6667 static normalizeSubstrateAddress(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {68 return encodeAddress(decodeAddress(address), ss58Format);69 }7071 static withNormalizedSubstrate(address: TSubstrateAccount, ss58Format = 42): CrossAccountId {72 return new CrossAccountId({Substrate: CrossAccountId.normalizeSubstrateAddress(address, ss58Format)});73 }7475 withNormalizedSubstrate(ss58Format = 42): CrossAccountId {76 if (this.Substrate) return CrossAccountId.withNormalizedSubstrate(this.Substrate, ss58Format);77 return this;78 }7980 static translateSubToEth(address: TSubstrateAccount): TEthereumAccount {81 return nesting.toChecksumAddress('0x' + Array.from(addressToEvm(address), i => i.toString(16).padStart(2, '0')).join(''));82 }8384 toEthereum(): CrossAccountId {85 if (this.Substrate) return new CrossAccountId({Ethereum: CrossAccountId.translateSubToEth(this.Substrate)});86 return this;87 }8889 static translateEthToSub(address: TEthereumAccount, ss58Format?: number): TSubstrateAccount {90 return evmToAddress(address, ss58Format);91 }9293 toSubstrate(ss58Format?: number): CrossAccountId {94 if (this.Ethereum) return new CrossAccountId({Substrate: CrossAccountId.translateEthToSub(this.Ethereum, ss58Format)});95 return this;96 }9798 toLowerCase(): CrossAccountId {99 if (this.Substrate) this.Substrate = this.Substrate.toLowerCase();100 if (this.Ethereum) this.Ethereum = this.Ethereum.toLowerCase();101 return this;102 }103}104105const nesting = {106 toChecksumAddress(address: string): string {107 if (typeof address === 'undefined') return '';108109 if(!/^(0x)?[0-9a-f]{40}$/i.test(address)) throw new Error(`Given address "${address}" is not a valid Ethereum address.`);110111 address = address.toLowerCase().replace(/^0x/i,'');112 const addressHash = keccakAsHex(address).replace(/^0x/i,'');113 const checksumAddress = ['0x'];114115 for (let i = 0; i < address.length; i++) {116 // If ith character is 8 to f then make it uppercase117 if (parseInt(addressHash[i], 16) > 7) {118 checksumAddress.push(address[i].toUpperCase());119 } else {120 checksumAddress.push(address[i]);121 }122 }123 return checksumAddress.join('');124 },125 tokenIdToAddress(collectionId: number, tokenId: number) {126 return this.toChecksumAddress(`0xf8238ccfff8ed887463fd5e0${collectionId.toString(16).padStart(8,'0')}${tokenId.toString(16).padStart(8,'0')}`);127 },128};129130class UniqueUtil {131 static transactionStatus = {132 NOT_READY: 'NotReady',133 FAIL: 'Fail',134 SUCCESS: 'Success',135 };136137 static chainLogType = {138 EXTRINSIC: 'extrinsic',139 RPC: 'rpc',140 };141142 static getTokenAccount(token: IToken): CrossAccountId {143 return new CrossAccountId({Ethereum: this.getTokenAddress(token)});144 }145146 static getTokenAddress(token: IToken): string {147 return nesting.tokenIdToAddress(token.collectionId, token.tokenId);148 }149150 static getDefaultLogger(): ILogger {151 return {152 log(msg: any, level = 'INFO') {153 console[level.toLocaleLowerCase() === 'error' ? 'error' : 'log'](...(Array.isArray(msg) ? msg : [msg]));154 },155 level: {156 ERROR: 'ERROR',157 WARNING: 'WARNING',158 INFO: 'INFO',159 },160 };161 }162163 static vec2str(arr: string[] | number[]) {164 return arr.map(x => String.fromCharCode(parseInt(x.toString()))).join('');165 }166167 static str2vec(string: string) {168 if (typeof string !== 'string') return string;169 return Array.from(string).map(x => x.charCodeAt(0));170 }171172 static fromSeed(seed: string, ss58Format = 42) {173 const keyring = new Keyring({type: 'sr25519', ss58Format});174 return keyring.addFromUri(seed);175 }176177 static extractCollectionIdFromCreationResult(creationResult: ITransactionResult): number {178 if (creationResult.status !== this.transactionStatus.SUCCESS) {179 throw Error('Unable to create collection!');180 }181182 let collectionId = null;183 creationResult.result.events.forEach(({event: {data, method, section}}) => {184 if ((section === 'common') && (method === 'CollectionCreated')) {185 collectionId = parseInt(data[0].toString(), 10);186 }187 });188189 if (collectionId === null) {190 throw Error('No CollectionCreated event was found!');191 }192193 return collectionId;194 }195196 static extractTokensFromCreationResult(creationResult: ITransactionResult): {197 success: boolean,198 tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[],199 } {200 if (creationResult.status !== this.transactionStatus.SUCCESS) {201 throw Error('Unable to create tokens!');202 }203 let success = false;204 const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[];205 creationResult.result.events.forEach(({event: {data, method, section}}) => {206 if (method === 'ExtrinsicSuccess') {207 success = true;208 } else if ((section === 'common') && (method === 'ItemCreated')) {209 tokens.push({210 collectionId: parseInt(data[0].toString(), 10),211 tokenId: parseInt(data[1].toString(), 10),212 owner: data[2].toHuman(),213 amount: data[3].toBigInt(),214 });215 }216 });217 return {success, tokens};218 }219220 static extractTokensFromBurnResult(burnResult: ITransactionResult): {221 success: boolean,222 tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[],223 } {224 if (burnResult.status !== this.transactionStatus.SUCCESS) {225 throw Error('Unable to burn tokens!');226 }227 let success = false;228 const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[];229 burnResult.result.events.forEach(({event: {data, method, section}}) => {230 if (method === 'ExtrinsicSuccess') {231 success = true;232 } else if ((section === 'common') && (method === 'ItemDestroyed')) {233 tokens.push({234 collectionId: parseInt(data[0].toString(), 10),235 tokenId: parseInt(data[1].toString(), 10),236 owner: data[2].toHuman(),237 amount: data[3].toBigInt(),238 });239 }240 });241 return {success, tokens};242 }243244 static findCollectionInEvents(events: {event: IEvent}[], collectionId: number, expectedSection: string, expectedMethod: string): boolean {245 let eventId = null;246 events.forEach(({event: {data, method, section}}) => {247 if ((section === expectedSection) && (method === expectedMethod)) {248 eventId = parseInt(data[0].toString(), 10);249 }250 });251252 if (eventId === null) {253 throw Error(`No ${expectedMethod} event was found!`);254 }255 return eventId === collectionId;256 }257258 static isTokenTransferSuccess(events: {event: IEvent}[], collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {259 const normalizeAddress = (address: string | ICrossAccountId) => {260 if(typeof address === 'string') return address;261 const obj = {} as any;262 Object.keys(address).forEach(k => {263 obj[k.toLocaleLowerCase()] = address[k as 'Substrate' | 'Ethereum'];264 });265 if(obj.substrate) return CrossAccountId.withNormalizedSubstrate(obj.substrate);266 if(obj.ethereum) return CrossAccountId.fromLowerCaseKeys(obj).toLowerCase();267 return address;268 };269 let transfer = {collectionId: null, tokenId: null, from: null, to: null, amount: 1} as any;270 events.forEach(({event: {data, method, section}}) => {271 if ((section === 'common') && (method === 'Transfer')) {272 const hData = (data as any).toJSON();273 transfer = {274 collectionId: hData[0],275 tokenId: hData[1],276 from: normalizeAddress(hData[2]),277 to: normalizeAddress(hData[3]),278 amount: BigInt(hData[4]),279 };280 }281 });282 let isSuccess = parseInt(collectionId.toString()) === transfer.collectionId && parseInt(tokenId.toString()) === transfer.tokenId;283 isSuccess = isSuccess && JSON.stringify(normalizeAddress(fromAddressObj)) === JSON.stringify(transfer.from);284 isSuccess = isSuccess && JSON.stringify(normalizeAddress(toAddressObj)) === JSON.stringify(transfer.to);285 isSuccess = isSuccess && amount === transfer.amount;286 return isSuccess;287 }288289 static bigIntToDecimals(number: bigint, decimals = 18) {290 const numberStr = number.toString();291 const dotPos = numberStr.length - decimals;292293 if (dotPos <= 0) {294 return '0.' + '0'.repeat(Math.abs(dotPos)) + numberStr;295 } else {296 const intPart = numberStr.substring(0, dotPos);297 const fractPart = numberStr.substring(dotPos);298 return intPart + '.' + fractPart;299 }300 }301}302303class UniqueEventHelper {304 private static extractIndex(index: any): [number, number] | string {305 if(index.toRawType() === '[u8;2]') return [index[0], index[1]];306 return index.toJSON();307 }308309 private static extractSub(data: any, subTypes: any): {[key: string]: any} {310 let obj: any = {};311 let index = 0;312313 if (data.entries) {314 for(const [key, value] of data.entries()) {315 obj[key] = this.extractData(value, subTypes[index]);316 index++;317 }318 } else obj = data.toJSON();319320 return obj;321 }322323 private static extractData(data: any, type: any): any {324 if(!type) return data.toHuman();325 if (['u16', 'u32'].indexOf(type.type) > -1) return data.toNumber();326 if (['u64', 'u128', 'u256'].indexOf(type.type) > -1) return data.toBigInt();327 if(type.hasOwnProperty('sub')) return this.extractSub(data, type.sub);328 return data.toHuman();329 }330331 public static extractEvents(events: {event: any, phase: any}[]): IEvent[] {332 const parsedEvents: IEvent[] = [];333334 events.forEach((record) => {335 const {event, phase} = record;336 const types = event.typeDef;337338 const eventData: IEvent = {339 section: event.section.toString(),340 method: event.method.toString(),341 index: this.extractIndex(event.index),342 data: [],343 phase: phase.toJSON(),344 };345346 event.data.forEach((val: any, index: number) => {347 eventData.data.push(this.extractData(val, types[index]));348 });349350 parsedEvents.push(eventData);351 });352353 return parsedEvents;354 }355}356357export class ChainHelperBase {358 helperBase: any;359360 transactionStatus = UniqueUtil.transactionStatus;361 chainLogType = UniqueUtil.chainLogType;362 util: typeof UniqueUtil;363 eventHelper: typeof UniqueEventHelper;364 logger: ILogger;365 api: ApiPromise | null;366 forcedNetwork: TNetworks | null;367 network: TNetworks | null;368 chainLog: IUniqueHelperLog[];369 children: ChainHelperBase[];370 address: AddressGroup;371 chain: ChainGroup;372373 constructor(logger?: ILogger, helperBase?: any) {374 this.helperBase = helperBase;375376 this.util = UniqueUtil;377 this.eventHelper = UniqueEventHelper;378 if (typeof logger == 'undefined') logger = this.util.getDefaultLogger();379 this.logger = logger;380 this.api = null;381 this.forcedNetwork = null;382 this.network = null;383 this.chainLog = [];384 this.children = [];385 this.address = new AddressGroup(this);386 this.chain = new ChainGroup(this);387 }388389 clone(helperCls: ChainHelperBaseConstructor, options: {[key: string]: any} = {}) {390 Object.setPrototypeOf(helperCls.prototype, this);391 const newHelper = new helperCls(this.logger, options);392393 newHelper.api = this.api;394 newHelper.network = this.network;395 newHelper.forceNetwork = this.forceNetwork;396397 this.children.push(newHelper);398399 return newHelper;400 }401402 getApi(): ApiPromise {403 if(this.api === null) throw Error('API not initialized');404 return this.api;405 }406407 clearChainLog(): void {408 this.chainLog = [];409 }410411 forceNetwork(value: TNetworks): void {412 this.forcedNetwork = value;413 }414415 async connect(wsEndpoint: string, listeners?: IApiListeners) {416 if (this.api !== null) throw Error('Already connected');417 const {api, network} = await ChainHelperBase.createConnection(wsEndpoint, listeners, this.forcedNetwork);418 this.api = api;419 this.network = network;420 }421422 async disconnect() {423 for (const child of this.children) {424 child.clearApi();425 }426427 if (this.api === null) return;428 await this.api.disconnect();429 this.clearApi();430 }431432 clearApi() {433 this.api = null;434 this.network = null;435 }436437 static async detectNetwork(api: ApiPromise): Promise<TNetworks> {438 const spec = (await api.query.system.lastRuntimeUpgrade()).toJSON() as any;439 const xcmChains = ['rococo', 'westend', 'westmint', 'acala', 'karura', 'moonbeam', 'moonriver'];440441 if(xcmChains.indexOf(spec.specName) > -1) return spec.specName;442443 if(['quartz', 'unique'].indexOf(spec.specName) > -1) return spec.specName;444 return 'opal';445 }446447 static async detectNetworkByWsEndpoint(wsEndpoint: string): Promise<TNetworks> {448 const api = new ApiPromise({provider: new WsProvider(wsEndpoint)});449 await api.isReady;450451 const network = await this.detectNetwork(api);452453 await api.disconnect();454455 return network;456 }457458 static async createConnection(wsEndpoint: string, listeners?: IApiListeners, network?: TNetworks | null): Promise<{459 api: ApiPromise;460 network: TNetworks;461 }> {462 if(typeof network === 'undefined' || network === null) network = 'opal';463 const supportedRPC = {464 opal: {465 unique: require('@unique-nft/opal-testnet-types/definitions').unique.rpc,466 },467 quartz: {468 unique: require('@unique-nft/quartz-mainnet-types/definitions').unique.rpc,469 },470 unique: {471 unique: require('@unique-nft/unique-mainnet-types/definitions').unique.rpc,472 },473 rococo: {},474 westend: {},475 moonbeam: {},476 moonriver: {},477 acala: {},478 karura: {},479 westmint: {},480 };481 if(!supportedRPC.hasOwnProperty(network)) network = await this.detectNetworkByWsEndpoint(wsEndpoint);482 const rpc = supportedRPC[network];483484 // TODO: investigate how to replace rpc in runtime485 // api._rpcCore.addUserInterfaces(rpc);486487 const api = new ApiPromise({provider: new WsProvider(wsEndpoint), rpc});488489 await api.isReadyOrError;490491 if (typeof listeners === 'undefined') listeners = {};492 for (const event of ['connected', 'disconnected', 'error', 'ready', 'decorated']) {493 if (!listeners.hasOwnProperty(event) || typeof listeners[event as TApiAllowedListeners] === 'undefined') continue;494 api.on(event as ApiInterfaceEvents, listeners[event as TApiAllowedListeners] as (...args: any[]) => any);495 }496497 return {api, network};498 }499500 getTransactionStatus(data: {events: {event: IEvent}[], status: any}) {501 const {events, status} = data;502 if (status.isReady) {503 return this.transactionStatus.NOT_READY;504 }505 if (status.isBroadcast) {506 return this.transactionStatus.NOT_READY;507 }508 if (status.isInBlock || status.isFinalized) {509 const errors = events.filter(e => e.event.method === 'ExtrinsicFailed');510 if (errors.length > 0) {511 return this.transactionStatus.FAIL;512 }513 if (events.filter(e => e.event.method === 'ExtrinsicSuccess').length > 0) {514 return this.transactionStatus.SUCCESS;515 }516 }517518 return this.transactionStatus.FAIL;519 }520521 signTransaction(sender: TSigner, transaction: any, options: Partial<SignerOptions> | null = null, label = 'transaction') {522 const sign = (callback: any) => {523 if(options !== null) return transaction.signAndSend(sender, options, callback);524 return transaction.signAndSend(sender, callback);525 };526 // eslint-disable-next-line no-async-promise-executor527 return new Promise(async (resolve, reject) => {528 try {529 const unsub = await sign((result: any) => {530 const status = this.getTransactionStatus(result);531532 if (status === this.transactionStatus.SUCCESS) {533 this.logger.log(`${label} successful`);534 unsub();535 resolve({result, status});536 } else if (status === this.transactionStatus.FAIL) {537 let moduleError = null;538539 if (result.hasOwnProperty('dispatchError')) {540 const dispatchError = result['dispatchError'];541542 if (dispatchError) {543 if (dispatchError.isModule) {544 const modErr = dispatchError.asModule;545 const errorMeta = dispatchError.registry.findMetaError(modErr);546547 moduleError = `${errorMeta.section}.${errorMeta.name}`;548 } else {549 moduleError = dispatchError.toHuman();550 }551 } else {552 this.logger.log(result, this.logger.level.ERROR);553 }554 }555556 this.logger.log(`Something went wrong with ${label}. Status: ${status}`, this.logger.level.ERROR);557 unsub();558 reject({status, moduleError, result});559 }560 });561 } catch (e) {562 this.logger.log(e, this.logger.level.ERROR);563 reject(e);564 }565 });566 }567568 async getPaymentInfo(signer: TSigner, tx: any, len: number | null) {569 const api = this.getApi();570 const signingInfo = await api.derive.tx.signingInfo(signer.address);571572 // We need to sign the tx because573 // unsigned transactions does not have an inclusion fee574 tx.sign(signer, {575 blockHash: api.genesisHash,576 genesisHash: api.genesisHash,577 runtimeVersion: api.runtimeVersion,578 nonce: signingInfo.nonce,579 });580581 if (len === null) {582 return (await this.callRpc('api.rpc.payment.queryInfo', [tx.toHex()])) as RuntimeDispatchInfo;583 } else {584 return (await api.call.transactionPaymentApi.queryInfo(tx, len)) as RuntimeDispatchInfo;585 }586 }587588 constructApiCall(apiCall: string, params: any[]) {589 if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);590 let call = this.getApi() as any;591 for(const part of apiCall.slice(4).split('.')) {592 call = call[part];593 }594 return call(...params);595 }596597 async executeExtrinsic(sender: TSigner, extrinsic: string, params: any[], expectSuccess=true, options: Partial<SignerOptions>|null = null/*, failureMessage='expected success'*/) {598 if(this.api === null) throw Error('API not initialized');599 if(!extrinsic.startsWith('api.tx.')) throw Error(`${extrinsic} is not transaction`);600601 const startTime = (new Date()).getTime();602 let result: ITransactionResult;603 let events: IEvent[] = [];604 try {605 result = await this.signTransaction(sender, this.constructApiCall(extrinsic, params), options, extrinsic) as ITransactionResult;606 events = this.eventHelper.extractEvents(result.result.events);607 }608 catch(e) {609 if(!(e as object).hasOwnProperty('status')) throw e;610 result = e as ITransactionResult;611 }612613 const endTime = (new Date()).getTime();614615 const log = {616 executedAt: endTime,617 executionTime: endTime - startTime,618 type: this.chainLogType.EXTRINSIC,619 status: result.status,620 call: extrinsic,621 signer: this.getSignerAddress(sender),622 params,623 } as IUniqueHelperLog;624625 if(result.status !== this.transactionStatus.SUCCESS) {626 if (result.moduleError) log.moduleError = result.moduleError;627 else if (result.result.dispatchError) log.dispatchError = result.result.dispatchError;628 }629 if(events.length > 0) log.events = events;630631 this.chainLog.push(log);632633 if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) {634 if (result.moduleError) throw Error(`${result.moduleError}`);635 else if (result.result.dispatchError) throw Error(JSON.stringify(result.result.dispatchError));636 }637 return result;638 }639640 async callRpc(rpc: string, params?: any[]) {641 if(typeof params === 'undefined') params = [];642 if(this.api === null) throw Error('API not initialized');643 if(!rpc.startsWith('api.rpc.') && !rpc.startsWith('api.query.')) throw Error(`${rpc} is not RPC call`);644645 const startTime = (new Date()).getTime();646 let result;647 let error = null;648 const log = {649 type: this.chainLogType.RPC,650 call: rpc,651 params,652 } as IUniqueHelperLog;653654 try {655 result = await this.constructApiCall(rpc, params);656 }657 catch(e) {658 error = e;659 }660661 const endTime = (new Date()).getTime();662663 log.executedAt = endTime;664 log.status = (error === null ? this.transactionStatus.SUCCESS : this.transactionStatus.FAIL) as 'Fail' | 'Success';665 log.executionTime = endTime - startTime;666667 this.chainLog.push(log);668669 if(error !== null) throw error;670671 return result;672 }673674 getSignerAddress(signer: IKeyringPair | string): string {675 if(typeof signer === 'string') return signer;676 return signer.address;677 }678679 fetchAllPalletNames(): string[] {680 if(this.api === null) throw Error('API not initialized');681 return this.api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());682 }683684 fetchMissingPalletNames(requiredPallets: string[]): string[] {685 const palletNames = this.fetchAllPalletNames();686 return requiredPallets.filter(p => !palletNames.includes(p));687 }688}689690691class HelperGroup<T extends ChainHelperBase> {692 helper: T;693694 constructor(uniqueHelper: T) {695 this.helper = uniqueHelper;696 }697}698699700class CollectionGroup extends HelperGroup<UniqueHelper> {701 /**702 * Get number of blocks when sponsored transaction is available.703 *704 * @param collectionId ID of collection705 * @param tokenId ID of token706 * @param addressObj address for which the sponsorship is checked707 * @example await getTokenNextSponsored(1, 2, {Substrate: '5DfhbVfww7ThF8q6f3...'});708 * @returns number of blocks or null if sponsorship hasn't been set709 */710 async getTokenNextSponsored(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<number | null> {711 return (await this.helper.callRpc('api.rpc.unique.nextSponsored', [collectionId, addressObj, tokenId])).toJSON();712 }713714 /**715 * Get the number of created collections.716 *717 * @returns number of created collections718 */719 async getTotalCount(): Promise<number> {720 return (await this.helper.callRpc('api.rpc.unique.collectionStats')).created.toNumber();721 }722723 /**724 * Get information about the collection with additional data,725 * including the number of tokens it contains, its administrators,726 * the normalized address of the collection's owner, and decoded name and description.727 *728 * @param collectionId ID of collection729 * @example await getData(2)730 * @returns collection information object731 */732 async getData(collectionId: number): Promise<{733 id: number;734 name: string;735 description: string;736 tokensCount: number;737 admins: CrossAccountId[];738 normalizedOwner: TSubstrateAccount;739 raw: any740 } | null> {741 const collection = await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId]);742 const humanCollection = collection.toHuman(), collectionData = {743 id: collectionId, name: null, description: null, tokensCount: 0, admins: [],744 raw: humanCollection,745 } as any, jsonCollection = collection.toJSON();746 if (humanCollection === null) return null;747 collectionData.raw.limits = jsonCollection.limits;748 collectionData.raw.permissions = jsonCollection.permissions;749 collectionData.normalizedOwner = this.helper.address.normalizeSubstrate(collectionData.raw.owner);750 for (const key of ['name', 'description']) {751 collectionData[key] = this.helper.util.vec2str(humanCollection[key]);752 }753754 collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode))755 ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId)756 : 0;757 collectionData.admins = await this.getAdmins(collectionId);758759 return collectionData;760 }761762 /**763 * Get the addresses of the collection's administrators, optionally normalized.764 *765 * @param collectionId ID of collection766 * @param normalize whether to normalize the addresses to the default ss58 format767 * @example await getAdmins(1)768 * @returns array of administrators769 */770 async getAdmins(collectionId: number, normalize = false): Promise<CrossAccountId[]> {771 const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman();772773 return normalize774 ? admins.map((address: CrossAccountId) => address.withNormalizedSubstrate())775 : admins;776 }777778 /**779 * Get the addresses added to the collection allow-list, optionally normalized.780 * @param collectionId ID of collection781 * @param normalize whether to normalize the addresses to the default ss58 format782 * @example await getAllowList(1)783 * @returns array of allow-listed addresses784 */785 async getAllowList(collectionId: number, normalize = false): Promise<CrossAccountId[]> {786 const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman();787 return normalize788 ? allowListed.map((address: CrossAccountId) => address.withNormalizedSubstrate())789 : allowListed;790 }791792 /**793 * Get the effective limits of the collection instead of null for default values794 *795 * @param collectionId ID of collection796 * @example await getEffectiveLimits(2)797 * @returns object of collection limits798 */799 async getEffectiveLimits(collectionId: number): Promise<ICollectionLimits> {800 return (await this.helper.callRpc('api.rpc.unique.effectiveCollectionLimits', [collectionId])).toJSON();801 }802803 /**804 * Burns the collection if the signer has sufficient permissions and collection is empty.805 *806 * @param signer keyring of signer807 * @param collectionId ID of collection808 * @example await helper.collection.burn(aliceKeyring, 3);809 * @returns ```true``` if extrinsic success, otherwise ```false```810 */811 async burn(signer: TSigner, collectionId: number): Promise<boolean> {812 const result = await this.helper.executeExtrinsic(813 signer,814 'api.tx.unique.destroyCollection', [collectionId],815 true,816 );817818 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed');819 }820821 /**822 * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.823 *824 * @param signer keyring of signer825 * @param collectionId ID of collection826 * @param sponsorAddress Sponsor substrate address827 * @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")828 * @returns ```true``` if extrinsic success, otherwise ```false```829 */830 async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise<boolean> {831 const result = await this.helper.executeExtrinsic(832 signer,833 'api.tx.unique.setCollectionSponsor', [collectionId, sponsorAddress],834 true,835 );836837 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorSet');838 }839840 /**841 * Confirms consent to sponsor the collection on behalf of the signer.842 *843 * @param signer keyring of signer844 * @param collectionId ID of collection845 * @example confirmSponsorship(aliceKeyring, 10)846 * @returns ```true``` if extrinsic success, otherwise ```false```847 */848 async confirmSponsorship(signer: TSigner, collectionId: number): Promise<boolean> {849 const result = await this.helper.executeExtrinsic(850 signer,851 'api.tx.unique.confirmSponsorship', [collectionId],852 true,853 );854855 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'SponsorshipConfirmed');856 }857858 /**859 * Removes the sponsor of a collection, regardless if it consented or not.860 *861 * @param signer keyring of signer862 * @param collectionId ID of collection863 * @example removeSponsor(aliceKeyring, 10)864 * @returns ```true``` if extrinsic success, otherwise ```false```865 */866 async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {867 const result = await this.helper.executeExtrinsic(868 signer,869 'api.tx.unique.removeCollectionSponsor', [collectionId],870 true,871 );872873 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorRemoved');874 }875876 /**877 * Sets the limits of the collection. At least one limit must be specified for a correct call.878 *879 * @param signer keyring of signer880 * @param collectionId ID of collection881 * @param limits collection limits object882 * @example883 * await setLimits(884 * aliceKeyring,885 * 10,886 * {887 * sponsorTransferTimeout: 0,888 * ownerCanDestroy: false889 * }890 * )891 * @returns ```true``` if extrinsic success, otherwise ```false```892 */893 async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise<boolean> {894 const result = await this.helper.executeExtrinsic(895 signer,896 'api.tx.unique.setCollectionLimits', [collectionId, limits],897 true,898 );899900 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionLimitSet');901 }902903 /**904 * Changes the owner of the collection to the new Substrate address.905 *906 * @param signer keyring of signer907 * @param collectionId ID of collection908 * @param ownerAddress substrate address of new owner909 * @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")910 * @returns ```true``` if extrinsic success, otherwise ```false```911 */912 async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise<boolean> {913 const result = await this.helper.executeExtrinsic(914 signer,915 'api.tx.unique.changeCollectionOwner', [collectionId, ownerAddress],916 true,917 );918919 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionOwnedChanged');920 }921922 /**923 * Adds a collection administrator.924 *925 * @param signer keyring of signer926 * @param collectionId ID of collection927 * @param adminAddressObj Administrator address (substrate or ethereum)928 * @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})929 * @returns ```true``` if extrinsic success, otherwise ```false```930 */931 async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {932 const result = await this.helper.executeExtrinsic(933 signer,934 'api.tx.unique.addCollectionAdmin', [collectionId, adminAddressObj],935 true,936 );937938 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminAdded');939 }940941 /**942 * Removes a collection administrator.943 *944 * @param signer keyring of signer945 * @param collectionId ID of collection946 * @param adminAddressObj Administrator address (substrate or ethereum)947 * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})948 * @returns ```true``` if extrinsic success, otherwise ```false```949 */950 async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {951 const result = await this.helper.executeExtrinsic(952 signer,953 'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj],954 true,955 );956957 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminRemoved');958 }959960 /**961 * Check if user is in allow list.962 *963 * @param collectionId ID of collection964 * @param user Account to check965 * @example await getAdmins(1)966 * @returns is user in allow list967 */968 async allowed(collectionId: number, user: ICrossAccountId): Promise<boolean> {969 return (await this.helper.callRpc('api.rpc.unique.allowed', [collectionId, user])).toJSON();970 }971972 /**973 * Adds an address to allow list974 * @param signer keyring of signer975 * @param collectionId ID of collection976 * @param addressObj address to add to the allow list977 * @returns ```true``` if extrinsic success, otherwise ```false```978 */979 async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {980 const result = await this.helper.executeExtrinsic(981 signer,982 'api.tx.unique.addToAllowList', [collectionId, addressObj],983 true,984 );985986 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressAdded');987 }988989 /**990 * Removes an address from allow list991 *992 * @param signer keyring of signer993 * @param collectionId ID of collection994 * @param addressObj address to remove from the allow list995 * @returns ```true``` if extrinsic success, otherwise ```false```996 */997 async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {998 const result = await this.helper.executeExtrinsic(999 signer,1000 'api.tx.unique.removeFromAllowList', [collectionId, addressObj],1001 true,1002 );10031004 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressRemoved');1005 }10061007 /**1008 * Sets onchain permissions for selected collection.1009 *1010 * @param signer keyring of signer1011 * @param collectionId ID of collection1012 * @param permissions collection permissions object1013 * @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}});1014 * @returns ```true``` if extrinsic success, otherwise ```false```1015 */1016 async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise<boolean> {1017 const result = await this.helper.executeExtrinsic(1018 signer,1019 'api.tx.unique.setCollectionPermissions', [collectionId, permissions],1020 true,1021 );10221023 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionPermissionSet');1024 }10251026 /**1027 * Enables nesting for selected collection. If `restricted` set, you can nest only tokens from specified collections.1028 *1029 * @param signer keyring of signer1030 * @param collectionId ID of collection1031 * @param permissions nesting permissions object1032 * @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true});1033 * @returns ```true``` if extrinsic success, otherwise ```false```1034 */1035 async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise<boolean> {1036 return await this.setPermissions(signer, collectionId, {nesting: permissions});1037 }10381039 /**1040 * Disables nesting for selected collection.1041 *1042 * @param signer keyring of signer1043 * @param collectionId ID of collection1044 * @example disableNesting(aliceKeyring, 10);1045 * @returns ```true``` if extrinsic success, otherwise ```false```1046 */1047 async disableNesting(signer: TSigner, collectionId: number): Promise<boolean> {1048 return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}});1049 }10501051 /**1052 * Sets onchain properties to the collection.1053 *1054 * @param signer keyring of signer1055 * @param collectionId ID of collection1056 * @param properties array of property objects1057 * @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]);1058 * @returns ```true``` if extrinsic success, otherwise ```false```1059 */1060 async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise<boolean> {1061 const result = await this.helper.executeExtrinsic(1062 signer,1063 'api.tx.unique.setCollectionProperties', [collectionId, properties],1064 true,1065 );10661067 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');1068 }10691070 /**1071 * Get collection properties.1072 *1073 * @param collectionId ID of collection1074 * @param propertyKeys optionally filter the returned properties to only these keys1075 * @example getProperties(1219, ['location', 'date', 'time', 'isParadise']);1076 * @returns array of key-value pairs1077 */1078 async getProperties(collectionId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1079 return (await this.helper.callRpc('api.rpc.unique.collectionProperties', [collectionId, propertyKeys])).toHuman();1080 }10811082 async getCollectionOptions(collectionId: number) {1083 return (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1084 }10851086 /**1087 * Deletes onchain properties from the collection.1088 *1089 * @param signer keyring of signer1090 * @param collectionId ID of collection1091 * @param propertyKeys array of property keys to delete1092 * @example deleteProperties(aliceKeyring, 10, ["gender", "age"]);1093 * @returns ```true``` if extrinsic success, otherwise ```false```1094 */1095 async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise<boolean> {1096 const result = await this.helper.executeExtrinsic(1097 signer,1098 'api.tx.unique.deleteCollectionProperties', [collectionId, propertyKeys],1099 true,1100 );11011102 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted');1103 }11041105 /**1106 * Changes the owner of the token.1107 *1108 * @param signer keyring of signer1109 * @param collectionId ID of collection1110 * @param tokenId ID of token1111 * @param addressObj address of a new owner1112 * @param amount amount of tokens to be transfered. For NFT must be set to 1n1113 * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1114 * @returns true if the token success, otherwise false1115 */1116 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {1117 const result = await this.helper.executeExtrinsic(1118 signer,1119 'api.tx.unique.transfer', [addressObj, collectionId, tokenId, amount],1120 true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1121 );11221123 return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount);1124 }11251126 /**1127 *1128 * Change ownership of a token(s) on behalf of the owner.1129 *1130 * @param signer keyring of signer1131 * @param collectionId ID of collection1132 * @param tokenId ID of token1133 * @param fromAddressObj address on behalf of which the token will be sent1134 * @param toAddressObj new token owner1135 * @param amount amount of tokens to be transfered. For NFT must be set to 1n1136 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg"}, {Ethereum: "0x9F0583DbB85..."})1137 * @returns true if the token success, otherwise false1138 */1139 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1140 const result = await this.helper.executeExtrinsic(1141 signer,1142 'api.tx.unique.transferFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],1143 true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1144 );1145 return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1146 }11471148 /**1149 *1150 * Destroys a concrete instance of NFT/RFT or burns a specified amount of fungible tokens.1151 *1152 * @param signer keyring of signer1153 * @param collectionId ID of collection1154 * @param tokenId ID of token1155 * @param amount amount of tokens to be burned. For NFT must be set to 1n1156 * @example burnToken(aliceKeyring, 10, 5);1157 * @returns ```true``` if the extrinsic is successful, otherwise ```false```1158 */1159 async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount=1n): Promise<boolean> {1160 const burnResult = await this.helper.executeExtrinsic(1161 signer,1162 'api.tx.unique.burnItem', [collectionId, tokenId, amount],1163 true, // `Unable to burn token for ${label}`,1164 );1165 const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1166 if (burnedTokens.tokens.length > 1) throw Error('Burned multiple tokens');1167 return burnedTokens.success;1168 }11691170 /**1171 * Destroys a concrete instance of NFT on behalf of the owner1172 *1173 * @param signer keyring of signer1174 * @param collectionId ID of collection1175 * @param tokenId ID of token1176 * @param fromAddressObj address on behalf of which the token will be burnt1177 * @param amount amount of tokens to be burned. For NFT must be set to 1n1178 * @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."})1179 * @returns ```true``` if extrinsic success, otherwise ```false```1180 */1181 async burnTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1182 const burnResult = await this.helper.executeExtrinsic(1183 signer,1184 'api.tx.unique.burnFrom', [collectionId, fromAddressObj, tokenId, amount],1185 true, // `Unable to burn token from for ${label}`,1186 );1187 const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1188 return burnedTokens.success && burnedTokens.tokens.length > 0;1189 }11901191 /**1192 * Set, change, or remove approved address to transfer the ownership of the NFT.1193 *1194 * @param signer keyring of signer1195 * @param collectionId ID of collection1196 * @param tokenId ID of token1197 * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens1198 * @param amount amount of token to be approved. For NFT must be set to 1n1199 * @returns ```true``` if extrinsic success, otherwise ```false```1200 */1201 async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {1202 const approveResult = await this.helper.executeExtrinsic(1203 signer,1204 'api.tx.unique.approve', [toAddressObj, collectionId, tokenId, amount],1205 true, // `Unable to approve token for ${label}`,1206 );12071208 return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');1209 }12101211 /**1212 * Get the amount of token pieces approved to transfer or burn. Normally 0.1213 *1214 * @param collectionId ID of collection1215 * @param tokenId ID of token1216 * @param toAccountObj address which is approved to use token pieces1217 * @param fromAccountObj address which may have allowed the use of its owned tokens1218 * @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."})1219 * @returns number of approved to transfer pieces1220 */1221 async getTokenApprovedPieces(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId, fromAccountObj: ICrossAccountId): Promise<bigint> {1222 return (await this.helper.callRpc('api.rpc.unique.allowance', [collectionId, fromAccountObj, toAccountObj, tokenId])).toBigInt();1223 }12241225 /**1226 * Get the last created token ID in a collection1227 *1228 * @param collectionId ID of collection1229 * @example getLastTokenId(10);1230 * @returns id of the last created token1231 */1232 async getLastTokenId(collectionId: number): Promise<number> {1233 return (await this.helper.callRpc('api.rpc.unique.lastTokenId', [collectionId])).toNumber();1234 }12351236 /**1237 * Check if token exists1238 *1239 * @param collectionId ID of collection1240 * @param tokenId ID of token1241 * @example doesTokenExist(10, 20);1242 * @returns true if the token exists, otherwise false1243 */1244 async doesTokenExist(collectionId: number, tokenId: number): Promise<boolean> {1245 return (await this.helper.callRpc('api.rpc.unique.tokenExists', [collectionId, tokenId])).toJSON();1246 }1247}12481249class NFTnRFT extends CollectionGroup {1250 /**1251 * Get tokens owned by account1252 *1253 * @param collectionId ID of collection1254 * @param addressObj tokens owner1255 * @example getTokensByAddress(10, {Substrate: "5DyN4Y92vZCjv38fg..."})1256 * @returns array of token ids owned by account1257 */1258 async getTokensByAddress(collectionId: number, addressObj: ICrossAccountId): Promise<number[]> {1259 return (await this.helper.callRpc('api.rpc.unique.accountTokens', [collectionId, addressObj])).toJSON();1260 }12611262 /**1263 * Get token data1264 *1265 * @param collectionId ID of collection1266 * @param tokenId ID of token1267 * @param propertyKeys optionally filter the token properties to only these keys1268 * @param blockHashAt optionally query the data at some block with this hash1269 * @example getToken(10, 5);1270 * @returns human readable token data1271 */1272 async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{1273 properties: IProperty[];1274 owner: CrossAccountId;1275 normalizedOwner: CrossAccountId;1276 }| null> {1277 let tokenData;1278 if(typeof blockHashAt === 'undefined') {1279 tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId]);1280 }1281 else {1282 if(propertyKeys.length == 0) {1283 const collection = (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1284 if(!collection) return null;1285 propertyKeys = collection.tokenPropertyPermissions.map((x: ITokenPropertyPermission) => x.key);1286 }1287 tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId, propertyKeys, blockHashAt]);1288 }1289 tokenData = tokenData.toHuman();1290 if (tokenData === null || tokenData.owner === null) return null;1291 const owner = {} as any;1292 for (const key of Object.keys(tokenData.owner)) {1293 owner[key.toLocaleLowerCase()] = key.toLocaleLowerCase() == 'substrate'1294 ? CrossAccountId.normalizeSubstrateAddress(tokenData.owner[key])1295 : tokenData.owner[key];1296 }1297 tokenData.normalizedOwner = CrossAccountId.fromLowerCaseKeys(owner);1298 return tokenData;1299 }13001301 /**1302 * Set permissions to change token properties1303 *1304 * @param signer keyring of signer1305 * @param collectionId ID of collection1306 * @param permissions permissions to change a property by the collection admin or token owner1307 * @example setTokenPropertyPermissions(1308 * aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}]1309 * )1310 * @returns true if extrinsic success otherwise false1311 */1312 async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise<boolean> {1313 const result = await this.helper.executeExtrinsic(1314 signer,1315 'api.tx.unique.setTokenPropertyPermissions', [collectionId, permissions],1316 true,1317 );13181319 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');1320 }13211322 /**1323 * Get token property permissions.1324 *1325 * @param collectionId ID of collection1326 * @param propertyKeys optionally filter the returned property permissions to only these keys1327 * @example getPropertyPermissions(1219, ['location', 'date', 'time', 'isParadise']);1328 * @returns array of key-permission pairs1329 */1330 async getPropertyPermissions(collectionId: number, propertyKeys: string[] | null = null): Promise<ITokenPropertyPermission[]> {1331 return (await this.helper.callRpc('api.rpc.unique.propertyPermissions', [collectionId, ...(propertyKeys === null ? [] : [propertyKeys])])).toHuman();1332 }13331334 /**1335 * Set token properties1336 *1337 * @param signer keyring of signer1338 * @param collectionId ID of collection1339 * @param tokenId ID of token1340 * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection1341 * @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}])1342 * @returns ```true``` if extrinsic success, otherwise ```false```1343 */1344 async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise<boolean> {1345 const result = await this.helper.executeExtrinsic(1346 signer,1347 'api.tx.unique.setTokenProperties', [collectionId, tokenId, properties],1348 true,1349 );13501351 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');1352 }13531354 /**1355 * Get properties, metadata assigned to a token.1356 *1357 * @param collectionId ID of collection1358 * @param tokenId ID of token1359 * @param propertyKeys optionally filter the returned properties to only these keys1360 * @example getTokenProperties(1219, ['location', 'date', 'time', 'isParadise']);1361 * @returns array of key-value pairs1362 */1363 async getTokenProperties(collectionId: number, tokenId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1364 return (await this.helper.callRpc('api.rpc.unique.tokenProperties', [collectionId, tokenId, propertyKeys])).toHuman();1365 }13661367 /**1368 * Delete the provided properties of a token1369 * @param signer keyring of signer1370 * @param collectionId ID of collection1371 * @param tokenId ID of token1372 * @param propertyKeys property keys to be deleted1373 * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"])1374 * @returns ```true``` if extrinsic success, otherwise ```false```1375 */1376 async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise<boolean> {1377 const result = await this.helper.executeExtrinsic(1378 signer,1379 'api.tx.unique.deleteTokenProperties', [collectionId, tokenId, propertyKeys],1380 true,1381 );13821383 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted');1384 }13851386 /**1387 * Mint new collection1388 *1389 * @param signer keyring of signer1390 * @param collectionOptions basic collection options and properties1391 * @param mode NFT or RFT type of a collection1392 * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")1393 * @returns object of the created collection1394 */1395 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueBaseCollection> {1396 collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1397 collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};1398 for (const key of ['name', 'description', 'tokenPrefix']) {1399 if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);1400 }1401 const creationResult = await this.helper.executeExtrinsic(1402 signer,1403 'api.tx.unique.createCollectionEx', [collectionOptions],1404 true, // errorLabel,1405 );1406 return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));1407 }14081409 getCollectionObject(_collectionId: number): any {1410 return null;1411 }14121413 getTokenObject(_collectionId: number, _tokenId: number): any {1414 return null;1415 }1416}141714181419class NFTGroup extends NFTnRFT {1420 /**1421 * Get collection object1422 * @param collectionId ID of collection1423 * @example getCollectionObject(2);1424 * @returns instance of UniqueNFTCollection1425 */1426 getCollectionObject(collectionId: number): UniqueNFTCollection {1427 return new UniqueNFTCollection(collectionId, this.helper);1428 }14291430 /**1431 * Get token object1432 * @param collectionId ID of collection1433 * @param tokenId ID of token1434 * @example getTokenObject(10, 5);1435 * @returns instance of UniqueNFTToken1436 */1437 getTokenObject(collectionId: number, tokenId: number): UniqueNFToken {1438 return new UniqueNFToken(tokenId, this.getCollectionObject(collectionId));1439 }14401441 /**1442 * Get token's owner1443 * @param collectionId ID of collection1444 * @param tokenId ID of token1445 * @param blockHashAt optionally query the data at the block with this hash1446 * @example getTokenOwner(10, 5);1447 * @returns Address in CrossAccountId format, e.g. {Substrate: "5DnSF6RRjwteE3BrCj..."}1448 */1449 async getTokenOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<CrossAccountId> {1450 let owner;1451 if (typeof blockHashAt === 'undefined') {1452 owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId]);1453 } else {1454 owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId, blockHashAt]);1455 }1456 return CrossAccountId.fromLowerCaseKeys(owner.toJSON());1457 }14581459 /**1460 * Is token approved to transfer1461 * @param collectionId ID of collection1462 * @param tokenId ID of token1463 * @param toAccountObj address to be approved1464 * @returns ```true``` if extrinsic success, otherwise ```false```1465 */1466 async isTokenApproved(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId): Promise<boolean> {1467 return (await this.getTokenApprovedPieces(collectionId, tokenId, toAccountObj, await this.getTokenOwner(collectionId, tokenId))) === 1n;1468 }14691470 /**1471 * Changes the owner of the token.1472 *1473 * @param signer keyring of signer1474 * @param collectionId ID of collection1475 * @param tokenId ID of token1476 * @param addressObj address of a new owner1477 * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1478 * @returns ```true``` if extrinsic success, otherwise ```false```1479 */1480 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<boolean> {1481 return await super.transferToken(signer, collectionId, tokenId, addressObj, 1n);1482 }14831484 /**1485 *1486 * Change ownership of a NFT on behalf of the owner.1487 *1488 * @param signer keyring of signer1489 * @param collectionId ID of collection1490 * @param tokenId ID of token1491 * @param fromAddressObj address on behalf of which the token will be sent1492 * @param toAddressObj new token owner1493 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Ethereum: "0x9F0583DbB85..."})1494 * @returns ```true``` if extrinsic success, otherwise ```false```1495 */1496 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId): Promise<boolean> {1497 return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, 1n);1498 }14991500 /**1501 * Recursively find the address that owns the token1502 * @param collectionId ID of collection1503 * @param tokenId ID of token1504 * @param blockHashAt1505 * @example getTokenTopmostOwner(10, 5);1506 * @returns address in CrossAccountId format, e.g. {Substrate: "5DyN4Y92vZCjv38fg..."}1507 */1508 async getTokenTopmostOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<CrossAccountId | null> {1509 let owner;1510 if (typeof blockHashAt === 'undefined') {1511 owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId]);1512 } else {1513 owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId, blockHashAt]);1514 }15151516 if (owner === null) return null;15171518 return owner.toHuman();1519 }15201521 /**1522 * Get tokens nested in the provided token1523 * @param collectionId ID of collection1524 * @param tokenId ID of token1525 * @param blockHashAt optionally query the data at the block with this hash1526 * @example getTokenChildren(10, 5);1527 * @returns tokens whose depth of nesting is <= 51528 */1529 async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {1530 let children;1531 if(typeof blockHashAt === 'undefined') {1532 children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId]);1533 } else {1534 children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId, blockHashAt]);1535 }15361537 return children.toJSON().map((x: any) => {1538 return {collectionId: x.collection, tokenId: x.token};1539 });1540 }15411542 /**1543 * Nest one token into another1544 * @param signer keyring of signer1545 * @param tokenObj token to be nested1546 * @param rootTokenObj token to be parent1547 * @example nestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4});1548 * @returns ```true``` if extrinsic success, otherwise ```false```1549 */1550 async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise<boolean> {1551 const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1552 const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress);1553 if(!result) {1554 throw Error('Unable to nest token!');1555 }1556 return result;1557 }15581559 /**1560 * Remove token from nested state1561 * @param signer keyring of signer1562 * @param tokenObj token to unnest1563 * @param rootTokenObj parent of a token1564 * @param toAddressObj address of a new token owner1565 * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});1566 * @returns ```true``` if extrinsic success, otherwise ```false```1567 */1568 async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {1569 const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1570 const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);1571 if(!result) {1572 throw Error('Unable to unnest token!');1573 }1574 return result;1575 }15761577 /**1578 * Mint new collection1579 * @param signer keyring of signer1580 * @param collectionOptions Collection options1581 * @example1582 * mintCollection(aliceKeyring, {1583 * name: 'New',1584 * description: 'New collection',1585 * tokenPrefix: 'NEW',1586 * })1587 * @returns object of the created collection1588 */1589 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueNFTCollection> {1590 return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection;1591 }15921593 /**1594 * Mint new token1595 * @param signer keyring of signer1596 * @param data token data1597 * @returns created token object1598 */1599 async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise<UniqueNFToken> {1600 const creationResult = await this.helper.executeExtrinsic(1601 signer,1602 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1603 nft: {1604 properties: data.properties,1605 },1606 }],1607 true,1608 );1609 const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1610 if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1611 if (createdTokens.tokens.length < 1) throw Error('No tokens minted');1612 return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1613 }16141615 /**1616 * Mint multiple NFT tokens1617 * @param signer keyring of signer1618 * @param collectionId ID of collection1619 * @param tokens array of tokens with owner and properties1620 * @example1621 * mintMultipleTokens(aliceKeyring, 10, [{1622 * owner: {Substrate: "5DyN4Y92vZCjv38fg..."},1623 * properties: [{key: "gender", value: "male"},{key: "age", value: "45"}],1624 * },{1625 * owner: {Ethereum: "0x9F0583DbB855d..."},1626 * properties: [{key: "gender", value: "female"},{key: "age", value: "22"}],1627 * }]);1628 * @returns ```true``` if extrinsic success, otherwise ```false```1629 */1630 async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {1631 const creationResult = await this.helper.executeExtrinsic(1632 signer,1633 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}],1634 true,1635 );1636 const collection = this.getCollectionObject(collectionId);1637 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1638 }16391640 /**1641 * Mint multiple NFT tokens with one owner1642 * @param signer keyring of signer1643 * @param collectionId ID of collection1644 * @param owner tokens owner1645 * @param tokens array of tokens with owner and properties1646 * @example1647 * mintMultipleTokensWithOneOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...", [{1648 * properties: [{1649 * key: "gender",1650 * value: "female",1651 * },{1652 * key: "age",1653 * value: "33",1654 * }],1655 * }]);1656 * @returns array of newly created tokens1657 */1658 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {1659 const rawTokens = [];1660 for (const token of tokens) {1661 const raw = {NFT: {properties: token.properties}};1662 rawTokens.push(raw);1663 }1664 const creationResult = await this.helper.executeExtrinsic(1665 signer,1666 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1667 true,1668 );1669 const collection = this.getCollectionObject(collectionId);1670 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1671 }16721673 /**1674 * Set, change, or remove approved address to transfer the ownership of the NFT.1675 *1676 * @param signer keyring of signer1677 * @param collectionId ID of collection1678 * @param tokenId ID of token1679 * @param toAddressObj address to approve1680 * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1681 * @returns ```true``` if extrinsic success, otherwise ```false```1682 */1683 approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId) {1684 return super.approveToken(signer, collectionId, tokenId, toAddressObj, 1n);1685 }1686}168716881689class RFTGroup extends NFTnRFT {1690 /**1691 * Get collection object1692 * @param collectionId ID of collection1693 * @example getCollectionObject(2);1694 * @returns instance of UniqueRFTCollection1695 */1696 getCollectionObject(collectionId: number): UniqueRFTCollection {1697 return new UniqueRFTCollection(collectionId, this.helper);1698 }16991700 /**1701 * Get token object1702 * @param collectionId ID of collection1703 * @param tokenId ID of token1704 * @example getTokenObject(10, 5);1705 * @returns instance of UniqueNFTToken1706 */1707 getTokenObject(collectionId: number, tokenId: number): UniqueRFToken {1708 return new UniqueRFToken(tokenId, this.getCollectionObject(collectionId));1709 }17101711 /**1712 * Get top 10 token owners with the largest number of pieces1713 * @param collectionId ID of collection1714 * @param tokenId ID of token1715 * @example getTokenTop10Owners(10, 5);1716 * @returns array of top 10 owners1717 */1718 async getTokenTop10Owners(collectionId: number, tokenId: number): Promise<CrossAccountId[]> {1719 return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, tokenId])).toJSON().map(CrossAccountId.fromLowerCaseKeys);1720 }17211722 /**1723 * Get number of pieces owned by address1724 * @param collectionId ID of collection1725 * @param tokenId ID of token1726 * @param addressObj address token owner1727 * @example getTokenBalance(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."});1728 * @returns number of pieces ownerd by address1729 */1730 async getTokenBalance(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<bigint> {1731 return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, tokenId])).toBigInt();1732 }17331734 /**1735 * Transfer pieces of token to another address1736 * @param signer keyring of signer1737 * @param collectionId ID of collection1738 * @param tokenId ID of token1739 * @param addressObj address of a new owner1740 * @param amount number of pieces to be transfered1741 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2000n)1742 * @returns ```true``` if extrinsic success, otherwise ```false```1743 */1744 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {1745 return await super.transferToken(signer, collectionId, tokenId, addressObj, amount);1746 }17471748 /**1749 * Change ownership of some pieces of RFT on behalf of the owner.1750 * @param signer keyring of signer1751 * @param collectionId ID of collection1752 * @param tokenId ID of token1753 * @param fromAddressObj address on behalf of which the token will be sent1754 * @param toAddressObj new token owner1755 * @param amount number of pieces to be transfered1756 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n)1757 * @returns ```true``` if extrinsic success, otherwise ```false```1758 */1759 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1760 return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1761 }17621763 /**1764 * Mint new collection1765 * @param signer keyring of signer1766 * @param collectionOptions Collection options1767 * @example1768 * mintCollection(aliceKeyring, {1769 * name: 'New',1770 * description: 'New collection',1771 * tokenPrefix: 'NEW',1772 * })1773 * @returns object of the created collection1774 */1775 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueRFTCollection> {1776 return await super.mintCollection(signer, collectionOptions, 'RFT') as UniqueRFTCollection;1777 }17781779 /**1780 * Mint new token1781 * @param signer keyring of signer1782 * @param data token data1783 * @example mintToken(aliceKeyring, {collectionId: 10, owner: {Substrate: '5GHoZe9c73RYbVzq...'}, pieces: 10000n});1784 * @returns created token object1785 */1786 async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise<UniqueRFToken> {1787 const creationResult = await this.helper.executeExtrinsic(1788 signer,1789 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1790 refungible: {1791 pieces: data.pieces,1792 properties: data.properties,1793 },1794 }],1795 true,1796 );1797 const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1798 if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1799 if (createdTokens.tokens.length < 1) throw Error('No tokens minted');1800 return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1801 }18021803 async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {1804 throw Error('Not implemented');1805 const creationResult = await this.helper.executeExtrinsic(1806 signer,1807 'api.tx.unique.createMultipleItemsEx', [collectionId, {RefungibleMultipleOwners: tokens}],1808 true, // `Unable to mint RFT tokens for ${label}`,1809 );1810 const collection = this.getCollectionObject(collectionId);1811 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1812 }18131814 /**1815 * Mint multiple RFT tokens with one owner1816 * @param signer keyring of signer1817 * @param collectionId ID of collection1818 * @param owner tokens owner1819 * @param tokens array of tokens with properties and pieces1820 * @example mintMultipleTokensWithOneOwner(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, [{pieces: 100000n, properties: [{key: "gender", value: "male"}]}]);1821 * @returns array of newly created RFT tokens1822 */1823 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {1824 const rawTokens = [];1825 for (const token of tokens) {1826 const raw = {ReFungible: {pieces: token.pieces, properties: token.properties}};1827 rawTokens.push(raw);1828 }1829 const creationResult = await this.helper.executeExtrinsic(1830 signer,1831 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1832 true,1833 );1834 const collection = this.getCollectionObject(collectionId);1835 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1836 }18371838 /**1839 * Destroys a concrete instance of RFT.1840 * @param signer keyring of signer1841 * @param collectionId ID of collection1842 * @param tokenId ID of token1843 * @param amount number of pieces to be burnt1844 * @example burnToken(aliceKeyring, 10, 5);1845 * @returns ```true``` if the extrinsic is successful, otherwise ```false```1846 */1847 async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount=1n): Promise<boolean> {1848 return await super.burnToken(signer, collectionId, tokenId, amount);1849 }18501851 /**1852 * Destroys a concrete instance of RFT on behalf of the owner.1853 * @param signer keyring of signer1854 * @param collectionId ID of collection1855 * @param tokenId ID of token1856 * @param fromAddressObj address on behalf of which the token will be burnt1857 * @param amount number of pieces to be burnt1858 * @example burnTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2n)1859 * @returns ```true``` if extrinsic success, otherwise ```false```1860 */1861 async burnTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1862 return await super.burnTokenFrom(signer, collectionId, tokenId, fromAddressObj, amount);1863 }18641865 /**1866 * Set, change, or remove approved address to transfer the ownership of the RFT.1867 *1868 * @param signer keyring of signer1869 * @param collectionId ID of collection1870 * @param tokenId ID of token1871 * @param toAddressObj address to approve1872 * @param amount number of pieces to be approved1873 * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n);1874 * @returns true if the token success, otherwise false1875 */1876 approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {1877 return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);1878 }18791880 /**1881 * Get total number of pieces1882 * @param collectionId ID of collection1883 * @param tokenId ID of token1884 * @example getTokenTotalPieces(10, 5);1885 * @returns number of pieces1886 */1887 async getTokenTotalPieces(collectionId: number, tokenId: number): Promise<bigint> {1888 return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, tokenId])).unwrap().toBigInt();1889 }18901891 /**1892 * Change number of token pieces. Signer must be the owner of all token pieces.1893 * @param signer keyring of signer1894 * @param collectionId ID of collection1895 * @param tokenId ID of token1896 * @param amount new number of pieces1897 * @example repartitionToken(aliceKeyring, 10, 5, 12345n);1898 * @returns true if the repartion was success, otherwise false1899 */1900 async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint): Promise<boolean> {1901 const currentAmount = await this.getTokenTotalPieces(collectionId, tokenId);1902 const repartitionResult = await this.helper.executeExtrinsic(1903 signer,1904 'api.tx.unique.repartition', [collectionId, tokenId, amount],1905 true,1906 );1907 if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated');1908 return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed');1909 }1910}191119121913class FTGroup extends CollectionGroup {1914 /**1915 * Get collection object1916 * @param collectionId ID of collection1917 * @example getCollectionObject(2);1918 * @returns instance of UniqueFTCollection1919 */1920 getCollectionObject(collectionId: number): UniqueFTCollection {1921 return new UniqueFTCollection(collectionId, this.helper);1922 }19231924 /**1925 * Mint new fungible collection1926 * @param signer keyring of signer1927 * @param collectionOptions Collection options1928 * @param decimalPoints number of token decimals1929 * @example1930 * mintCollection(aliceKeyring, {1931 * name: 'New',1932 * description: 'New collection',1933 * tokenPrefix: 'NEW',1934 * }, 18)1935 * @returns newly created fungible collection1936 */1937 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}, decimalPoints = 0): Promise<UniqueFTCollection> {1938 collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1939 if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions');1940 collectionOptions.mode = {fungible: decimalPoints};1941 for (const key of ['name', 'description', 'tokenPrefix']) {1942 if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);1943 }1944 const creationResult = await this.helper.executeExtrinsic(1945 signer,1946 'api.tx.unique.createCollectionEx', [collectionOptions],1947 true,1948 );1949 return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));1950 }19511952 /**1953 * Mint tokens1954 * @param signer keyring of signer1955 * @param collectionId ID of collection1956 * @param owner address owner of new tokens1957 * @param amount amount of tokens to be meanted1958 * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n);1959 * @returns ```true``` if extrinsic success, otherwise ```false```1960 */1961 async mintTokens(signer: TSigner, collectionId: number, amount: bigint, owner: ICrossAccountId | string): Promise<boolean> {1962 const creationResult = await this.helper.executeExtrinsic(1963 signer,1964 'api.tx.unique.createItem', [collectionId, (typeof owner === 'string') ? {Substrate: owner} : owner, {1965 fungible: {1966 value: amount,1967 },1968 }],1969 true, // `Unable to mint fungible tokens for ${label}`,1970 );1971 return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');1972 }19731974 /**1975 * Mint multiple Fungible tokens with one owner1976 * @param signer keyring of signer1977 * @param collectionId ID of collection1978 * @param owner tokens owner1979 * @param tokens array of tokens with properties and pieces1980 * @returns ```true``` if extrinsic success, otherwise ```false```1981 */1982 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, tokens: {value: bigint}[], owner: ICrossAccountId): Promise<boolean> {1983 const rawTokens = [];1984 for (const token of tokens) {1985 const raw = {Fungible: {Value: token.value}};1986 rawTokens.push(raw);1987 }1988 const creationResult = await this.helper.executeExtrinsic(1989 signer,1990 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1991 true,1992 );1993 return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');1994 }19951996 /**1997 * Get the top 10 owners with the largest balance for the Fungible collection1998 * @param collectionId ID of collection1999 * @example getTop10Owners(10);2000 * @returns array of ```ICrossAccountId```2001 */2002 async getTop10Owners(collectionId: number): Promise<CrossAccountId[]> {2003 return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, 0])).toJSON().map(CrossAccountId.fromLowerCaseKeys);2004 }20052006 /**2007 * Get account balance2008 * @param collectionId ID of collection2009 * @param addressObj address of owner2010 * @example getBalance(10, {Substrate: "5GHoZe9c73RYbVzq..."})2011 * @returns amount of fungible tokens owned by address2012 */2013 async getBalance(collectionId: number, addressObj: ICrossAccountId): Promise<bigint> {2014 return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, 0])).toBigInt();2015 }20162017 /**2018 * Transfer tokens to address2019 * @param signer keyring of signer2020 * @param collectionId ID of collection2021 * @param toAddressObj address recipient2022 * @param amount amount of tokens to be sent2023 * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2024 * @returns ```true``` if extrinsic success, otherwise ```false```2025 */2026 async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {2027 return await super.transferToken(signer, collectionId, 0, toAddressObj, amount);2028 }20292030 /**2031 * Transfer some tokens on behalf of the owner.2032 * @param signer keyring of signer2033 * @param collectionId ID of collection2034 * @param fromAddressObj address on behalf of which tokens will be sent2035 * @param toAddressObj address where token to be sent2036 * @param amount number of tokens to be sent2037 * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n);2038 * @returns ```true``` if extrinsic success, otherwise ```false```2039 */2040 async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {2041 return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount);2042 }20432044 /**2045 * Destroy some amount of tokens2046 * @param signer keyring of signer2047 * @param collectionId ID of collection2048 * @param amount amount of tokens to be destroyed2049 * @example burnTokens(aliceKeyring, 10, 1000n);2050 * @returns ```true``` if extrinsic success, otherwise ```false```2051 */2052 async burnTokens(signer: IKeyringPair, collectionId: number, amount=1n): Promise<boolean> {2053 return await super.burnToken(signer, collectionId, 0, amount);2054 }20552056 /**2057 * Burn some tokens on behalf of the owner.2058 * @param signer keyring of signer2059 * @param collectionId ID of collection2060 * @param fromAddressObj address on behalf of which tokens will be burnt2061 * @param amount amount of tokens to be burnt2062 * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2063 * @returns ```true``` if extrinsic success, otherwise ```false```2064 */2065 async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {2066 return await super.burnTokenFrom(signer, collectionId, 0, fromAddressObj, amount);2067 }20682069 /**2070 * Get total collection supply2071 * @param collectionId2072 * @returns2073 */2074 async getTotalPieces(collectionId: number): Promise<bigint> {2075 return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, 0])).unwrap().toBigInt();2076 }20772078 /**2079 * Set, change, or remove approved address to transfer tokens.2080 *2081 * @param signer keyring of signer2082 * @param collectionId ID of collection2083 * @param toAddressObj address to be approved2084 * @param amount amount of tokens to be approved2085 * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n)2086 * @returns ```true``` if extrinsic success, otherwise ```false```2087 */2088 approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {2089 return super.approveToken(signer, collectionId, 0, toAddressObj, amount);2090 }20912092 /**2093 * Get amount of fungible tokens approved to transfer2094 * @param collectionId ID of collection2095 * @param fromAddressObj owner of tokens2096 * @param toAddressObj the address approved for the transfer of tokens on behalf of the owner2097 * @returns number of tokens approved for the transfer2098 */2099 getApprovedTokens(collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {2100 return super.getTokenApprovedPieces(collectionId, 0, toAddressObj, fromAddressObj);2101 }2102}210321042105class ChainGroup extends HelperGroup<ChainHelperBase> {2106 /**2107 * Get system properties of a chain2108 * @example getChainProperties();2109 * @returns ss58Format, token decimals, and token symbol2110 */2111 getChainProperties(): IChainProperties {2112 const properties = (this.helper.getApi() as any).registry.getChainProperties().toJSON();2113 return {2114 ss58Format: properties.ss58Format.toJSON(),2115 tokenDecimals: properties.tokenDecimals.toJSON(),2116 tokenSymbol: properties.tokenSymbol.toJSON(),2117 };2118 }21192120 /**2121 * Get chain header2122 * @example getLatestBlockNumber();2123 * @returns the number of the last block2124 */2125 async getLatestBlockNumber(): Promise<number> {2126 return (await this.helper.callRpc('api.rpc.chain.getHeader')).number.toNumber();2127 }21282129 /**2130 * Get block hash by block number2131 * @param blockNumber number of block2132 * @example getBlockHashByNumber(12345);2133 * @returns hash of a block2134 */2135 async getBlockHashByNumber(blockNumber: number): Promise<string | null> {2136 const blockHash = (await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber])).toJSON();2137 if(blockHash === '0x0000000000000000000000000000000000000000000000000000000000000000') return null;2138 return blockHash;2139 }21402141 // TODO add docs2142 async getBlock(blockHashOrNumber: string | number): Promise<IBlock | null> {2143 const blockHash = typeof blockHashOrNumber === 'string' ? blockHashOrNumber : await this.getBlockHashByNumber(blockHashOrNumber);2144 if (!blockHash) return null;2145 return (await this.helper.callRpc('api.rpc.chain.getBlock', [blockHash])).toHuman().block;2146 }21472148 /**2149 * Get latest relay block2150 * @returns {number} relay block2151 */2152 async getRelayBlockNumber(): Promise<bigint> {2153 const blockNumber = (await this.helper.callRpc('api.query.parachainSystem.validationData')).toJSON().relayParentNumber;2154 return BigInt(blockNumber);2155 }21562157 /**2158 * Get account nonce2159 * @param address substrate address2160 * @example getNonce("5GrwvaEF5zXb26Fz...");2161 * @returns number, account's nonce2162 */2163 async getNonce(address: TSubstrateAccount): Promise<number> {2164 return (await this.helper.callRpc('api.query.system.account', [address])).nonce.toNumber();2165 }2166}21672168class SubstrateBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2169 /**2170 * Get substrate address balance2171 * @param address substrate address2172 * @example getSubstrate("5GrwvaEF5zXb26Fz...")2173 * @returns amount of tokens on address2174 */2175 async getSubstrate(address: TSubstrateAccount): Promise<bigint> {2176 return (await this.helper.callRpc('api.query.system.account', [address])).data.free.toBigInt();2177 }21782179 /**2180 * Transfer tokens to substrate address2181 * @param signer keyring of signer2182 * @param address substrate address of a recipient2183 * @param amount amount of tokens to be transfered2184 * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2185 * @returns ```true``` if extrinsic success, otherwise ```false```2186 */2187 async transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2188 const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true/*, `Unable to transfer balance from ${this.helper.getSignerAddress(signer)} to ${address}`*/);21892190 let transfer = {from: null, to: null, amount: 0n} as any;2191 result.result.events.forEach(({event: {data, method, section}}) => {2192 if ((section === 'balances') && (method === 'Transfer')) {2193 transfer = {2194 from: this.helper.address.normalizeSubstrate(data[0]),2195 to: this.helper.address.normalizeSubstrate(data[1]),2196 amount: BigInt(data[2]),2197 };2198 }2199 });2200 const isSuccess = this.helper.address.normalizeSubstrate(typeof signer === 'string' ? signer : signer.address) === transfer.from2201 && this.helper.address.normalizeSubstrate(address) === transfer.to2202 && BigInt(amount) === transfer.amount;2203 return isSuccess;2204 }22052206 /**2207 * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2208 * @param address substrate address2209 * @returns2210 */2211 async getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2212 const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data;2213 return {free: accountInfo.free.toBigInt(), miscFrozen: accountInfo.miscFrozen.toBigInt(), feeFrozen: accountInfo.feeFrozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};2214 }2215}22162217class EthereumBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2218 /**2219 * Get ethereum address balance2220 * @param address ethereum address2221 * @example getEthereum("0x9F0583DbB855d...")2222 * @returns amount of tokens on address2223 */2224 async getEthereum(address: TEthereumAccount): Promise<bigint> {2225 return (await this.helper.callRpc('api.rpc.eth.getBalance', [address])).toBigInt();2226 }22272228 /**2229 * Transfer tokens to address2230 * @param signer keyring of signer2231 * @param address Ethereum address of a recipient2232 * @param amount amount of tokens to be transfered2233 * @example transferToEthereum(alithKeyring, "0x9F0583DbB855d...", 100_000_000_000n);2234 * @returns ```true``` if extrinsic success, otherwise ```false```2235 */2236 async transferToEthereum(signer: TSigner, address: TEthereumAccount, amount: bigint | string): Promise<boolean> {2237 const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true);22382239 let transfer = {from: null, to: null, amount: 0n} as any;2240 result.result.events.forEach(({event: {data, method, section}}) => {2241 if ((section === 'balances') && (method === 'Transfer')) {2242 transfer = {2243 from: data[0].toString(),2244 to: data[1].toString(),2245 amount: BigInt(data[2]),2246 };2247 }2248 });2249 const isSuccess = (typeof signer === 'string' ? signer : signer.address) === transfer.from2250 && address === transfer.to2251 && BigInt(amount) === transfer.amount;2252 return isSuccess;2253 }2254}22552256class BalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2257 subBalanceGroup: SubstrateBalanceGroup<T>;2258 ethBalanceGroup: EthereumBalanceGroup<T>;22592260 constructor(helper: T) {2261 super(helper);2262 this.subBalanceGroup = new SubstrateBalanceGroup(helper);2263 this.ethBalanceGroup = new EthereumBalanceGroup(helper);2264 }22652266 getCollectionCreationPrice(): bigint {2267 return 2n * this.getOneTokenNominal();2268 }2269 /**2270 * Representation of the native token in the smallest unit - one OPAL (OPL), QUARTZ (QTZ), or UNIQUE (UNQ).2271 * @example getOneTokenNominal()2272 * @returns ```BigInt``` representation of the native token in the smallest unit, e.g. ```1_000_000_000_000_000_000n``` for QTZ.2273 */2274 getOneTokenNominal(): bigint {2275 const chainProperties = this.helper.chain.getChainProperties();2276 return 10n ** BigInt((chainProperties.tokenDecimals || [18])[0]);2277 }22782279 /**2280 * Get substrate address balance2281 * @param address substrate address2282 * @example getSubstrate("5GrwvaEF5zXb26Fz...")2283 * @returns amount of tokens on address2284 */2285 getSubstrate(address: TSubstrateAccount): Promise<bigint> {2286 return this.subBalanceGroup.getSubstrate(address);2287 }22882289 /**2290 * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2291 * @param address substrate address2292 * @returns2293 */2294 getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2295 return this.subBalanceGroup.getSubstrateFull(address);2296 }22972298 /**2299 * Get ethereum address balance2300 * @param address ethereum address2301 * @example getEthereum("0x9F0583DbB855d...")2302 * @returns amount of tokens on address2303 */2304 getEthereum(address: TEthereumAccount): Promise<bigint> {2305 return this.ethBalanceGroup.getEthereum(address);2306 }23072308 /**2309 * Transfer tokens to substrate address2310 * @param signer keyring of signer2311 * @param address substrate address of a recipient2312 * @param amount amount of tokens to be transfered2313 * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2314 * @returns ```true``` if extrinsic success, otherwise ```false```2315 */2316 transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2317 return this.subBalanceGroup.transferToSubstrate(signer, address, amount);2318 }23192320 async forceTransferToSubstrate(signer: TSigner, from: TSubstrateAccount, to: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2321 const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceTransfer', [from, to, amount], true);23222323 let transfer = {from: null, to: null, amount: 0n} as any;2324 result.result.events.forEach(({event: {data, method, section}}) => {2325 if ((section === 'balances') && (method === 'Transfer')) {2326 transfer = {2327 from: this.helper.address.normalizeSubstrate(data[0]),2328 to: this.helper.address.normalizeSubstrate(data[1]),2329 amount: BigInt(data[2]),2330 };2331 }2332 });2333 let isSuccess = this.helper.address.normalizeSubstrate(from) === transfer.from;2334 isSuccess = isSuccess && this.helper.address.normalizeSubstrate(to) === transfer.to;2335 isSuccess = isSuccess && BigInt(amount) === transfer.amount;2336 return isSuccess;2337 }23382339 /**2340 * Transfer tokens with the unlock period2341 * @param signer signers Keyring2342 * @param address Substrate address of recipient2343 * @param schedule Schedule params2344 * @example vestedTransfer(signer, recepient.address, 20000, 100, 10, 50 * nominal); // total amount of vested tokens will be 100 * 50 = 50002345 */2346 async vestedTransfer(signer: TSigner, address: TSubstrateAccount, schedule: {start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint}): Promise<void> {2347 const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.vestedTransfer', [address, schedule]);2348 const event = result.result.events2349 .find(e => e.event.section === 'vesting' &&2350 e.event.method === 'VestingScheduleAdded' &&2351 e.event.data[0].toHuman() === signer.address);2352 if (!event) throw Error('Cannot find transfer in events');2353 }23542355 /**2356 * Get schedule for recepient of vested transfer2357 * @param address Substrate address of recipient2358 * @returns 2359 */2360 async getVestingSchedules(address: TSubstrateAccount): Promise<{start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint}[]> {2361 const schedule = (await this.helper.callRpc('api.query.vesting.vestingSchedules', [address])).toJSON();2362 return schedule.map((schedule: any) => {2363 return {2364 start: BigInt(schedule.start),2365 period: BigInt(schedule.period),2366 periodCount: BigInt(schedule.periodCount),2367 perPeriod: BigInt(schedule.perPeriod),2368 };2369 });2370 }23712372 /**2373 * Claim vested tokens2374 * @param signer signers Keyring2375 */2376 async claim(signer: TSigner) {2377 const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.claim', []);2378 const event = result.result.events2379 .find(e => e.event.section === 'vesting' &&2380 e.event.method === 'Claimed' &&2381 e.event.data[0].toHuman() === signer.address);2382 if (!event) throw Error('Cannot find claim in events');2383 }2384}23852386class AddressGroup extends HelperGroup<ChainHelperBase> {2387 /**2388 * Normalizes the address to the specified ss58 format, by default ```42```.2389 * @param address substrate address2390 * @param ss58Format format for address conversion, by default ```42```2391 * @example normalizeSubstrate("unjKJQJrRd238pkUZZvzDQrfKuM39zBSnQ5zjAGAGcdRhaJTx") // returns 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY2392 * @returns substrate address converted to normalized (i.e., starting with 5) or specified explicitly representation2393 */2394 normalizeSubstrate(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {2395 return CrossAccountId.normalizeSubstrateAddress(address, ss58Format);2396 }23972398 /**2399 * Get address in the connected chain format2400 * @param address substrate address2401 * @example normalizeSubstrateToChainFormat("5GrwvaEF5zXb26Fz...") // returns unjKJQJrRd238pkUZZ... for Unique Network2402 * @returns address in chain format2403 */2404 normalizeSubstrateToChainFormat(address: TSubstrateAccount): TSubstrateAccount {2405 return this.normalizeSubstrate(address, this.helper.chain.getChainProperties().ss58Format);2406 }24072408 /**2409 * Get substrate mirror of an ethereum address2410 * @param ethAddress ethereum address2411 * @param toChainFormat false for normalized account2412 * @example ethToSubstrate('0x9F0583DbB855d...')2413 * @returns substrate mirror of a provided ethereum address2414 */2415 ethToSubstrate(ethAddress: TEthereumAccount, toChainFormat=false): TSubstrateAccount {2416 return CrossAccountId.translateEthToSub(ethAddress, toChainFormat ? this.helper.chain.getChainProperties().ss58Format : undefined);2417 }24182419 /**2420 * Get ethereum mirror of a substrate address2421 * @param subAddress substrate account2422 * @example substrateToEth("5DnSF6RRjwteE3BrC...")2423 * @returns ethereum mirror of a provided substrate address2424 */2425 substrateToEth(subAddress: TSubstrateAccount): TEthereumAccount {2426 return CrossAccountId.translateSubToEth(subAddress);2427 }24282429 /**2430 * Encode key to substrate address2431 * @param key key for encoding address2432 * @param ss58Format prefix for encoding to the address of the corresponding network2433 * @returns encoded substrate address2434 */2435 encodeSubstrateAddress (key: Uint8Array | string | bigint, ss58Format = 42): string {2436 const u8a :Uint8Array = typeof key === 'string'2437 ? hexToU8a(key)2438 : typeof key === 'bigint'2439 ? hexToU8a(key.toString(16))2440 : key;2441 2442 if (ss58Format < 0 || ss58Format > 16383 || [46, 47].includes(ss58Format)) {2443 throw new Error(`ss58Format is not valid, received ${typeofss58Format} "${ss58Format}"`);2444 }2445 2446 const allowedDecodedLengths = [1, 2, 4, 8, 32, 33];2447 if (!allowedDecodedLengths.includes(u8a.length)) {2448 throw new Error(`key length is not valid, received ${u8a.length}, valid values are ${allowedDecodedLengths.join(', ')}`);2449 }2450 2451 const u8aPrefix = ss58Format < 642452 ? new Uint8Array([ss58Format])2453 : new Uint8Array([2454 ((ss58Format & 0xfc) >> 2) | 0x40,2455 (ss58Format >> 8) | ((ss58Format & 0x03) << 6),2456 ]);24572458 const input = u8aConcat(u8aPrefix, u8a);2459 2460 return base58Encode(u8aConcat(2461 input,2462 blake2AsU8a(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1),2463 ));2464 }24652466 /**2467 * Restore substrate address from bigint representation2468 * @param number decimal representation of substrate address2469 * @returns substrate address2470 */2471 restoreCrossAccountFromBigInt(number: bigint): TSubstrateAccount {2472 if (this.helper.api === null) {2473 throw 'Not connected';2474 }2475 const res = this.helper.api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();2476 if (res === undefined || res === null) {2477 throw 'Restore address error';2478 }2479 return res.toString();2480 }24812482 /**2483 * Convert etherium cross account id to substrate cross account id2484 * @param ethCrossAccount etherium cross account2485 * @returns substrate cross account id2486 */2487 convertCrossAccountFromEthCrossAcoount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId {2488 if (ethCrossAccount.sub === '0') {2489 return {Ethereum: ethCrossAccount.eth.toLocaleLowerCase()};2490 }2491 2492 const ss58 = this.restoreCrossAccountFromBigInt(BigInt(ethCrossAccount.sub));2493 return {Substrate: ss58};2494 }24952496 paraSiblingSovereignAccount(paraid: number) {2497 // We are getting a *sibling* parachain sovereign account,2498 // so we need a sibling prefix: encoded(b"sibl") == 0x7369626c2499 const siblingPrefix = '0x7369626c';25002501 const encodedParaId = this.helper.getApi().createType('u32', paraid).toHex(true).substring(2);2502 const suffix = '000000000000000000000000000000000000000000000000';25032504 return siblingPrefix + encodedParaId + suffix;2505 }2506}25072508class StakingGroup extends HelperGroup<UniqueHelper> {2509 /**2510 * Stake tokens for App Promotion2511 * @param signer keyring of signer2512 * @param amountToStake amount of tokens to stake2513 * @param label extra label for log2514 * @returns2515 */2516 async stake(signer: TSigner, amountToStake: bigint, label?: string): Promise<boolean> {2517 if(typeof label === 'undefined') label = `${signer.address} amount: ${amountToStake}`;2518 const _stakeResult = await this.helper.executeExtrinsic(2519 signer, 'api.tx.appPromotion.stake',2520 [amountToStake], true,2521 );2522 // TODO extract info from stakeResult2523 return true;2524 }25252526 /**2527 * Unstake tokens for App Promotion2528 * @param signer keyring of signer2529 * @param amountToUnstake amount of tokens to unstake2530 * @param label extra label for log2531 * @returns block number where balances will be unlocked2532 */2533 async unstake(signer: TSigner, label?: string): Promise<number> {2534 if(typeof label === 'undefined') label = `${signer.address}`;2535 const _unstakeResult = await this.helper.executeExtrinsic(2536 signer, 'api.tx.appPromotion.unstake',2537 [], true,2538 );2539 // TODO extract block number fron events2540 return 1;2541 }25422543 /**2544 * Get total staked amount for address2545 * @param address substrate or ethereum address2546 * @returns total staked amount2547 */2548 async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {2549 if (address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();2550 return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();2551 }25522553 /**2554 * Get total staked per block2555 * @param address substrate or ethereum address2556 * @returns array of stakes. `block` – the number of the block in which the stake was made. `amount` - the number of tokens staked in the block2557 */2558 async getTotalStakedPerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2559 const rawTotalStakerdPerBlock = await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address]);2560 return rawTotalStakerdPerBlock.map(([block, amount]: any[]) => {2561 return {2562 block: block.toBigInt(),2563 amount: amount.toBigInt(),2564 };2565 });2566 }25672568 /**2569 * Get total pending unstake amount for address2570 * @param address substrate or ethereum address2571 * @returns total pending unstake amount2572 */2573 async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {2574 return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();2575 }25762577 /**2578 * Get pending unstake amount per block for address2579 * @param address substrate or ethereum address2580 * @returns array of pending stakes. `block` – the number of the block in which the unstake was made. `amount` - the number of tokens unstaked in the block2581 */2582 async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2583 const rawUnstakedPerBlock = await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address]);2584 const result = rawUnstakedPerBlock.map(([block, amount]: any[]) => {2585 return {2586 block: block.toBigInt(),2587 amount: amount.toBigInt(),2588 };2589 });2590 return result;2591 }2592}25932594class SchedulerGroup extends HelperGroup<UniqueHelper> {2595 constructor(helper: UniqueHelper) {2596 super(helper);2597 }25982599 cancelScheduled(signer: TSigner, scheduledId: string) {2600 return this.helper.executeExtrinsic(2601 signer,2602 'api.tx.scheduler.cancelNamed',2603 [scheduledId],2604 true,2605 );2606 }26072608 changePriority(signer: TSigner, scheduledId: string, priority: number) {2609 return this.helper.executeExtrinsic(2610 signer,2611 'api.tx.scheduler.changeNamedPriority',2612 [scheduledId, priority],2613 true,2614 );2615 }26162617 scheduleAt<T extends UniqueHelper>(2618 executionBlockNumber: number,2619 options: ISchedulerOptions = {},2620 ) {2621 return this.schedule<T>('schedule', executionBlockNumber, options);2622 }26232624 scheduleAfter<T extends UniqueHelper>(2625 blocksBeforeExecution: number,2626 options: ISchedulerOptions = {},2627 ) {2628 return this.schedule<T>('scheduleAfter', blocksBeforeExecution, options);2629 }26302631 schedule<T extends UniqueHelper>(2632 scheduleFn: 'schedule' | 'scheduleAfter',2633 blocksNum: number,2634 options: ISchedulerOptions = {},2635 ) {2636 // eslint-disable-next-line @typescript-eslint/naming-convention2637 const ScheduledHelperType = ScheduledUniqueHelper(this.helper.helperBase);2638 return this.helper.clone(ScheduledHelperType, {2639 scheduleFn,2640 blocksNum,2641 options,2642 }) as T;2643 }2644}26452646class ForeignAssetsGroup extends HelperGroup<UniqueHelper> {2647 async register(signer: TSigner, ownerAddress: TSubstrateAccount, location: any, metadata: IForeignAssetMetadata) {2648 await this.helper.executeExtrinsic(2649 signer,2650 'api.tx.foreignAssets.registerForeignAsset',2651 [ownerAddress, location, metadata],2652 true,2653 );2654 }26552656 async update(signer: TSigner, foreignAssetId: number, location: any, metadata: IForeignAssetMetadata) {2657 await this.helper.executeExtrinsic(2658 signer,2659 'api.tx.foreignAssets.updateForeignAsset',2660 [foreignAssetId, location, metadata],2661 true,2662 );2663 }2664}26652666class XcmGroup<T extends ChainHelperBase> extends HelperGroup<T> {2667 palletName: string;26682669 constructor(helper: T, palletName: string) {2670 super(helper);26712672 this.palletName = palletName;2673 }26742675 async limitedReserveTransferAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number, weightLimit: number) {2676 await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, {Limited: weightLimit}], true);2677 }2678}26792680class XTokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {2681 async transfer(signer: TSigner, currencyId: any, amount: bigint, destination: any, destWeight: number) {2682 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transfer', [currencyId, amount, destination, destWeight], true);2683 }26842685 async transferMultiasset(signer: TSigner, asset: any, destination: any, destWeight: number) {2686 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMultiasset', [asset, destination, destWeight], true);2687 }26882689 async transferMulticurrencies(signer: TSigner, currencies: any[], feeItem: number, destLocation: any, destWeight: number) {2690 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMulticurrencies', [currencies, feeItem, destLocation, destWeight], true);2691 }2692}26932694class TokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {2695 async accounts(address: string, currencyId: any) {2696 const {free} = (await this.helper.callRpc('api.query.tokens.accounts', [address, currencyId])).toJSON() as any;2697 return BigInt(free);2698 }2699}27002701class AssetsGroup<T extends ChainHelperBase> extends HelperGroup<T> {2702 async create(signer: TSigner, assetId: number, admin: string, minimalBalance: bigint) {2703 await this.helper.executeExtrinsic(signer, 'api.tx.assets.create', [assetId, admin, minimalBalance], true);2704 }27052706 async setMetadata(signer: TSigner, assetId: number, name: string, symbol: string, decimals: number) {2707 await this.helper.executeExtrinsic(signer, 'api.tx.assets.setMetadata', [assetId, name, symbol, decimals], true);2708 }27092710 async mint(signer: TSigner, assetId: number, beneficiary: string, amount: bigint) {2711 await this.helper.executeExtrinsic(signer, 'api.tx.assets.mint', [assetId, beneficiary, amount], true);2712 }27132714 async account(assetId: string | number, address: string) {2715 const accountAsset = (2716 await this.helper.callRpc('api.query.assets.account', [assetId, address])2717 ).toJSON()! as any;27182719 if (accountAsset !== null) {2720 return BigInt(accountAsset['balance']);2721 } else {2722 return null;2723 }2724 }2725}27262727class AcalaAssetRegistryGroup extends HelperGroup<AcalaHelper> {2728 async registerForeignAsset(signer: TSigner, destination: any, metadata: AcalaAssetMetadata) {2729 await this.helper.executeExtrinsic(signer, 'api.tx.assetRegistry.registerForeignAsset', [destination, metadata], true);2730 }2731}27322733class MoonbeamAssetManagerGroup extends HelperGroup<MoonbeamHelper> {2734 makeRegisterForeignAssetProposal(assetInfo: MoonbeamAssetInfo) {2735 const apiPrefix = 'api.tx.assetManager.';27362737 const registerTx = this.helper.constructApiCall(2738 apiPrefix + 'registerForeignAsset',2739 [assetInfo.location, assetInfo.metadata, assetInfo.existentialDeposit, assetInfo.isSufficient],2740 );27412742 const setUnitsTx = this.helper.constructApiCall(2743 apiPrefix + 'setAssetUnitsPerSecond',2744 [assetInfo.location, assetInfo.unitsPerSecond, assetInfo.numAssetsWeightHint],2745 );27462747 const batchCall = this.helper.getApi().tx.utility.batchAll([registerTx, setUnitsTx]);2748 const encodedProposal = batchCall?.method.toHex() || '';2749 return encodedProposal;2750 }27512752 async assetTypeId(location: any) {2753 return await this.helper.callRpc('api.query.assetManager.assetTypeId', [location]);2754 }2755}27562757class MoonbeamDemocracyGroup extends HelperGroup<MoonbeamHelper> {2758 async notePreimage(signer: TSigner, encodedProposal: string) {2759 await this.helper.executeExtrinsic(signer, 'api.tx.democracy.notePreimage', [encodedProposal], true);2760 }27612762 externalProposeMajority(proposalHash: string) {2763 return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposalHash]);2764 }27652766 fastTrack(proposalHash: string, votingPeriod: number, delayPeriod: number) {2767 return this.helper.constructApiCall('api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);2768 }27692770 async referendumVote(signer: TSigner, referendumIndex: number, accountVote: DemocracyStandardAccountVote) {2771 await this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, {Standard: accountVote}], true);2772 }2773}27742775class MoonbeamCollectiveGroup extends HelperGroup<MoonbeamHelper> {2776 collective: string;27772778 constructor(helper: MoonbeamHelper, collective: string) {2779 super(helper);27802781 this.collective = collective;2782 }27832784 async propose(signer: TSigner, threshold: number, proposalHash: string, lengthBound: number) {2785 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.propose`, [threshold, proposalHash, lengthBound], true);2786 }27872788 async vote(signer: TSigner, proposalHash: string, proposalIndex: number, approve: boolean) {2789 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve], true);2790 }27912792 async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: number, lengthBound: number) {2793 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [proposalHash, proposalIndex, weightBound, lengthBound], true);2794 }27952796 async proposalCount() {2797 return Number(await this.helper.callRpc(`api.query.${this.collective}.proposalCount`, []));2798 }2799}28002801export type ChainHelperBaseConstructor = new(...args: any[]) => ChainHelperBase;2802export type UniqueHelperConstructor = new(...args: any[]) => UniqueHelper;28032804export class UniqueHelper extends ChainHelperBase {2805 balance: BalanceGroup<UniqueHelper>;2806 collection: CollectionGroup;2807 nft: NFTGroup;2808 rft: RFTGroup;2809 ft: FTGroup;2810 staking: StakingGroup;2811 scheduler: SchedulerGroup;2812 foreignAssets: ForeignAssetsGroup;2813 xcm: XcmGroup<UniqueHelper>;2814 xTokens: XTokensGroup<UniqueHelper>;2815 tokens: TokensGroup<UniqueHelper>;28162817 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2818 super(logger, options.helperBase ?? UniqueHelper);28192820 this.balance = new BalanceGroup(this);2821 this.collection = new CollectionGroup(this);2822 this.nft = new NFTGroup(this);2823 this.rft = new RFTGroup(this);2824 this.ft = new FTGroup(this);2825 this.staking = new StakingGroup(this);2826 this.scheduler = new SchedulerGroup(this);2827 this.foreignAssets = new ForeignAssetsGroup(this);2828 this.xcm = new XcmGroup(this, 'polkadotXcm');2829 this.xTokens = new XTokensGroup(this);2830 this.tokens = new TokensGroup(this);2831 }28322833 getSudo<T extends UniqueHelper>() {2834 // eslint-disable-next-line @typescript-eslint/naming-convention2835 const SudoHelperType = SudoHelper(this.helperBase);2836 return this.clone(SudoHelperType) as T;2837 }2838}28392840export class XcmChainHelper extends ChainHelperBase {2841 async connect(wsEndpoint: string, _listeners?: any): Promise<void> {2842 const wsProvider = new WsProvider(wsEndpoint);2843 this.api = new ApiPromise({2844 provider: wsProvider,2845 });2846 await this.api.isReadyOrError;2847 this.network = await UniqueHelper.detectNetwork(this.api);2848 }2849}28502851export class RelayHelper extends XcmChainHelper {2852 xcm: XcmGroup<RelayHelper>;28532854 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2855 super(logger, options.helperBase ?? RelayHelper);28562857 this.xcm = new XcmGroup(this, 'xcmPallet');2858 }2859}28602861export class WestmintHelper extends XcmChainHelper {2862 balance: SubstrateBalanceGroup<WestmintHelper>;2863 xcm: XcmGroup<WestmintHelper>;2864 assets: AssetsGroup<WestmintHelper>;2865 xTokens: XTokensGroup<WestmintHelper>;28662867 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2868 super(logger, options.helperBase ?? WestmintHelper);28692870 this.balance = new SubstrateBalanceGroup(this);2871 this.xcm = new XcmGroup(this, 'polkadotXcm');2872 this.assets = new AssetsGroup(this);2873 this.xTokens = new XTokensGroup(this);2874 }2875}28762877export class MoonbeamHelper extends XcmChainHelper {2878 balance: EthereumBalanceGroup<MoonbeamHelper>;2879 assetManager: MoonbeamAssetManagerGroup;2880 assets: AssetsGroup<MoonbeamHelper>;2881 xTokens: XTokensGroup<MoonbeamHelper>;2882 democracy: MoonbeamDemocracyGroup;2883 collective: {2884 council: MoonbeamCollectiveGroup,2885 techCommittee: MoonbeamCollectiveGroup,2886 };28872888 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2889 super(logger, options.helperBase ?? MoonbeamHelper);28902891 this.balance = new EthereumBalanceGroup(this);2892 this.assetManager = new MoonbeamAssetManagerGroup(this);2893 this.assets = new AssetsGroup(this);2894 this.xTokens = new XTokensGroup(this);2895 this.democracy = new MoonbeamDemocracyGroup(this);2896 this.collective = {2897 council: new MoonbeamCollectiveGroup(this, 'councilCollective'),2898 techCommittee: new MoonbeamCollectiveGroup(this, 'techCommitteeCollective'),2899 };2900 }2901}29022903export class AcalaHelper extends XcmChainHelper {2904 balance: SubstrateBalanceGroup<AcalaHelper>;2905 assetRegistry: AcalaAssetRegistryGroup;2906 xTokens: XTokensGroup<AcalaHelper>;2907 tokens: TokensGroup<AcalaHelper>;29082909 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2910 super(logger, options.helperBase ?? AcalaHelper);29112912 this.balance = new SubstrateBalanceGroup(this);2913 this.assetRegistry = new AcalaAssetRegistryGroup(this);2914 this.xTokens = new XTokensGroup(this);2915 this.tokens = new TokensGroup(this);2916 }29172918 getSudo<T extends AcalaHelper>() {2919 // eslint-disable-next-line @typescript-eslint/naming-convention2920 const SudoHelperType = SudoHelper(this.helperBase);2921 return this.clone(SudoHelperType) as T;2922 }2923}29242925// eslint-disable-next-line @typescript-eslint/naming-convention2926function ScheduledUniqueHelper<T extends UniqueHelperConstructor>(Base: T) {2927 return class extends Base {2928 scheduleFn: 'schedule' | 'scheduleAfter';2929 blocksNum: number;2930 options: ISchedulerOptions;29312932 constructor(...args: any[]) {2933 const logger = args[0] as ILogger;2934 const options = args[1] as {2935 scheduleFn: 'schedule' | 'scheduleAfter',2936 blocksNum: number,2937 options: ISchedulerOptions2938 };29392940 super(logger);29412942 this.scheduleFn = options.scheduleFn;2943 this.blocksNum = options.blocksNum;2944 this.options = options.options;2945 }29462947 executeExtrinsic(sender: IKeyringPair, scheduledExtrinsic: string, scheduledParams: any[], expectSuccess?: boolean): Promise<ITransactionResult> {2948 const scheduledTx = this.constructApiCall(scheduledExtrinsic, scheduledParams);2949 2950 const mandatorySchedArgs = [2951 this.blocksNum,2952 this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null,2953 this.options.priority ?? null,2954 scheduledTx,2955 ];2956 2957 let schedArgs;2958 let scheduleFn;29592960 if (this.options.scheduledId) {2961 schedArgs = [this.options.scheduledId!, ...mandatorySchedArgs];29622963 if (this.scheduleFn == 'schedule') {2964 scheduleFn = 'scheduleNamed';2965 } else if (this.scheduleFn == 'scheduleAfter') {2966 scheduleFn = 'scheduleNamedAfter';2967 }2968 } else {2969 schedArgs = mandatorySchedArgs;2970 scheduleFn = this.scheduleFn;2971 }29722973 const extrinsic = 'api.tx.scheduler.' + scheduleFn;29742975 return super.executeExtrinsic(2976 sender,2977 extrinsic,2978 schedArgs,2979 expectSuccess,2980 );2981 }2982 };2983}29842985// eslint-disable-next-line @typescript-eslint/naming-convention2986function SudoHelper<T extends ChainHelperBaseConstructor>(Base: T) {2987 return class extends Base {2988 constructor(...args: any[]) {2989 super(...args);2990 }29912992 executeExtrinsic (2993 sender: IKeyringPair,2994 extrinsic: string,2995 params: any[],2996 expectSuccess?: boolean,2997 ): Promise<ITransactionResult> {2998 const call = this.constructApiCall(extrinsic, params);2999 return super.executeExtrinsic(3000 sender,3001 'api.tx.sudo.sudo',3002 [call],3003 expectSuccess,3004 );3005 }3006 };3007}30083009export class UniqueBaseCollection {3010 helper: UniqueHelper;3011 collectionId: number;30123013 constructor(collectionId: number, uniqueHelper: UniqueHelper) {3014 this.collectionId = collectionId;3015 this.helper = uniqueHelper;3016 }30173018 async getData() {3019 return await this.helper.collection.getData(this.collectionId);3020 }30213022 async getLastTokenId() {3023 return await this.helper.collection.getLastTokenId(this.collectionId);3024 }30253026 async doesTokenExist(tokenId: number) {3027 return await this.helper.collection.doesTokenExist(this.collectionId, tokenId);3028 }30293030 async getAdmins() {3031 return await this.helper.collection.getAdmins(this.collectionId);3032 }30333034 async getAllowList() {3035 return await this.helper.collection.getAllowList(this.collectionId);3036 }30373038 async getEffectiveLimits() {3039 return await this.helper.collection.getEffectiveLimits(this.collectionId);3040 }30413042 async getProperties(propertyKeys?: string[] | null) {3043 return await this.helper.collection.getProperties(this.collectionId, propertyKeys);3044 }30453046 async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) {3047 return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj);3048 }30493050 async getOptions() {3051 return await this.helper.collection.getCollectionOptions(this.collectionId);3052 }30533054 async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) {3055 return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress);3056 }30573058 async confirmSponsorship(signer: TSigner) {3059 return await this.helper.collection.confirmSponsorship(signer, this.collectionId);3060 }30613062 async removeSponsor(signer: TSigner) {3063 return await this.helper.collection.removeSponsor(signer, this.collectionId);3064 }30653066 async setLimits(signer: TSigner, limits: ICollectionLimits) {3067 return await this.helper.collection.setLimits(signer, this.collectionId, limits);3068 }30693070 async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount) {3071 return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress);3072 }30733074 async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3075 return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj);3076 }30773078 async addToAllowList(signer: TSigner, addressObj: ICrossAccountId) {3079 return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj);3080 }30813082 async removeFromAllowList(signer: TSigner, addressObj: ICrossAccountId) {3083 return await this.helper.collection.removeFromAllowList(signer, this.collectionId, addressObj);3084 }30853086 async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3087 return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj);3088 }30893090 async setProperties(signer: TSigner, properties: IProperty[]) {3091 return await this.helper.collection.setProperties(signer, this.collectionId, properties);3092 }30933094 async deleteProperties(signer: TSigner, propertyKeys: string[]) {3095 return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys);3096 }30973098 async setPermissions(signer: TSigner, permissions: ICollectionPermissions) {3099 return await this.helper.collection.setPermissions(signer, this.collectionId, permissions);3100 }31013102 async enableNesting(signer: TSigner, permissions: INestingPermissions) {3103 return await this.helper.collection.enableNesting(signer, this.collectionId, permissions);3104 }31053106 async disableNesting(signer: TSigner) {3107 return await this.helper.collection.disableNesting(signer, this.collectionId);3108 }31093110 async burn(signer: TSigner) {3111 return await this.helper.collection.burn(signer, this.collectionId);3112 }31133114 scheduleAt<T extends UniqueHelper>(3115 executionBlockNumber: number,3116 options: ISchedulerOptions = {},3117 ) {3118 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3119 return new UniqueBaseCollection(this.collectionId, scheduledHelper);3120 }31213122 scheduleAfter<T extends UniqueHelper>(3123 blocksBeforeExecution: number,3124 options: ISchedulerOptions = {},3125 ) {3126 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3127 return new UniqueBaseCollection(this.collectionId, scheduledHelper);3128 }31293130 getSudo<T extends UniqueHelper>() {3131 return new UniqueBaseCollection(this.collectionId, this.helper.getSudo<T>());3132 }3133}313431353136export class UniqueNFTCollection extends UniqueBaseCollection {3137 getTokenObject(tokenId: number) {3138 return new UniqueNFToken(tokenId, this);3139 }31403141 async getTokensByAddress(addressObj: ICrossAccountId) {3142 return await this.helper.nft.getTokensByAddress(this.collectionId, addressObj);3143 }31443145 async getToken(tokenId: number, blockHashAt?: string) {3146 return await this.helper.nft.getToken(this.collectionId, tokenId, [], blockHashAt);3147 }31483149 async getTokenOwner(tokenId: number, blockHashAt?: string) {3150 return await this.helper.nft.getTokenOwner(this.collectionId, tokenId, blockHashAt);3151 }31523153 async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {3154 return await this.helper.nft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);3155 }31563157 async getTokenChildren(tokenId: number, blockHashAt?: string) {3158 return await this.helper.nft.getTokenChildren(this.collectionId, tokenId, blockHashAt);3159 }31603161 async getPropertyPermissions(propertyKeys: string[] | null = null) {3162 return await this.helper.nft.getPropertyPermissions(this.collectionId, propertyKeys);3163 }31643165 async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3166 return await this.helper.nft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3167 }31683169 async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId) {3170 return await this.helper.nft.transferToken(signer, this.collectionId, tokenId, addressObj);3171 }31723173 async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3174 return await this.helper.nft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj);3175 }31763177 async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId) {3178 return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj);3179 }31803181 async isTokenApproved(tokenId: number, toAddressObj: ICrossAccountId) {3182 return await this.helper.nft.isTokenApproved(this.collectionId, tokenId, toAddressObj);3183 }31843185 async mintToken(signer: TSigner, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3186 return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties});3187 }31883189 async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]) {3190 return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens);3191 }31923193 async burnToken(signer: TSigner, tokenId: number) {3194 return await this.helper.nft.burnToken(signer, this.collectionId, tokenId);3195 }31963197 async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId) {3198 return await this.helper.nft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj);3199 }32003201 async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3202 return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties);3203 }32043205 async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3206 return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3207 }32083209 async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3210 return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3211 }32123213 async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {3214 return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);3215 }32163217 async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3218 return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);3219 }32203221 scheduleAt<T extends UniqueHelper>(3222 executionBlockNumber: number,3223 options: ISchedulerOptions = {},3224 ) {3225 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3226 return new UniqueNFTCollection(this.collectionId, scheduledHelper);3227 }32283229 scheduleAfter<T extends UniqueHelper>(3230 blocksBeforeExecution: number,3231 options: ISchedulerOptions = {},3232 ) {3233 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3234 return new UniqueNFTCollection(this.collectionId, scheduledHelper);3235 }32363237 getSudo<T extends UniqueHelper>() {3238 return new UniqueNFTCollection(this.collectionId, this.helper.getSudo<T>());3239 }3240}324132423243export class UniqueRFTCollection extends UniqueBaseCollection {3244 getTokenObject(tokenId: number) {3245 return new UniqueRFToken(tokenId, this);3246 }32473248 async getToken(tokenId: number, blockHashAt?: string) {3249 return await this.helper.rft.getToken(this.collectionId, tokenId, [], blockHashAt);3250 }32513252 async getTokensByAddress(addressObj: ICrossAccountId) {3253 return await this.helper.rft.getTokensByAddress(this.collectionId, addressObj);3254 }32553256 async getTop10TokenOwners(tokenId: number) {3257 return await this.helper.rft.getTokenTop10Owners(this.collectionId, tokenId);3258 }32593260 async getTokenBalance(tokenId: number, addressObj: ICrossAccountId) {3261 return await this.helper.rft.getTokenBalance(this.collectionId, tokenId, addressObj);3262 }32633264 async getTokenTotalPieces(tokenId: number) {3265 return await this.helper.rft.getTokenTotalPieces(this.collectionId, tokenId);3266 }32673268 async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3269 return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj);3270 }32713272 async getPropertyPermissions(propertyKeys: string[] | null = null) {3273 return await this.helper.rft.getPropertyPermissions(this.collectionId, propertyKeys);3274 }32753276 async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3277 return await this.helper.rft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3278 }32793280 async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount=1n) {3281 return await this.helper.rft.transferToken(signer, this.collectionId, tokenId, addressObj, amount);3282 }32833284 async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3285 return await this.helper.rft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj, amount);3286 }32873288 async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {3289 return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, amount);3290 }32913292 async repartitionToken(signer: TSigner, tokenId: number, amount: bigint) {3293 return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount);3294 }32953296 async mintToken(signer: TSigner, pieces=1n, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3297 return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties});3298 }32993300 async mintMultipleTokens(signer: TSigner, tokens: {pieces: bigint, owner: ICrossAccountId, properties?: IProperty[]}[]) {3301 return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens);3302 }33033304 async burnToken(signer: TSigner, tokenId: number, amount=1n) {3305 return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, amount);3306 }33073308 async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n) {3309 return await this.helper.rft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, amount);3310 }33113312 async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3313 return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties);3314 }33153316 async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3317 return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3318 }33193320 async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3321 return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3322 }33233324 scheduleAt<T extends UniqueHelper>(3325 executionBlockNumber: number,3326 options: ISchedulerOptions = {},3327 ) {3328 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3329 return new UniqueRFTCollection(this.collectionId, scheduledHelper);3330 }33313332 scheduleAfter<T extends UniqueHelper>(3333 blocksBeforeExecution: number,3334 options: ISchedulerOptions = {},3335 ) {3336 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3337 return new UniqueRFTCollection(this.collectionId, scheduledHelper);3338 }33393340 getSudo<T extends UniqueHelper>() {3341 return new UniqueRFTCollection(this.collectionId, this.helper.getSudo<T>());3342 }3343}334433453346export class UniqueFTCollection extends UniqueBaseCollection {3347 async getBalance(addressObj: ICrossAccountId) {3348 return await this.helper.ft.getBalance(this.collectionId, addressObj);3349 }33503351 async getTotalPieces() {3352 return await this.helper.ft.getTotalPieces(this.collectionId);3353 }33543355 async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3356 return await this.helper.ft.getApprovedTokens(this.collectionId, fromAddressObj, toAddressObj);3357 }33583359 async getTop10Owners() {3360 return await this.helper.ft.getTop10Owners(this.collectionId);3361 }33623363 async mint(signer: TSigner, amount=1n, owner: ICrossAccountId = {Substrate: signer.address}) {3364 return await this.helper.ft.mintTokens(signer, this.collectionId, amount, owner);3365 }33663367 async mintWithOneOwner(signer: TSigner, tokens: {value: bigint}[], owner: ICrossAccountId = {Substrate: signer.address}) {3368 return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, tokens, owner);3369 }33703371 async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3372 return await this.helper.ft.transfer(signer, this.collectionId, toAddressObj, amount);3373 }33743375 async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3376 return await this.helper.ft.transferFrom(signer, this.collectionId, fromAddressObj, toAddressObj, amount);3377 }33783379 async burnTokens(signer: TSigner, amount=1n) {3380 return await this.helper.ft.burnTokens(signer, this.collectionId, amount);3381 }33823383 async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {3384 return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount);3385 }33863387 async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3388 return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);3389 }33903391 scheduleAt<T extends UniqueHelper>(3392 executionBlockNumber: number,3393 options: ISchedulerOptions = {},3394 ) {3395 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3396 return new UniqueFTCollection(this.collectionId, scheduledHelper);3397 }33983399 scheduleAfter<T extends UniqueHelper>(3400 blocksBeforeExecution: number,3401 options: ISchedulerOptions = {},3402 ) {3403 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3404 return new UniqueFTCollection(this.collectionId, scheduledHelper);3405 }34063407 getSudo<T extends UniqueHelper>() {3408 return new UniqueFTCollection(this.collectionId, this.helper.getSudo<T>());3409 }3410}341134123413export class UniqueBaseToken {3414 collection: UniqueNFTCollection | UniqueRFTCollection;3415 collectionId: number;3416 tokenId: number;34173418 constructor(tokenId: number, collection: UniqueNFTCollection | UniqueRFTCollection) {3419 this.collection = collection;3420 this.collectionId = collection.collectionId;3421 this.tokenId = tokenId;3422 }34233424 async getNextSponsored(addressObj: ICrossAccountId) {3425 return await this.collection.getTokenNextSponsored(this.tokenId, addressObj);3426 }34273428 async getProperties(propertyKeys?: string[] | null) {3429 return await this.collection.getTokenProperties(this.tokenId, propertyKeys);3430 }34313432 async setProperties(signer: TSigner, properties: IProperty[]) {3433 return await this.collection.setTokenProperties(signer, this.tokenId, properties);3434 }34353436 async deleteProperties(signer: TSigner, propertyKeys: string[]) {3437 return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys);3438 }34393440 async doesExist() {3441 return await this.collection.doesTokenExist(this.tokenId);3442 }34433444 nestingAccount() {3445 return this.collection.helper.util.getTokenAccount(this);3446 }34473448 scheduleAt<T extends UniqueHelper>(3449 executionBlockNumber: number,3450 options: ISchedulerOptions = {},3451 ) {3452 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3453 return new UniqueBaseToken(this.tokenId, scheduledCollection);3454 }34553456 scheduleAfter<T extends UniqueHelper>(3457 blocksBeforeExecution: number,3458 options: ISchedulerOptions = {},3459 ) {3460 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3461 return new UniqueBaseToken(this.tokenId, scheduledCollection);3462 }34633464 getSudo<T extends UniqueHelper>() {3465 return new UniqueBaseToken(this.tokenId, this.collection.getSudo<T>());3466 }3467}346834693470export class UniqueNFToken extends UniqueBaseToken {3471 collection: UniqueNFTCollection;34723473 constructor(tokenId: number, collection: UniqueNFTCollection) {3474 super(tokenId, collection);3475 this.collection = collection;3476 }34773478 async getData(blockHashAt?: string) {3479 return await this.collection.getToken(this.tokenId, blockHashAt);3480 }34813482 async getOwner(blockHashAt?: string) {3483 return await this.collection.getTokenOwner(this.tokenId, blockHashAt);3484 }34853486 async getTopmostOwner(blockHashAt?: string) {3487 return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);3488 }34893490 async getChildren(blockHashAt?: string) {3491 return await this.collection.getTokenChildren(this.tokenId, blockHashAt);3492 }34933494 async nest(signer: TSigner, toTokenObj: IToken) {3495 return await this.collection.nestToken(signer, this.tokenId, toTokenObj);3496 }34973498 async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3499 return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);3500 }35013502 async transfer(signer: TSigner, addressObj: ICrossAccountId) {3503 return await this.collection.transferToken(signer, this.tokenId, addressObj);3504 }35053506 async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3507 return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj);3508 }35093510 async approve(signer: TSigner, toAddressObj: ICrossAccountId) {3511 return await this.collection.approveToken(signer, this.tokenId, toAddressObj);3512 }35133514 async isApproved(toAddressObj: ICrossAccountId) {3515 return await this.collection.isTokenApproved(this.tokenId, toAddressObj);3516 }35173518 async burn(signer: TSigner) {3519 return await this.collection.burnToken(signer, this.tokenId);3520 }35213522 async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId) {3523 return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj);3524 }35253526 scheduleAt<T extends UniqueHelper>(3527 executionBlockNumber: number,3528 options: ISchedulerOptions = {},3529 ) {3530 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3531 return new UniqueNFToken(this.tokenId, scheduledCollection);3532 }35333534 scheduleAfter<T extends UniqueHelper>(3535 blocksBeforeExecution: number,3536 options: ISchedulerOptions = {},3537 ) {3538 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3539 return new UniqueNFToken(this.tokenId, scheduledCollection);3540 }35413542 getSudo<T extends UniqueHelper>() {3543 return new UniqueNFToken(this.tokenId, this.collection.getSudo<T>());3544 }3545}35463547export class UniqueRFToken extends UniqueBaseToken {3548 collection: UniqueRFTCollection;35493550 constructor(tokenId: number, collection: UniqueRFTCollection) {3551 super(tokenId, collection);3552 this.collection = collection;3553 }35543555 async getData(blockHashAt?: string) {3556 return await this.collection.getToken(this.tokenId, blockHashAt);3557 }35583559 async getTop10Owners() {3560 return await this.collection.getTop10TokenOwners(this.tokenId);3561 }35623563 async getBalance(addressObj: ICrossAccountId) {3564 return await this.collection.getTokenBalance(this.tokenId, addressObj);3565 }35663567 async getTotalPieces() {3568 return await this.collection.getTokenTotalPieces(this.tokenId);3569 }35703571 async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) {3572 return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj);3573 }35743575 async transfer(signer: TSigner, addressObj: ICrossAccountId, amount=1n) {3576 return await this.collection.transferToken(signer, this.tokenId, addressObj, amount);3577 }35783579 async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3580 return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj, amount);3581 }35823583 async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3584 return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount);3585 }35863587 async repartition(signer: TSigner, amount: bigint) {3588 return await this.collection.repartitionToken(signer, this.tokenId, amount);3589 }35903591 async burn(signer: TSigner, amount=1n) {3592 return await this.collection.burnToken(signer, this.tokenId, amount);3593 }35943595 async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {3596 return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj, amount);3597 }35983599 scheduleAt<T extends UniqueHelper>(3600 executionBlockNumber: number,3601 options: ISchedulerOptions = {},3602 ) {3603 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3604 return new UniqueRFToken(this.tokenId, scheduledCollection);3605 }36063607 scheduleAfter<T extends UniqueHelper>(3608 blocksBeforeExecution: number,3609 options: ISchedulerOptions = {},3610 ) {3611 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3612 return new UniqueRFToken(this.tokenId, scheduledCollection);3613 }36143615 getSudo<T extends UniqueHelper>() {3616 return new UniqueRFToken(this.tokenId, this.collection.getSudo<T>());3617 }3618}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034/* eslint-disable @typescript-eslint/no-var-requires */5/* eslint-disable function-call-argument-newline */6/* eslint-disable no-prototype-builtins */78import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';9import {ApiInterfaceEvents, SignerOptions} from '@polkadot/api/types';10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto';11import {IKeyringPair} from '@polkadot/types/types';12import {hexToU8a} from '@polkadot/util/hex';13import {u8aConcat} from '@polkadot/util/u8a';14import {15 IApiListeners,16 IBlock,17 IEvent,18 IChainProperties,19 ICollectionCreationOptions,20 ICollectionLimits,21 ICollectionPermissions,22 ICrossAccountId,23 ICrossAccountIdLower,24 ILogger,25 INestingPermissions,26 IProperty,27 IStakingInfo,28 ISchedulerOptions,29 ISubstrateBalance,30 IToken,31 ITokenPropertyPermission,32 ITransactionResult,33 IUniqueHelperLog,34 TApiAllowedListeners,35 TEthereumAccount,36 TSigner,37 TSubstrateAccount,38 TNetworks,39 IForeignAssetMetadata,40 AcalaAssetMetadata,41 MoonbeamAssetInfo,42 DemocracyStandardAccountVote,43 IEthCrossAccountId,44} from './types';45import {RuntimeDispatchInfo} from '@polkadot/types/interfaces';4647export class CrossAccountId implements ICrossAccountId {48 Substrate?: TSubstrateAccount;49 Ethereum?: TEthereumAccount;5051 constructor(account: ICrossAccountId) {52 if (account.Substrate) this.Substrate = account.Substrate;53 if (account.Ethereum) this.Ethereum = account.Ethereum;54 }5556 static fromKeyring(account: IKeyringPair, domain: 'Substrate' | 'Ethereum' = 'Substrate') {57 switch (domain) {58 case 'Substrate': return new CrossAccountId({Substrate: account.address});59 case 'Ethereum': return new CrossAccountId({Substrate: account.address}).toEthereum();60 }61 }6263 static fromLowerCaseKeys(address: ICrossAccountIdLower): CrossAccountId {64 return new CrossAccountId({Substrate: address.substrate, Ethereum: address.ethereum});65 }6667 static normalizeSubstrateAddress(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {68 return encodeAddress(decodeAddress(address), ss58Format);69 }7071 static withNormalizedSubstrate(address: TSubstrateAccount, ss58Format = 42): CrossAccountId {72 return new CrossAccountId({Substrate: CrossAccountId.normalizeSubstrateAddress(address, ss58Format)});73 }7475 withNormalizedSubstrate(ss58Format = 42): CrossAccountId {76 if (this.Substrate) return CrossAccountId.withNormalizedSubstrate(this.Substrate, ss58Format);77 return this;78 }7980 static translateSubToEth(address: TSubstrateAccount): TEthereumAccount {81 return nesting.toChecksumAddress('0x' + Array.from(addressToEvm(address), i => i.toString(16).padStart(2, '0')).join(''));82 }8384 toEthereum(): CrossAccountId {85 if (this.Substrate) return new CrossAccountId({Ethereum: CrossAccountId.translateSubToEth(this.Substrate)});86 return this;87 }8889 static translateEthToSub(address: TEthereumAccount, ss58Format?: number): TSubstrateAccount {90 return evmToAddress(address, ss58Format);91 }9293 toSubstrate(ss58Format?: number): CrossAccountId {94 if (this.Ethereum) return new CrossAccountId({Substrate: CrossAccountId.translateEthToSub(this.Ethereum, ss58Format)});95 return this;96 }9798 toLowerCase(): CrossAccountId {99 if (this.Substrate) this.Substrate = this.Substrate.toLowerCase();100 if (this.Ethereum) this.Ethereum = this.Ethereum.toLowerCase();101 return this;102 }103}104105const nesting = {106 toChecksumAddress(address: string): string {107 if (typeof address === 'undefined') return '';108109 if(!/^(0x)?[0-9a-f]{40}$/i.test(address)) throw new Error(`Given address "${address}" is not a valid Ethereum address.`);110111 address = address.toLowerCase().replace(/^0x/i,'');112 const addressHash = keccakAsHex(address).replace(/^0x/i,'');113 const checksumAddress = ['0x'];114115 for (let i = 0; i < address.length; i++) {116 // If ith character is 8 to f then make it uppercase117 if (parseInt(addressHash[i], 16) > 7) {118 checksumAddress.push(address[i].toUpperCase());119 } else {120 checksumAddress.push(address[i]);121 }122 }123 return checksumAddress.join('');124 },125 tokenIdToAddress(collectionId: number, tokenId: number) {126 return this.toChecksumAddress(`0xf8238ccfff8ed887463fd5e0${collectionId.toString(16).padStart(8,'0')}${tokenId.toString(16).padStart(8,'0')}`);127 },128};129130class UniqueUtil {131 static transactionStatus = {132 NOT_READY: 'NotReady',133 FAIL: 'Fail',134 SUCCESS: 'Success',135 };136137 static chainLogType = {138 EXTRINSIC: 'extrinsic',139 RPC: 'rpc',140 };141142 static getTokenAccount(token: IToken): CrossAccountId {143 return new CrossAccountId({Ethereum: this.getTokenAddress(token)});144 }145146 static getTokenAddress(token: IToken): string {147 return nesting.tokenIdToAddress(token.collectionId, token.tokenId);148 }149150 static getDefaultLogger(): ILogger {151 return {152 log(msg: any, level = 'INFO') {153 console[level.toLocaleLowerCase() === 'error' ? 'error' : 'log'](...(Array.isArray(msg) ? msg : [msg]));154 },155 level: {156 ERROR: 'ERROR',157 WARNING: 'WARNING',158 INFO: 'INFO',159 },160 };161 }162163 static vec2str(arr: string[] | number[]) {164 return arr.map(x => String.fromCharCode(parseInt(x.toString()))).join('');165 }166167 static str2vec(string: string) {168 if (typeof string !== 'string') return string;169 return Array.from(string).map(x => x.charCodeAt(0));170 }171172 static fromSeed(seed: string, ss58Format = 42) {173 const keyring = new Keyring({type: 'sr25519', ss58Format});174 return keyring.addFromUri(seed);175 }176177 static extractCollectionIdFromCreationResult(creationResult: ITransactionResult): number {178 if (creationResult.status !== this.transactionStatus.SUCCESS) {179 throw Error('Unable to create collection!');180 }181182 let collectionId = null;183 creationResult.result.events.forEach(({event: {data, method, section}}) => {184 if ((section === 'common') && (method === 'CollectionCreated')) {185 collectionId = parseInt(data[0].toString(), 10);186 }187 });188189 if (collectionId === null) {190 throw Error('No CollectionCreated event was found!');191 }192193 return collectionId;194 }195196 static extractTokensFromCreationResult(creationResult: ITransactionResult): {197 success: boolean,198 tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[],199 } {200 if (creationResult.status !== this.transactionStatus.SUCCESS) {201 throw Error('Unable to create tokens!');202 }203 let success = false;204 const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[];205 creationResult.result.events.forEach(({event: {data, method, section}}) => {206 if (method === 'ExtrinsicSuccess') {207 success = true;208 } else if ((section === 'common') && (method === 'ItemCreated')) {209 tokens.push({210 collectionId: parseInt(data[0].toString(), 10),211 tokenId: parseInt(data[1].toString(), 10),212 owner: data[2].toHuman(),213 amount: data[3].toBigInt(),214 });215 }216 });217 return {success, tokens};218 }219220 static extractTokensFromBurnResult(burnResult: ITransactionResult): {221 success: boolean,222 tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[],223 } {224 if (burnResult.status !== this.transactionStatus.SUCCESS) {225 throw Error('Unable to burn tokens!');226 }227 let success = false;228 const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[];229 burnResult.result.events.forEach(({event: {data, method, section}}) => {230 if (method === 'ExtrinsicSuccess') {231 success = true;232 } else if ((section === 'common') && (method === 'ItemDestroyed')) {233 tokens.push({234 collectionId: parseInt(data[0].toString(), 10),235 tokenId: parseInt(data[1].toString(), 10),236 owner: data[2].toHuman(),237 amount: data[3].toBigInt(),238 });239 }240 });241 return {success, tokens};242 }243244 static findCollectionInEvents(events: {event: IEvent}[], collectionId: number, expectedSection: string, expectedMethod: string): boolean {245 let eventId = null;246 events.forEach(({event: {data, method, section}}) => {247 if ((section === expectedSection) && (method === expectedMethod)) {248 eventId = parseInt(data[0].toString(), 10);249 }250 });251252 if (eventId === null) {253 throw Error(`No ${expectedMethod} event was found!`);254 }255 return eventId === collectionId;256 }257258 static isTokenTransferSuccess(events: {event: IEvent}[], collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {259 const normalizeAddress = (address: string | ICrossAccountId) => {260 if(typeof address === 'string') return address;261 const obj = {} as any;262 Object.keys(address).forEach(k => {263 obj[k.toLocaleLowerCase()] = address[k as 'Substrate' | 'Ethereum'];264 });265 if(obj.substrate) return CrossAccountId.withNormalizedSubstrate(obj.substrate);266 if(obj.ethereum) return CrossAccountId.fromLowerCaseKeys(obj).toLowerCase();267 return address;268 };269 let transfer = {collectionId: null, tokenId: null, from: null, to: null, amount: 1} as any;270 events.forEach(({event: {data, method, section}}) => {271 if ((section === 'common') && (method === 'Transfer')) {272 const hData = (data as any).toJSON();273 transfer = {274 collectionId: hData[0],275 tokenId: hData[1],276 from: normalizeAddress(hData[2]),277 to: normalizeAddress(hData[3]),278 amount: BigInt(hData[4]),279 };280 }281 });282 let isSuccess = parseInt(collectionId.toString()) === transfer.collectionId && parseInt(tokenId.toString()) === transfer.tokenId;283 isSuccess = isSuccess && JSON.stringify(normalizeAddress(fromAddressObj)) === JSON.stringify(transfer.from);284 isSuccess = isSuccess && JSON.stringify(normalizeAddress(toAddressObj)) === JSON.stringify(transfer.to);285 isSuccess = isSuccess && amount === transfer.amount;286 return isSuccess;287 }288289 static bigIntToDecimals(number: bigint, decimals = 18) {290 const numberStr = number.toString();291 const dotPos = numberStr.length - decimals;292293 if (dotPos <= 0) {294 return '0.' + '0'.repeat(Math.abs(dotPos)) + numberStr;295 } else {296 const intPart = numberStr.substring(0, dotPos);297 const fractPart = numberStr.substring(dotPos);298 return intPart + '.' + fractPart;299 }300 }301}302303class UniqueEventHelper {304 private static extractIndex(index: any): [number, number] | string {305 if(index.toRawType() === '[u8;2]') return [index[0], index[1]];306 return index.toJSON();307 }308309 private static extractSub(data: any, subTypes: any): {[key: string]: any} {310 let obj: any = {};311 let index = 0;312313 if (data.entries) {314 for(const [key, value] of data.entries()) {315 obj[key] = this.extractData(value, subTypes[index]);316 index++;317 }318 } else obj = data.toJSON();319320 return obj;321 }322323 private static extractData(data: any, type: any): any {324 if(!type) return data.toHuman();325 if (['u16', 'u32'].indexOf(type.type) > -1) return data.toNumber();326 if (['u64', 'u128', 'u256'].indexOf(type.type) > -1) return data.toBigInt();327 if(type.hasOwnProperty('sub')) return this.extractSub(data, type.sub);328 return data.toHuman();329 }330331 public static extractEvents(events: {event: any, phase: any}[]): IEvent[] {332 const parsedEvents: IEvent[] = [];333334 events.forEach((record) => {335 const {event, phase} = record;336 const types = event.typeDef;337338 const eventData: IEvent = {339 section: event.section.toString(),340 method: event.method.toString(),341 index: this.extractIndex(event.index),342 data: [],343 phase: phase.toJSON(),344 };345346 event.data.forEach((val: any, index: number) => {347 eventData.data.push(this.extractData(val, types[index]));348 });349350 parsedEvents.push(eventData);351 });352353 return parsedEvents;354 }355}356357export class ChainHelperBase {358 helperBase: any;359360 transactionStatus = UniqueUtil.transactionStatus;361 chainLogType = UniqueUtil.chainLogType;362 util: typeof UniqueUtil;363 eventHelper: typeof UniqueEventHelper;364 logger: ILogger;365 api: ApiPromise | null;366 forcedNetwork: TNetworks | null;367 network: TNetworks | null;368 chainLog: IUniqueHelperLog[];369 children: ChainHelperBase[];370 address: AddressGroup;371 chain: ChainGroup;372373 constructor(logger?: ILogger, helperBase?: any) {374 this.helperBase = helperBase;375376 this.util = UniqueUtil;377 this.eventHelper = UniqueEventHelper;378 if (typeof logger == 'undefined') logger = this.util.getDefaultLogger();379 this.logger = logger;380 this.api = null;381 this.forcedNetwork = null;382 this.network = null;383 this.chainLog = [];384 this.children = [];385 this.address = new AddressGroup(this);386 this.chain = new ChainGroup(this);387 }388389 clone(helperCls: ChainHelperBaseConstructor, options: {[key: string]: any} = {}) {390 Object.setPrototypeOf(helperCls.prototype, this);391 const newHelper = new helperCls(this.logger, options);392393 newHelper.api = this.api;394 newHelper.network = this.network;395 newHelper.forceNetwork = this.forceNetwork;396397 this.children.push(newHelper);398399 return newHelper;400 }401402 getApi(): ApiPromise {403 if(this.api === null) throw Error('API not initialized');404 return this.api;405 }406407 clearChainLog(): void {408 this.chainLog = [];409 }410411 forceNetwork(value: TNetworks): void {412 this.forcedNetwork = value;413 }414415 async connect(wsEndpoint: string, listeners?: IApiListeners) {416 if (this.api !== null) throw Error('Already connected');417 const {api, network} = await ChainHelperBase.createConnection(wsEndpoint, listeners, this.forcedNetwork);418 this.api = api;419 this.network = network;420 }421422 async disconnect() {423 for (const child of this.children) {424 child.clearApi();425 }426427 if (this.api === null) return;428 await this.api.disconnect();429 this.clearApi();430 }431432 clearApi() {433 this.api = null;434 this.network = null;435 }436437 static async detectNetwork(api: ApiPromise): Promise<TNetworks> {438 const spec = (await api.query.system.lastRuntimeUpgrade()).toJSON() as any;439 const xcmChains = ['rococo', 'westend', 'westmint', 'acala', 'karura', 'moonbeam', 'moonriver'];440441 if(xcmChains.indexOf(spec.specName) > -1) return spec.specName;442443 if(['quartz', 'unique'].indexOf(spec.specName) > -1) return spec.specName;444 return 'opal';445 }446447 static async detectNetworkByWsEndpoint(wsEndpoint: string): Promise<TNetworks> {448 const api = new ApiPromise({provider: new WsProvider(wsEndpoint)});449 await api.isReady;450451 const network = await this.detectNetwork(api);452453 await api.disconnect();454455 return network;456 }457458 static async createConnection(wsEndpoint: string, listeners?: IApiListeners, network?: TNetworks | null): Promise<{459 api: ApiPromise;460 network: TNetworks;461 }> {462 if(typeof network === 'undefined' || network === null) network = 'opal';463 const supportedRPC = {464 opal: {465 unique: require('@unique-nft/opal-testnet-types/definitions').unique.rpc,466 },467 quartz: {468 unique: require('@unique-nft/quartz-mainnet-types/definitions').unique.rpc,469 },470 unique: {471 unique: require('@unique-nft/unique-mainnet-types/definitions').unique.rpc,472 },473 rococo: {},474 westend: {},475 moonbeam: {},476 moonriver: {},477 acala: {},478 karura: {},479 westmint: {},480 };481 if(!supportedRPC.hasOwnProperty(network)) network = await this.detectNetworkByWsEndpoint(wsEndpoint);482 const rpc = supportedRPC[network];483484 // TODO: investigate how to replace rpc in runtime485 // api._rpcCore.addUserInterfaces(rpc);486487 const api = new ApiPromise({provider: new WsProvider(wsEndpoint), rpc});488489 await api.isReadyOrError;490491 if (typeof listeners === 'undefined') listeners = {};492 for (const event of ['connected', 'disconnected', 'error', 'ready', 'decorated']) {493 if (!listeners.hasOwnProperty(event) || typeof listeners[event as TApiAllowedListeners] === 'undefined') continue;494 api.on(event as ApiInterfaceEvents, listeners[event as TApiAllowedListeners] as (...args: any[]) => any);495 }496497 return {api, network};498 }499500 getTransactionStatus(data: {events: {event: IEvent}[], status: any}) {501 const {events, status} = data;502 if (status.isReady) {503 return this.transactionStatus.NOT_READY;504 }505 if (status.isBroadcast) {506 return this.transactionStatus.NOT_READY;507 }508 if (status.isInBlock || status.isFinalized) {509 const errors = events.filter(e => e.event.method === 'ExtrinsicFailed');510 if (errors.length > 0) {511 return this.transactionStatus.FAIL;512 }513 if (events.filter(e => e.event.method === 'ExtrinsicSuccess').length > 0) {514 return this.transactionStatus.SUCCESS;515 }516 }517518 return this.transactionStatus.FAIL;519 }520521 signTransaction(sender: TSigner, transaction: any, options: Partial<SignerOptions> | null = null, label = 'transaction') {522 const sign = (callback: any) => {523 if(options !== null) return transaction.signAndSend(sender, options, callback);524 return transaction.signAndSend(sender, callback);525 };526 // eslint-disable-next-line no-async-promise-executor527 return new Promise(async (resolve, reject) => {528 try {529 const unsub = await sign((result: any) => {530 const status = this.getTransactionStatus(result);531532 if (status === this.transactionStatus.SUCCESS) {533 this.logger.log(`${label} successful`);534 unsub();535 resolve({result, status});536 } else if (status === this.transactionStatus.FAIL) {537 let moduleError = null;538539 if (result.hasOwnProperty('dispatchError')) {540 const dispatchError = result['dispatchError'];541542 if (dispatchError) {543 if (dispatchError.isModule) {544 const modErr = dispatchError.asModule;545 const errorMeta = dispatchError.registry.findMetaError(modErr);546547 moduleError = `${errorMeta.section}.${errorMeta.name}`;548 } else {549 moduleError = dispatchError.toHuman();550 }551 } else {552 this.logger.log(result, this.logger.level.ERROR);553 }554 }555556 this.logger.log(`Something went wrong with ${label}. Status: ${status}`, this.logger.level.ERROR);557 unsub();558 reject({status, moduleError, result});559 }560 });561 } catch (e) {562 this.logger.log(e, this.logger.level.ERROR);563 reject(e);564 }565 });566 }567568 async getPaymentInfo(signer: TSigner, tx: any, len: number | null) {569 const api = this.getApi();570 const signingInfo = await api.derive.tx.signingInfo(signer.address);571572 // We need to sign the tx because573 // unsigned transactions does not have an inclusion fee574 tx.sign(signer, {575 blockHash: api.genesisHash,576 genesisHash: api.genesisHash,577 runtimeVersion: api.runtimeVersion,578 nonce: signingInfo.nonce,579 });580581 if (len === null) {582 return (await this.callRpc('api.rpc.payment.queryInfo', [tx.toHex()])) as RuntimeDispatchInfo;583 } else {584 return (await api.call.transactionPaymentApi.queryInfo(tx, len)) as RuntimeDispatchInfo;585 }586 }587588 constructApiCall(apiCall: string, params: any[]) {589 if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);590 let call = this.getApi() as any;591 for(const part of apiCall.slice(4).split('.')) {592 call = call[part];593 }594 return call(...params);595 }596597 async executeExtrinsic(sender: TSigner, extrinsic: string, params: any[], expectSuccess=true, options: Partial<SignerOptions>|null = null/*, failureMessage='expected success'*/) {598 if(this.api === null) throw Error('API not initialized');599 if(!extrinsic.startsWith('api.tx.')) throw Error(`${extrinsic} is not transaction`);600601 const startTime = (new Date()).getTime();602 let result: ITransactionResult;603 let events: IEvent[] = [];604 try {605 result = await this.signTransaction(sender, this.constructApiCall(extrinsic, params), options, extrinsic) as ITransactionResult;606 events = this.eventHelper.extractEvents(result.result.events);607 }608 catch(e) {609 if(!(e as object).hasOwnProperty('status')) throw e;610 result = e as ITransactionResult;611 }612613 const endTime = (new Date()).getTime();614615 const log = {616 executedAt: endTime,617 executionTime: endTime - startTime,618 type: this.chainLogType.EXTRINSIC,619 status: result.status,620 call: extrinsic,621 signer: this.getSignerAddress(sender),622 params,623 } as IUniqueHelperLog;624625 if(result.status !== this.transactionStatus.SUCCESS) {626 if (result.moduleError) log.moduleError = result.moduleError;627 else if (result.result.dispatchError) log.dispatchError = result.result.dispatchError;628 }629 if(events.length > 0) log.events = events;630631 this.chainLog.push(log);632633 if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) {634 if (result.moduleError) throw Error(`${result.moduleError}`);635 else if (result.result.dispatchError) throw Error(JSON.stringify(result.result.dispatchError));636 }637 return result;638 }639640 async callRpc(rpc: string, params?: any[]) {641 if(typeof params === 'undefined') params = [];642 if(this.api === null) throw Error('API not initialized');643 if(!rpc.startsWith('api.rpc.') && !rpc.startsWith('api.query.')) throw Error(`${rpc} is not RPC call`);644645 const startTime = (new Date()).getTime();646 let result;647 let error = null;648 const log = {649 type: this.chainLogType.RPC,650 call: rpc,651 params,652 } as IUniqueHelperLog;653654 try {655 result = await this.constructApiCall(rpc, params);656 }657 catch(e) {658 error = e;659 }660661 const endTime = (new Date()).getTime();662663 log.executedAt = endTime;664 log.status = (error === null ? this.transactionStatus.SUCCESS : this.transactionStatus.FAIL) as 'Fail' | 'Success';665 log.executionTime = endTime - startTime;666667 this.chainLog.push(log);668669 if(error !== null) throw error;670671 return result;672 }673674 getSignerAddress(signer: IKeyringPair | string): string {675 if(typeof signer === 'string') return signer;676 return signer.address;677 }678679 fetchAllPalletNames(): string[] {680 if(this.api === null) throw Error('API not initialized');681 return this.api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());682 }683684 fetchMissingPalletNames(requiredPallets: string[]): string[] {685 const palletNames = this.fetchAllPalletNames();686 return requiredPallets.filter(p => !palletNames.includes(p));687 }688}689690691class HelperGroup<T extends ChainHelperBase> {692 helper: T;693694 constructor(uniqueHelper: T) {695 this.helper = uniqueHelper;696 }697}698699700class CollectionGroup extends HelperGroup<UniqueHelper> {701 /**702 * Get number of blocks when sponsored transaction is available.703 *704 * @param collectionId ID of collection705 * @param tokenId ID of token706 * @param addressObj address for which the sponsorship is checked707 * @example await getTokenNextSponsored(1, 2, {Substrate: '5DfhbVfww7ThF8q6f3...'});708 * @returns number of blocks or null if sponsorship hasn't been set709 */710 async getTokenNextSponsored(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<number | null> {711 return (await this.helper.callRpc('api.rpc.unique.nextSponsored', [collectionId, addressObj, tokenId])).toJSON();712 }713714 /**715 * Get the number of created collections.716 *717 * @returns number of created collections718 */719 async getTotalCount(): Promise<number> {720 return (await this.helper.callRpc('api.rpc.unique.collectionStats')).created.toNumber();721 }722723 /**724 * Get information about the collection with additional data,725 * including the number of tokens it contains, its administrators,726 * the normalized address of the collection's owner, and decoded name and description.727 *728 * @param collectionId ID of collection729 * @example await getData(2)730 * @returns collection information object731 */732 async getData(collectionId: number): Promise<{733 id: number;734 name: string;735 description: string;736 tokensCount: number;737 admins: CrossAccountId[];738 normalizedOwner: TSubstrateAccount;739 raw: any740 } | null> {741 const collection = await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId]);742 const humanCollection = collection.toHuman(), collectionData = {743 id: collectionId, name: null, description: null, tokensCount: 0, admins: [],744 raw: humanCollection,745 } as any, jsonCollection = collection.toJSON();746 if (humanCollection === null) return null;747 collectionData.raw.limits = jsonCollection.limits;748 collectionData.raw.permissions = jsonCollection.permissions;749 collectionData.normalizedOwner = this.helper.address.normalizeSubstrate(collectionData.raw.owner);750 for (const key of ['name', 'description']) {751 collectionData[key] = this.helper.util.vec2str(humanCollection[key]);752 }753754 collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode))755 ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId)756 : 0;757 collectionData.admins = await this.getAdmins(collectionId);758759 return collectionData;760 }761762 /**763 * Get the addresses of the collection's administrators, optionally normalized.764 *765 * @param collectionId ID of collection766 * @param normalize whether to normalize the addresses to the default ss58 format767 * @example await getAdmins(1)768 * @returns array of administrators769 */770 async getAdmins(collectionId: number, normalize = false): Promise<CrossAccountId[]> {771 const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman();772773 return normalize774 ? admins.map((address: CrossAccountId) => address.withNormalizedSubstrate())775 : admins;776 }777778 /**779 * Get the addresses added to the collection allow-list, optionally normalized.780 * @param collectionId ID of collection781 * @param normalize whether to normalize the addresses to the default ss58 format782 * @example await getAllowList(1)783 * @returns array of allow-listed addresses784 */785 async getAllowList(collectionId: number, normalize = false): Promise<CrossAccountId[]> {786 const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman();787 return normalize788 ? allowListed.map((address: CrossAccountId) => address.withNormalizedSubstrate())789 : allowListed;790 }791792 /**793 * Get the effective limits of the collection instead of null for default values794 *795 * @param collectionId ID of collection796 * @example await getEffectiveLimits(2)797 * @returns object of collection limits798 */799 async getEffectiveLimits(collectionId: number): Promise<ICollectionLimits> {800 return (await this.helper.callRpc('api.rpc.unique.effectiveCollectionLimits', [collectionId])).toJSON();801 }802803 /**804 * Burns the collection if the signer has sufficient permissions and collection is empty.805 *806 * @param signer keyring of signer807 * @param collectionId ID of collection808 * @example await helper.collection.burn(aliceKeyring, 3);809 * @returns ```true``` if extrinsic success, otherwise ```false```810 */811 async burn(signer: TSigner, collectionId: number): Promise<boolean> {812 const result = await this.helper.executeExtrinsic(813 signer,814 'api.tx.unique.destroyCollection', [collectionId],815 true,816 );817818 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed');819 }820821 /**822 * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.823 *824 * @param signer keyring of signer825 * @param collectionId ID of collection826 * @param sponsorAddress Sponsor substrate address827 * @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")828 * @returns ```true``` if extrinsic success, otherwise ```false```829 */830 async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise<boolean> {831 const result = await this.helper.executeExtrinsic(832 signer,833 'api.tx.unique.setCollectionSponsor', [collectionId, sponsorAddress],834 true,835 );836837 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorSet');838 }839840 /**841 * Confirms consent to sponsor the collection on behalf of the signer.842 *843 * @param signer keyring of signer844 * @param collectionId ID of collection845 * @example confirmSponsorship(aliceKeyring, 10)846 * @returns ```true``` if extrinsic success, otherwise ```false```847 */848 async confirmSponsorship(signer: TSigner, collectionId: number): Promise<boolean> {849 const result = await this.helper.executeExtrinsic(850 signer,851 'api.tx.unique.confirmSponsorship', [collectionId],852 true,853 );854855 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'SponsorshipConfirmed');856 }857858 /**859 * Removes the sponsor of a collection, regardless if it consented or not.860 *861 * @param signer keyring of signer862 * @param collectionId ID of collection863 * @example removeSponsor(aliceKeyring, 10)864 * @returns ```true``` if extrinsic success, otherwise ```false```865 */866 async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {867 const result = await this.helper.executeExtrinsic(868 signer,869 'api.tx.unique.removeCollectionSponsor', [collectionId],870 true,871 );872873 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionSponsorRemoved');874 }875876 /**877 * Sets the limits of the collection. At least one limit must be specified for a correct call.878 *879 * @param signer keyring of signer880 * @param collectionId ID of collection881 * @param limits collection limits object882 * @example883 * await setLimits(884 * aliceKeyring,885 * 10,886 * {887 * sponsorTransferTimeout: 0,888 * ownerCanDestroy: false889 * }890 * )891 * @returns ```true``` if extrinsic success, otherwise ```false```892 */893 async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise<boolean> {894 const result = await this.helper.executeExtrinsic(895 signer,896 'api.tx.unique.setCollectionLimits', [collectionId, limits],897 true,898 );899900 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionLimitSet');901 }902903 /**904 * Changes the owner of the collection to the new Substrate address.905 *906 * @param signer keyring of signer907 * @param collectionId ID of collection908 * @param ownerAddress substrate address of new owner909 * @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")910 * @returns ```true``` if extrinsic success, otherwise ```false```911 */912 async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise<boolean> {913 const result = await this.helper.executeExtrinsic(914 signer,915 'api.tx.unique.changeCollectionOwner', [collectionId, ownerAddress],916 true,917 );918919 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionOwnedChanged');920 }921922 /**923 * Adds a collection administrator.924 *925 * @param signer keyring of signer926 * @param collectionId ID of collection927 * @param adminAddressObj Administrator address (substrate or ethereum)928 * @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})929 * @returns ```true``` if extrinsic success, otherwise ```false```930 */931 async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {932 const result = await this.helper.executeExtrinsic(933 signer,934 'api.tx.unique.addCollectionAdmin', [collectionId, adminAddressObj],935 true,936 );937938 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminAdded');939 }940941 /**942 * Removes a collection administrator.943 *944 * @param signer keyring of signer945 * @param collectionId ID of collection946 * @param adminAddressObj Administrator address (substrate or ethereum)947 * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})948 * @returns ```true``` if extrinsic success, otherwise ```false```949 */950 async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {951 const result = await this.helper.executeExtrinsic(952 signer,953 'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj],954 true,955 );956957 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionAdminRemoved');958 }959960 /**961 * Check if user is in allow list.962 *963 * @param collectionId ID of collection964 * @param user Account to check965 * @example await getAdmins(1)966 * @returns is user in allow list967 */968 async allowed(collectionId: number, user: ICrossAccountId): Promise<boolean> {969 return (await this.helper.callRpc('api.rpc.unique.allowed', [collectionId, user])).toJSON();970 }971972 /**973 * Adds an address to allow list974 * @param signer keyring of signer975 * @param collectionId ID of collection976 * @param addressObj address to add to the allow list977 * @returns ```true``` if extrinsic success, otherwise ```false```978 */979 async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {980 const result = await this.helper.executeExtrinsic(981 signer,982 'api.tx.unique.addToAllowList', [collectionId, addressObj],983 true,984 );985986 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressAdded');987 }988989 /**990 * Removes an address from allow list991 *992 * @param signer keyring of signer993 * @param collectionId ID of collection994 * @param addressObj address to remove from the allow list995 * @returns ```true``` if extrinsic success, otherwise ```false```996 */997 async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {998 const result = await this.helper.executeExtrinsic(999 signer,1000 'api.tx.unique.removeFromAllowList', [collectionId, addressObj],1001 true,1002 );10031004 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'AllowListAddressRemoved');1005 }10061007 /**1008 * Sets onchain permissions for selected collection.1009 *1010 * @param signer keyring of signer1011 * @param collectionId ID of collection1012 * @param permissions collection permissions object1013 * @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}});1014 * @returns ```true``` if extrinsic success, otherwise ```false```1015 */1016 async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise<boolean> {1017 const result = await this.helper.executeExtrinsic(1018 signer,1019 'api.tx.unique.setCollectionPermissions', [collectionId, permissions],1020 true,1021 );10221023 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'unique', 'CollectionPermissionSet');1024 }10251026 /**1027 * Enables nesting for selected collection. If `restricted` set, you can nest only tokens from specified collections.1028 *1029 * @param signer keyring of signer1030 * @param collectionId ID of collection1031 * @param permissions nesting permissions object1032 * @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true});1033 * @returns ```true``` if extrinsic success, otherwise ```false```1034 */1035 async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise<boolean> {1036 return await this.setPermissions(signer, collectionId, {nesting: permissions});1037 }10381039 /**1040 * Disables nesting for selected collection.1041 *1042 * @param signer keyring of signer1043 * @param collectionId ID of collection1044 * @example disableNesting(aliceKeyring, 10);1045 * @returns ```true``` if extrinsic success, otherwise ```false```1046 */1047 async disableNesting(signer: TSigner, collectionId: number): Promise<boolean> {1048 return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}});1049 }10501051 /**1052 * Sets onchain properties to the collection.1053 *1054 * @param signer keyring of signer1055 * @param collectionId ID of collection1056 * @param properties array of property objects1057 * @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]);1058 * @returns ```true``` if extrinsic success, otherwise ```false```1059 */1060 async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise<boolean> {1061 const result = await this.helper.executeExtrinsic(1062 signer,1063 'api.tx.unique.setCollectionProperties', [collectionId, properties],1064 true,1065 );10661067 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');1068 }10691070 /**1071 * Get collection properties.1072 *1073 * @param collectionId ID of collection1074 * @param propertyKeys optionally filter the returned properties to only these keys1075 * @example getProperties(1219, ['location', 'date', 'time', 'isParadise']);1076 * @returns array of key-value pairs1077 */1078 async getProperties(collectionId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1079 return (await this.helper.callRpc('api.rpc.unique.collectionProperties', [collectionId, propertyKeys])).toHuman();1080 }10811082 async getCollectionOptions(collectionId: number) {1083 return (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1084 }10851086 /**1087 * Deletes onchain properties from the collection.1088 *1089 * @param signer keyring of signer1090 * @param collectionId ID of collection1091 * @param propertyKeys array of property keys to delete1092 * @example deleteProperties(aliceKeyring, 10, ["gender", "age"]);1093 * @returns ```true``` if extrinsic success, otherwise ```false```1094 */1095 async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise<boolean> {1096 const result = await this.helper.executeExtrinsic(1097 signer,1098 'api.tx.unique.deleteCollectionProperties', [collectionId, propertyKeys],1099 true,1100 );11011102 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted');1103 }11041105 /**1106 * Changes the owner of the token.1107 *1108 * @param signer keyring of signer1109 * @param collectionId ID of collection1110 * @param tokenId ID of token1111 * @param addressObj address of a new owner1112 * @param amount amount of tokens to be transfered. For NFT must be set to 1n1113 * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1114 * @returns true if the token success, otherwise false1115 */1116 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {1117 const result = await this.helper.executeExtrinsic(1118 signer,1119 'api.tx.unique.transfer', [addressObj, collectionId, tokenId, amount],1120 true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1121 );11221123 return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount);1124 }11251126 /**1127 *1128 * Change ownership of a token(s) on behalf of the owner.1129 *1130 * @param signer keyring of signer1131 * @param collectionId ID of collection1132 * @param tokenId ID of token1133 * @param fromAddressObj address on behalf of which the token will be sent1134 * @param toAddressObj new token owner1135 * @param amount amount of tokens to be transfered. For NFT must be set to 1n1136 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg"}, {Ethereum: "0x9F0583DbB85..."})1137 * @returns true if the token success, otherwise false1138 */1139 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1140 const result = await this.helper.executeExtrinsic(1141 signer,1142 'api.tx.unique.transferFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],1143 true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1144 );1145 return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1146 }11471148 /**1149 *1150 * Destroys a concrete instance of NFT/RFT or burns a specified amount of fungible tokens.1151 *1152 * @param signer keyring of signer1153 * @param collectionId ID of collection1154 * @param tokenId ID of token1155 * @param amount amount of tokens to be burned. For NFT must be set to 1n1156 * @example burnToken(aliceKeyring, 10, 5);1157 * @returns ```true``` if the extrinsic is successful, otherwise ```false```1158 */1159 async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount=1n): Promise<boolean> {1160 const burnResult = await this.helper.executeExtrinsic(1161 signer,1162 'api.tx.unique.burnItem', [collectionId, tokenId, amount],1163 true, // `Unable to burn token for ${label}`,1164 );1165 const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1166 if (burnedTokens.tokens.length > 1) throw Error('Burned multiple tokens');1167 return burnedTokens.success;1168 }11691170 /**1171 * Destroys a concrete instance of NFT on behalf of the owner1172 *1173 * @param signer keyring of signer1174 * @param collectionId ID of collection1175 * @param tokenId ID of token1176 * @param fromAddressObj address on behalf of which the token will be burnt1177 * @param amount amount of tokens to be burned. For NFT must be set to 1n1178 * @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."})1179 * @returns ```true``` if extrinsic success, otherwise ```false```1180 */1181 async burnTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1182 const burnResult = await this.helper.executeExtrinsic(1183 signer,1184 'api.tx.unique.burnFrom', [collectionId, fromAddressObj, tokenId, amount],1185 true, // `Unable to burn token from for ${label}`,1186 );1187 const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1188 return burnedTokens.success && burnedTokens.tokens.length > 0;1189 }11901191 /**1192 * Set, change, or remove approved address to transfer the ownership of the NFT.1193 *1194 * @param signer keyring of signer1195 * @param collectionId ID of collection1196 * @param tokenId ID of token1197 * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens1198 * @param amount amount of token to be approved. For NFT must be set to 1n1199 * @returns ```true``` if extrinsic success, otherwise ```false```1200 */1201 async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {1202 const approveResult = await this.helper.executeExtrinsic(1203 signer,1204 'api.tx.unique.approve', [toAddressObj, collectionId, tokenId, amount],1205 true, // `Unable to approve token for ${label}`,1206 );12071208 return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');1209 }12101211 /**1212 * Get the amount of token pieces approved to transfer or burn. Normally 0.1213 *1214 * @param collectionId ID of collection1215 * @param tokenId ID of token1216 * @param toAccountObj address which is approved to use token pieces1217 * @param fromAccountObj address which may have allowed the use of its owned tokens1218 * @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."})1219 * @returns number of approved to transfer pieces1220 */1221 async getTokenApprovedPieces(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId, fromAccountObj: ICrossAccountId): Promise<bigint> {1222 return (await this.helper.callRpc('api.rpc.unique.allowance', [collectionId, fromAccountObj, toAccountObj, tokenId])).toBigInt();1223 }12241225 /**1226 * Get the last created token ID in a collection1227 *1228 * @param collectionId ID of collection1229 * @example getLastTokenId(10);1230 * @returns id of the last created token1231 */1232 async getLastTokenId(collectionId: number): Promise<number> {1233 return (await this.helper.callRpc('api.rpc.unique.lastTokenId', [collectionId])).toNumber();1234 }12351236 /**1237 * Check if token exists1238 *1239 * @param collectionId ID of collection1240 * @param tokenId ID of token1241 * @example doesTokenExist(10, 20);1242 * @returns true if the token exists, otherwise false1243 */1244 async doesTokenExist(collectionId: number, tokenId: number): Promise<boolean> {1245 return (await this.helper.callRpc('api.rpc.unique.tokenExists', [collectionId, tokenId])).toJSON();1246 }1247}12481249class NFTnRFT extends CollectionGroup {1250 /**1251 * Get tokens owned by account1252 *1253 * @param collectionId ID of collection1254 * @param addressObj tokens owner1255 * @example getTokensByAddress(10, {Substrate: "5DyN4Y92vZCjv38fg..."})1256 * @returns array of token ids owned by account1257 */1258 async getTokensByAddress(collectionId: number, addressObj: ICrossAccountId): Promise<number[]> {1259 return (await this.helper.callRpc('api.rpc.unique.accountTokens', [collectionId, addressObj])).toJSON();1260 }12611262 /**1263 * Get token data1264 *1265 * @param collectionId ID of collection1266 * @param tokenId ID of token1267 * @param propertyKeys optionally filter the token properties to only these keys1268 * @param blockHashAt optionally query the data at some block with this hash1269 * @example getToken(10, 5);1270 * @returns human readable token data1271 */1272 async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{1273 properties: IProperty[];1274 owner: CrossAccountId;1275 normalizedOwner: CrossAccountId;1276 }| null> {1277 let tokenData;1278 if(typeof blockHashAt === 'undefined') {1279 tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId]);1280 }1281 else {1282 if(propertyKeys.length == 0) {1283 const collection = (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1284 if(!collection) return null;1285 propertyKeys = collection.tokenPropertyPermissions.map((x: ITokenPropertyPermission) => x.key);1286 }1287 tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId, propertyKeys, blockHashAt]);1288 }1289 tokenData = tokenData.toHuman();1290 if (tokenData === null || tokenData.owner === null) return null;1291 const owner = {} as any;1292 for (const key of Object.keys(tokenData.owner)) {1293 owner[key.toLocaleLowerCase()] = key.toLocaleLowerCase() == 'substrate'1294 ? CrossAccountId.normalizeSubstrateAddress(tokenData.owner[key])1295 : tokenData.owner[key];1296 }1297 tokenData.normalizedOwner = CrossAccountId.fromLowerCaseKeys(owner);1298 return tokenData;1299 }13001301 /**1302 * Set permissions to change token properties1303 *1304 * @param signer keyring of signer1305 * @param collectionId ID of collection1306 * @param permissions permissions to change a property by the collection admin or token owner1307 * @example setTokenPropertyPermissions(1308 * aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}]1309 * )1310 * @returns true if extrinsic success otherwise false1311 */1312 async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise<boolean> {1313 const result = await this.helper.executeExtrinsic(1314 signer,1315 'api.tx.unique.setTokenPropertyPermissions', [collectionId, permissions],1316 true,1317 );13181319 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');1320 }13211322 /**1323 * Get token property permissions.1324 *1325 * @param collectionId ID of collection1326 * @param propertyKeys optionally filter the returned property permissions to only these keys1327 * @example getPropertyPermissions(1219, ['location', 'date', 'time', 'isParadise']);1328 * @returns array of key-permission pairs1329 */1330 async getPropertyPermissions(collectionId: number, propertyKeys: string[] | null = null): Promise<ITokenPropertyPermission[]> {1331 return (await this.helper.callRpc('api.rpc.unique.propertyPermissions', [collectionId, ...(propertyKeys === null ? [] : [propertyKeys])])).toHuman();1332 }13331334 /**1335 * Set token properties1336 *1337 * @param signer keyring of signer1338 * @param collectionId ID of collection1339 * @param tokenId ID of token1340 * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection1341 * @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}])1342 * @returns ```true``` if extrinsic success, otherwise ```false```1343 */1344 async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise<boolean> {1345 const result = await this.helper.executeExtrinsic(1346 signer,1347 'api.tx.unique.setTokenProperties', [collectionId, tokenId, properties],1348 true,1349 );13501351 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');1352 }13531354 /**1355 * Get properties, metadata assigned to a token.1356 *1357 * @param collectionId ID of collection1358 * @param tokenId ID of token1359 * @param propertyKeys optionally filter the returned properties to only these keys1360 * @example getTokenProperties(1219, ['location', 'date', 'time', 'isParadise']);1361 * @returns array of key-value pairs1362 */1363 async getTokenProperties(collectionId: number, tokenId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1364 return (await this.helper.callRpc('api.rpc.unique.tokenProperties', [collectionId, tokenId, propertyKeys])).toHuman();1365 }13661367 /**1368 * Delete the provided properties of a token1369 * @param signer keyring of signer1370 * @param collectionId ID of collection1371 * @param tokenId ID of token1372 * @param propertyKeys property keys to be deleted1373 * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"])1374 * @returns ```true``` if extrinsic success, otherwise ```false```1375 */1376 async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise<boolean> {1377 const result = await this.helper.executeExtrinsic(1378 signer,1379 'api.tx.unique.deleteTokenProperties', [collectionId, tokenId, propertyKeys],1380 true,1381 );13821383 return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted');1384 }13851386 /**1387 * Mint new collection1388 *1389 * @param signer keyring of signer1390 * @param collectionOptions basic collection options and properties1391 * @param mode NFT or RFT type of a collection1392 * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")1393 * @returns object of the created collection1394 */1395 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueBaseCollection> {1396 collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1397 collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};1398 for (const key of ['name', 'description', 'tokenPrefix']) {1399 if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);1400 }1401 const creationResult = await this.helper.executeExtrinsic(1402 signer,1403 'api.tx.unique.createCollectionEx', [collectionOptions],1404 true, // errorLabel,1405 );1406 return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));1407 }14081409 getCollectionObject(_collectionId: number): any {1410 return null;1411 }14121413 getTokenObject(_collectionId: number, _tokenId: number): any {1414 return null;1415 }1416}141714181419class NFTGroup extends NFTnRFT {1420 /**1421 * Get collection object1422 * @param collectionId ID of collection1423 * @example getCollectionObject(2);1424 * @returns instance of UniqueNFTCollection1425 */1426 getCollectionObject(collectionId: number): UniqueNFTCollection {1427 return new UniqueNFTCollection(collectionId, this.helper);1428 }14291430 /**1431 * Get token object1432 * @param collectionId ID of collection1433 * @param tokenId ID of token1434 * @example getTokenObject(10, 5);1435 * @returns instance of UniqueNFTToken1436 */1437 getTokenObject(collectionId: number, tokenId: number): UniqueNFToken {1438 return new UniqueNFToken(tokenId, this.getCollectionObject(collectionId));1439 }14401441 /**1442 * Get token's owner1443 * @param collectionId ID of collection1444 * @param tokenId ID of token1445 * @param blockHashAt optionally query the data at the block with this hash1446 * @example getTokenOwner(10, 5);1447 * @returns Address in CrossAccountId format, e.g. {Substrate: "5DnSF6RRjwteE3BrCj..."}1448 */1449 async getTokenOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<CrossAccountId> {1450 let owner;1451 if (typeof blockHashAt === 'undefined') {1452 owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId]);1453 } else {1454 owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId, blockHashAt]);1455 }1456 return CrossAccountId.fromLowerCaseKeys(owner.toJSON());1457 }14581459 /**1460 * Is token approved to transfer1461 * @param collectionId ID of collection1462 * @param tokenId ID of token1463 * @param toAccountObj address to be approved1464 * @returns ```true``` if extrinsic success, otherwise ```false```1465 */1466 async isTokenApproved(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId): Promise<boolean> {1467 return (await this.getTokenApprovedPieces(collectionId, tokenId, toAccountObj, await this.getTokenOwner(collectionId, tokenId))) === 1n;1468 }14691470 /**1471 * Changes the owner of the token.1472 *1473 * @param signer keyring of signer1474 * @param collectionId ID of collection1475 * @param tokenId ID of token1476 * @param addressObj address of a new owner1477 * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1478 * @returns ```true``` if extrinsic success, otherwise ```false```1479 */1480 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<boolean> {1481 return await super.transferToken(signer, collectionId, tokenId, addressObj, 1n);1482 }14831484 /**1485 *1486 * Change ownership of a NFT on behalf of the owner.1487 *1488 * @param signer keyring of signer1489 * @param collectionId ID of collection1490 * @param tokenId ID of token1491 * @param fromAddressObj address on behalf of which the token will be sent1492 * @param toAddressObj new token owner1493 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Ethereum: "0x9F0583DbB85..."})1494 * @returns ```true``` if extrinsic success, otherwise ```false```1495 */1496 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId): Promise<boolean> {1497 return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, 1n);1498 }14991500 /**1501 * Recursively find the address that owns the token1502 * @param collectionId ID of collection1503 * @param tokenId ID of token1504 * @param blockHashAt1505 * @example getTokenTopmostOwner(10, 5);1506 * @returns address in CrossAccountId format, e.g. {Substrate: "5DyN4Y92vZCjv38fg..."}1507 */1508 async getTokenTopmostOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<CrossAccountId | null> {1509 let owner;1510 if (typeof blockHashAt === 'undefined') {1511 owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId]);1512 } else {1513 owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId, blockHashAt]);1514 }15151516 if (owner === null) return null;15171518 return owner.toHuman();1519 }15201521 /**1522 * Get tokens nested in the provided token1523 * @param collectionId ID of collection1524 * @param tokenId ID of token1525 * @param blockHashAt optionally query the data at the block with this hash1526 * @example getTokenChildren(10, 5);1527 * @returns tokens whose depth of nesting is <= 51528 */1529 async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {1530 let children;1531 if(typeof blockHashAt === 'undefined') {1532 children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId]);1533 } else {1534 children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId, blockHashAt]);1535 }15361537 return children.toJSON().map((x: any) => {1538 return {collectionId: x.collection, tokenId: x.token};1539 });1540 }15411542 /**1543 * Nest one token into another1544 * @param signer keyring of signer1545 * @param tokenObj token to be nested1546 * @param rootTokenObj token to be parent1547 * @example nestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4});1548 * @returns ```true``` if extrinsic success, otherwise ```false```1549 */1550 async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise<boolean> {1551 const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1552 const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress);1553 if(!result) {1554 throw Error('Unable to nest token!');1555 }1556 return result;1557 }15581559 /**1560 * Remove token from nested state1561 * @param signer keyring of signer1562 * @param tokenObj token to unnest1563 * @param rootTokenObj parent of a token1564 * @param toAddressObj address of a new token owner1565 * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});1566 * @returns ```true``` if extrinsic success, otherwise ```false```1567 */1568 async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {1569 const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1570 const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);1571 if(!result) {1572 throw Error('Unable to unnest token!');1573 }1574 return result;1575 }15761577 /**1578 * Mint new collection1579 * @param signer keyring of signer1580 * @param collectionOptions Collection options1581 * @example1582 * mintCollection(aliceKeyring, {1583 * name: 'New',1584 * description: 'New collection',1585 * tokenPrefix: 'NEW',1586 * })1587 * @returns object of the created collection1588 */1589 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueNFTCollection> {1590 return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection;1591 }15921593 /**1594 * Mint new token1595 * @param signer keyring of signer1596 * @param data token data1597 * @returns created token object1598 */1599 async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise<UniqueNFToken> {1600 const creationResult = await this.helper.executeExtrinsic(1601 signer,1602 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1603 nft: {1604 properties: data.properties,1605 },1606 }],1607 true,1608 );1609 const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1610 if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1611 if (createdTokens.tokens.length < 1) throw Error('No tokens minted');1612 return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1613 }16141615 /**1616 * Mint multiple NFT tokens1617 * @param signer keyring of signer1618 * @param collectionId ID of collection1619 * @param tokens array of tokens with owner and properties1620 * @example1621 * mintMultipleTokens(aliceKeyring, 10, [{1622 * owner: {Substrate: "5DyN4Y92vZCjv38fg..."},1623 * properties: [{key: "gender", value: "male"},{key: "age", value: "45"}],1624 * },{1625 * owner: {Ethereum: "0x9F0583DbB855d..."},1626 * properties: [{key: "gender", value: "female"},{key: "age", value: "22"}],1627 * }]);1628 * @returns ```true``` if extrinsic success, otherwise ```false```1629 */1630 async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {1631 const creationResult = await this.helper.executeExtrinsic(1632 signer,1633 'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}],1634 true,1635 );1636 const collection = this.getCollectionObject(collectionId);1637 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1638 }16391640 /**1641 * Mint multiple NFT tokens with one owner1642 * @param signer keyring of signer1643 * @param collectionId ID of collection1644 * @param owner tokens owner1645 * @param tokens array of tokens with owner and properties1646 * @example1647 * mintMultipleTokensWithOneOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...", [{1648 * properties: [{1649 * key: "gender",1650 * value: "female",1651 * },{1652 * key: "age",1653 * value: "33",1654 * }],1655 * }]);1656 * @returns array of newly created tokens1657 */1658 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {1659 const rawTokens = [];1660 for (const token of tokens) {1661 const raw = {NFT: {properties: token.properties}};1662 rawTokens.push(raw);1663 }1664 const creationResult = await this.helper.executeExtrinsic(1665 signer,1666 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1667 true,1668 );1669 const collection = this.getCollectionObject(collectionId);1670 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1671 }16721673 /**1674 * Set, change, or remove approved address to transfer the ownership of the NFT.1675 *1676 * @param signer keyring of signer1677 * @param collectionId ID of collection1678 * @param tokenId ID of token1679 * @param toAddressObj address to approve1680 * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1681 * @returns ```true``` if extrinsic success, otherwise ```false```1682 */1683 approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId) {1684 return super.approveToken(signer, collectionId, tokenId, toAddressObj, 1n);1685 }1686}168716881689class RFTGroup extends NFTnRFT {1690 /**1691 * Get collection object1692 * @param collectionId ID of collection1693 * @example getCollectionObject(2);1694 * @returns instance of UniqueRFTCollection1695 */1696 getCollectionObject(collectionId: number): UniqueRFTCollection {1697 return new UniqueRFTCollection(collectionId, this.helper);1698 }16991700 /**1701 * Get token object1702 * @param collectionId ID of collection1703 * @param tokenId ID of token1704 * @example getTokenObject(10, 5);1705 * @returns instance of UniqueNFTToken1706 */1707 getTokenObject(collectionId: number, tokenId: number): UniqueRFToken {1708 return new UniqueRFToken(tokenId, this.getCollectionObject(collectionId));1709 }17101711 /**1712 * Get top 10 token owners with the largest number of pieces1713 * @param collectionId ID of collection1714 * @param tokenId ID of token1715 * @example getTokenTop10Owners(10, 5);1716 * @returns array of top 10 owners1717 */1718 async getTokenTop10Owners(collectionId: number, tokenId: number): Promise<CrossAccountId[]> {1719 return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, tokenId])).toJSON().map(CrossAccountId.fromLowerCaseKeys);1720 }17211722 /**1723 * Get number of pieces owned by address1724 * @param collectionId ID of collection1725 * @param tokenId ID of token1726 * @param addressObj address token owner1727 * @example getTokenBalance(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."});1728 * @returns number of pieces ownerd by address1729 */1730 async getTokenBalance(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<bigint> {1731 return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, tokenId])).toBigInt();1732 }17331734 /**1735 * Transfer pieces of token to another address1736 * @param signer keyring of signer1737 * @param collectionId ID of collection1738 * @param tokenId ID of token1739 * @param addressObj address of a new owner1740 * @param amount number of pieces to be transfered1741 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2000n)1742 * @returns ```true``` if extrinsic success, otherwise ```false```1743 */1744 async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {1745 return await super.transferToken(signer, collectionId, tokenId, addressObj, amount);1746 }17471748 /**1749 * Change ownership of some pieces of RFT on behalf of the owner.1750 * @param signer keyring of signer1751 * @param collectionId ID of collection1752 * @param tokenId ID of token1753 * @param fromAddressObj address on behalf of which the token will be sent1754 * @param toAddressObj new token owner1755 * @param amount number of pieces to be transfered1756 * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n)1757 * @returns ```true``` if extrinsic success, otherwise ```false```1758 */1759 async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1760 return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1761 }17621763 /**1764 * Mint new collection1765 * @param signer keyring of signer1766 * @param collectionOptions Collection options1767 * @example1768 * mintCollection(aliceKeyring, {1769 * name: 'New',1770 * description: 'New collection',1771 * tokenPrefix: 'NEW',1772 * })1773 * @returns object of the created collection1774 */1775 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueRFTCollection> {1776 return await super.mintCollection(signer, collectionOptions, 'RFT') as UniqueRFTCollection;1777 }17781779 /**1780 * Mint new token1781 * @param signer keyring of signer1782 * @param data token data1783 * @example mintToken(aliceKeyring, {collectionId: 10, owner: {Substrate: '5GHoZe9c73RYbVzq...'}, pieces: 10000n});1784 * @returns created token object1785 */1786 async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise<UniqueRFToken> {1787 const creationResult = await this.helper.executeExtrinsic(1788 signer,1789 'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1790 refungible: {1791 pieces: data.pieces,1792 properties: data.properties,1793 },1794 }],1795 true,1796 );1797 const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1798 if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1799 if (createdTokens.tokens.length < 1) throw Error('No tokens minted');1800 return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1801 }18021803 async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {1804 throw Error('Not implemented');1805 const creationResult = await this.helper.executeExtrinsic(1806 signer,1807 'api.tx.unique.createMultipleItemsEx', [collectionId, {RefungibleMultipleOwners: tokens}],1808 true, // `Unable to mint RFT tokens for ${label}`,1809 );1810 const collection = this.getCollectionObject(collectionId);1811 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1812 }18131814 /**1815 * Mint multiple RFT tokens with one owner1816 * @param signer keyring of signer1817 * @param collectionId ID of collection1818 * @param owner tokens owner1819 * @param tokens array of tokens with properties and pieces1820 * @example mintMultipleTokensWithOneOwner(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, [{pieces: 100000n, properties: [{key: "gender", value: "male"}]}]);1821 * @returns array of newly created RFT tokens1822 */1823 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {1824 const rawTokens = [];1825 for (const token of tokens) {1826 const raw = {ReFungible: {pieces: token.pieces, properties: token.properties}};1827 rawTokens.push(raw);1828 }1829 const creationResult = await this.helper.executeExtrinsic(1830 signer,1831 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1832 true,1833 );1834 const collection = this.getCollectionObject(collectionId);1835 return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1836 }18371838 /**1839 * Destroys a concrete instance of RFT.1840 * @param signer keyring of signer1841 * @param collectionId ID of collection1842 * @param tokenId ID of token1843 * @param amount number of pieces to be burnt1844 * @example burnToken(aliceKeyring, 10, 5);1845 * @returns ```true``` if the extrinsic is successful, otherwise ```false```1846 */1847 async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount=1n): Promise<boolean> {1848 return await super.burnToken(signer, collectionId, tokenId, amount);1849 }18501851 /**1852 * Destroys a concrete instance of RFT on behalf of the owner.1853 * @param signer keyring of signer1854 * @param collectionId ID of collection1855 * @param tokenId ID of token1856 * @param fromAddressObj address on behalf of which the token will be burnt1857 * @param amount number of pieces to be burnt1858 * @example burnTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2n)1859 * @returns ```true``` if extrinsic success, otherwise ```false```1860 */1861 async burnTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1862 return await super.burnTokenFrom(signer, collectionId, tokenId, fromAddressObj, amount);1863 }18641865 /**1866 * Set, change, or remove approved address to transfer the ownership of the RFT.1867 *1868 * @param signer keyring of signer1869 * @param collectionId ID of collection1870 * @param tokenId ID of token1871 * @param toAddressObj address to approve1872 * @param amount number of pieces to be approved1873 * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n);1874 * @returns true if the token success, otherwise false1875 */1876 approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {1877 return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);1878 }18791880 /**1881 * Get total number of pieces1882 * @param collectionId ID of collection1883 * @param tokenId ID of token1884 * @example getTokenTotalPieces(10, 5);1885 * @returns number of pieces1886 */1887 async getTokenTotalPieces(collectionId: number, tokenId: number): Promise<bigint> {1888 return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, tokenId])).unwrap().toBigInt();1889 }18901891 /**1892 * Change number of token pieces. Signer must be the owner of all token pieces.1893 * @param signer keyring of signer1894 * @param collectionId ID of collection1895 * @param tokenId ID of token1896 * @param amount new number of pieces1897 * @example repartitionToken(aliceKeyring, 10, 5, 12345n);1898 * @returns true if the repartion was success, otherwise false1899 */1900 async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint): Promise<boolean> {1901 const currentAmount = await this.getTokenTotalPieces(collectionId, tokenId);1902 const repartitionResult = await this.helper.executeExtrinsic(1903 signer,1904 'api.tx.unique.repartition', [collectionId, tokenId, amount],1905 true,1906 );1907 if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated');1908 return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed');1909 }1910}191119121913class FTGroup extends CollectionGroup {1914 /**1915 * Get collection object1916 * @param collectionId ID of collection1917 * @example getCollectionObject(2);1918 * @returns instance of UniqueFTCollection1919 */1920 getCollectionObject(collectionId: number): UniqueFTCollection {1921 return new UniqueFTCollection(collectionId, this.helper);1922 }19231924 /**1925 * Mint new fungible collection1926 * @param signer keyring of signer1927 * @param collectionOptions Collection options1928 * @param decimalPoints number of token decimals1929 * @example1930 * mintCollection(aliceKeyring, {1931 * name: 'New',1932 * description: 'New collection',1933 * tokenPrefix: 'NEW',1934 * }, 18)1935 * @returns newly created fungible collection1936 */1937 async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}, decimalPoints = 0): Promise<UniqueFTCollection> {1938 collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1939 if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions');1940 collectionOptions.mode = {fungible: decimalPoints};1941 for (const key of ['name', 'description', 'tokenPrefix']) {1942 if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);1943 }1944 const creationResult = await this.helper.executeExtrinsic(1945 signer,1946 'api.tx.unique.createCollectionEx', [collectionOptions],1947 true,1948 );1949 return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));1950 }19511952 /**1953 * Mint tokens1954 * @param signer keyring of signer1955 * @param collectionId ID of collection1956 * @param owner address owner of new tokens1957 * @param amount amount of tokens to be meanted1958 * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n);1959 * @returns ```true``` if extrinsic success, otherwise ```false```1960 */1961 async mintTokens(signer: TSigner, collectionId: number, amount: bigint, owner: ICrossAccountId | string): Promise<boolean> {1962 const creationResult = await this.helper.executeExtrinsic(1963 signer,1964 'api.tx.unique.createItem', [collectionId, (typeof owner === 'string') ? {Substrate: owner} : owner, {1965 fungible: {1966 value: amount,1967 },1968 }],1969 true, // `Unable to mint fungible tokens for ${label}`,1970 );1971 return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');1972 }19731974 /**1975 * Mint multiple Fungible tokens with one owner1976 * @param signer keyring of signer1977 * @param collectionId ID of collection1978 * @param owner tokens owner1979 * @param tokens array of tokens with properties and pieces1980 * @returns ```true``` if extrinsic success, otherwise ```false```1981 */1982 async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, tokens: {value: bigint}[], owner: ICrossAccountId): Promise<boolean> {1983 const rawTokens = [];1984 for (const token of tokens) {1985 const raw = {Fungible: {Value: token.value}};1986 rawTokens.push(raw);1987 }1988 const creationResult = await this.helper.executeExtrinsic(1989 signer,1990 'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1991 true,1992 );1993 return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');1994 }19951996 /**1997 * Get the top 10 owners with the largest balance for the Fungible collection1998 * @param collectionId ID of collection1999 * @example getTop10Owners(10);2000 * @returns array of ```ICrossAccountId```2001 */2002 async getTop10Owners(collectionId: number): Promise<CrossAccountId[]> {2003 return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, 0])).toJSON().map(CrossAccountId.fromLowerCaseKeys);2004 }20052006 /**2007 * Get account balance2008 * @param collectionId ID of collection2009 * @param addressObj address of owner2010 * @example getBalance(10, {Substrate: "5GHoZe9c73RYbVzq..."})2011 * @returns amount of fungible tokens owned by address2012 */2013 async getBalance(collectionId: number, addressObj: ICrossAccountId): Promise<bigint> {2014 return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, 0])).toBigInt();2015 }20162017 /**2018 * Transfer tokens to address2019 * @param signer keyring of signer2020 * @param collectionId ID of collection2021 * @param toAddressObj address recipient2022 * @param amount amount of tokens to be sent2023 * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2024 * @returns ```true``` if extrinsic success, otherwise ```false```2025 */2026 async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {2027 return await super.transferToken(signer, collectionId, 0, toAddressObj, amount);2028 }20292030 /**2031 * Transfer some tokens on behalf of the owner.2032 * @param signer keyring of signer2033 * @param collectionId ID of collection2034 * @param fromAddressObj address on behalf of which tokens will be sent2035 * @param toAddressObj address where token to be sent2036 * @param amount number of tokens to be sent2037 * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n);2038 * @returns ```true``` if extrinsic success, otherwise ```false```2039 */2040 async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {2041 return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount);2042 }20432044 /**2045 * Destroy some amount of tokens2046 * @param signer keyring of signer2047 * @param collectionId ID of collection2048 * @param amount amount of tokens to be destroyed2049 * @example burnTokens(aliceKeyring, 10, 1000n);2050 * @returns ```true``` if extrinsic success, otherwise ```false```2051 */2052 async burnTokens(signer: IKeyringPair, collectionId: number, amount=1n): Promise<boolean> {2053 return await super.burnToken(signer, collectionId, 0, amount);2054 }20552056 /**2057 * Burn some tokens on behalf of the owner.2058 * @param signer keyring of signer2059 * @param collectionId ID of collection2060 * @param fromAddressObj address on behalf of which tokens will be burnt2061 * @param amount amount of tokens to be burnt2062 * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2063 * @returns ```true``` if extrinsic success, otherwise ```false```2064 */2065 async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {2066 return await super.burnTokenFrom(signer, collectionId, 0, fromAddressObj, amount);2067 }20682069 /**2070 * Get total collection supply2071 * @param collectionId2072 * @returns2073 */2074 async getTotalPieces(collectionId: number): Promise<bigint> {2075 return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, 0])).unwrap().toBigInt();2076 }20772078 /**2079 * Set, change, or remove approved address to transfer tokens.2080 *2081 * @param signer keyring of signer2082 * @param collectionId ID of collection2083 * @param toAddressObj address to be approved2084 * @param amount amount of tokens to be approved2085 * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n)2086 * @returns ```true``` if extrinsic success, otherwise ```false```2087 */2088 approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {2089 return super.approveToken(signer, collectionId, 0, toAddressObj, amount);2090 }20912092 /**2093 * Get amount of fungible tokens approved to transfer2094 * @param collectionId ID of collection2095 * @param fromAddressObj owner of tokens2096 * @param toAddressObj the address approved for the transfer of tokens on behalf of the owner2097 * @returns number of tokens approved for the transfer2098 */2099 getApprovedTokens(collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {2100 return super.getTokenApprovedPieces(collectionId, 0, toAddressObj, fromAddressObj);2101 }2102}210321042105class ChainGroup extends HelperGroup<ChainHelperBase> {2106 /**2107 * Get system properties of a chain2108 * @example getChainProperties();2109 * @returns ss58Format, token decimals, and token symbol2110 */2111 getChainProperties(): IChainProperties {2112 const properties = (this.helper.getApi() as any).registry.getChainProperties().toJSON();2113 return {2114 ss58Format: properties.ss58Format.toJSON(),2115 tokenDecimals: properties.tokenDecimals.toJSON(),2116 tokenSymbol: properties.tokenSymbol.toJSON(),2117 };2118 }21192120 /**2121 * Get chain header2122 * @example getLatestBlockNumber();2123 * @returns the number of the last block2124 */2125 async getLatestBlockNumber(): Promise<number> {2126 return (await this.helper.callRpc('api.rpc.chain.getHeader')).number.toNumber();2127 }21282129 /**2130 * Get block hash by block number2131 * @param blockNumber number of block2132 * @example getBlockHashByNumber(12345);2133 * @returns hash of a block2134 */2135 async getBlockHashByNumber(blockNumber: number): Promise<string | null> {2136 const blockHash = (await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber])).toJSON();2137 if(blockHash === '0x0000000000000000000000000000000000000000000000000000000000000000') return null;2138 return blockHash;2139 }21402141 // TODO add docs2142 async getBlock(blockHashOrNumber: string | number): Promise<IBlock | null> {2143 const blockHash = typeof blockHashOrNumber === 'string' ? blockHashOrNumber : await this.getBlockHashByNumber(blockHashOrNumber);2144 if (!blockHash) return null;2145 return (await this.helper.callRpc('api.rpc.chain.getBlock', [blockHash])).toHuman().block;2146 }21472148 /**2149 * Get latest relay block2150 * @returns {number} relay block2151 */2152 async getRelayBlockNumber(): Promise<bigint> {2153 const blockNumber = (await this.helper.callRpc('api.query.parachainSystem.validationData')).toJSON().relayParentNumber;2154 return BigInt(blockNumber);2155 }21562157 /**2158 * Get account nonce2159 * @param address substrate address2160 * @example getNonce("5GrwvaEF5zXb26Fz...");2161 * @returns number, account's nonce2162 */2163 async getNonce(address: TSubstrateAccount): Promise<number> {2164 return (await this.helper.callRpc('api.query.system.account', [address])).nonce.toNumber();2165 }2166}21672168class SubstrateBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2169 /**2170 * Get substrate address balance2171 * @param address substrate address2172 * @example getSubstrate("5GrwvaEF5zXb26Fz...")2173 * @returns amount of tokens on address2174 */2175 async getSubstrate(address: TSubstrateAccount): Promise<bigint> {2176 return (await this.helper.callRpc('api.query.system.account', [address])).data.free.toBigInt();2177 }21782179 /**2180 * Transfer tokens to substrate address2181 * @param signer keyring of signer2182 * @param address substrate address of a recipient2183 * @param amount amount of tokens to be transfered2184 * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2185 * @returns ```true``` if extrinsic success, otherwise ```false```2186 */2187 async transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2188 const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true/*, `Unable to transfer balance from ${this.helper.getSignerAddress(signer)} to ${address}`*/);21892190 let transfer = {from: null, to: null, amount: 0n} as any;2191 result.result.events.forEach(({event: {data, method, section}}) => {2192 if ((section === 'balances') && (method === 'Transfer')) {2193 transfer = {2194 from: this.helper.address.normalizeSubstrate(data[0]),2195 to: this.helper.address.normalizeSubstrate(data[1]),2196 amount: BigInt(data[2]),2197 };2198 }2199 });2200 const isSuccess = this.helper.address.normalizeSubstrate(typeof signer === 'string' ? signer : signer.address) === transfer.from2201 && this.helper.address.normalizeSubstrate(address) === transfer.to2202 && BigInt(amount) === transfer.amount;2203 return isSuccess;2204 }22052206 /**2207 * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2208 * @param address substrate address2209 * @returns2210 */2211 async getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2212 const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data;2213 return {free: accountInfo.free.toBigInt(), miscFrozen: accountInfo.miscFrozen.toBigInt(), feeFrozen: accountInfo.feeFrozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};2214 }2215}22162217class EthereumBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2218 /**2219 * Get ethereum address balance2220 * @param address ethereum address2221 * @example getEthereum("0x9F0583DbB855d...")2222 * @returns amount of tokens on address2223 */2224 async getEthereum(address: TEthereumAccount): Promise<bigint> {2225 return (await this.helper.callRpc('api.rpc.eth.getBalance', [address])).toBigInt();2226 }22272228 /**2229 * Transfer tokens to address2230 * @param signer keyring of signer2231 * @param address Ethereum address of a recipient2232 * @param amount amount of tokens to be transfered2233 * @example transferToEthereum(alithKeyring, "0x9F0583DbB855d...", 100_000_000_000n);2234 * @returns ```true``` if extrinsic success, otherwise ```false```2235 */2236 async transferToEthereum(signer: TSigner, address: TEthereumAccount, amount: bigint | string): Promise<boolean> {2237 const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true);22382239 let transfer = {from: null, to: null, amount: 0n} as any;2240 result.result.events.forEach(({event: {data, method, section}}) => {2241 if ((section === 'balances') && (method === 'Transfer')) {2242 transfer = {2243 from: data[0].toString(),2244 to: data[1].toString(),2245 amount: BigInt(data[2]),2246 };2247 }2248 });2249 const isSuccess = (typeof signer === 'string' ? signer : signer.address) === transfer.from2250 && address === transfer.to2251 && BigInt(amount) === transfer.amount;2252 return isSuccess;2253 }2254}22552256class BalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2257 subBalanceGroup: SubstrateBalanceGroup<T>;2258 ethBalanceGroup: EthereumBalanceGroup<T>;22592260 constructor(helper: T) {2261 super(helper);2262 this.subBalanceGroup = new SubstrateBalanceGroup(helper);2263 this.ethBalanceGroup = new EthereumBalanceGroup(helper);2264 }22652266 getCollectionCreationPrice(): bigint {2267 return 2n * this.getOneTokenNominal();2268 }2269 /**2270 * Representation of the native token in the smallest unit - one OPAL (OPL), QUARTZ (QTZ), or UNIQUE (UNQ).2271 * @example getOneTokenNominal()2272 * @returns ```BigInt``` representation of the native token in the smallest unit, e.g. ```1_000_000_000_000_000_000n``` for QTZ.2273 */2274 getOneTokenNominal(): bigint {2275 const chainProperties = this.helper.chain.getChainProperties();2276 return 10n ** BigInt((chainProperties.tokenDecimals || [18])[0]);2277 }22782279 /**2280 * Get substrate address balance2281 * @param address substrate address2282 * @example getSubstrate("5GrwvaEF5zXb26Fz...")2283 * @returns amount of tokens on address2284 */2285 getSubstrate(address: TSubstrateAccount): Promise<bigint> {2286 return this.subBalanceGroup.getSubstrate(address);2287 }22882289 /**2290 * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2291 * @param address substrate address2292 * @returns2293 */2294 getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2295 return this.subBalanceGroup.getSubstrateFull(address);2296 }22972298 /**2299 * Get ethereum address balance2300 * @param address ethereum address2301 * @example getEthereum("0x9F0583DbB855d...")2302 * @returns amount of tokens on address2303 */2304 getEthereum(address: TEthereumAccount): Promise<bigint> {2305 return this.ethBalanceGroup.getEthereum(address);2306 }23072308 /**2309 * Transfer tokens to substrate address2310 * @param signer keyring of signer2311 * @param address substrate address of a recipient2312 * @param amount amount of tokens to be transfered2313 * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2314 * @returns ```true``` if extrinsic success, otherwise ```false```2315 */2316 transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2317 return this.subBalanceGroup.transferToSubstrate(signer, address, amount);2318 }23192320 async forceTransferToSubstrate(signer: TSigner, from: TSubstrateAccount, to: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2321 const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceTransfer', [from, to, amount], true);23222323 let transfer = {from: null, to: null, amount: 0n} as any;2324 result.result.events.forEach(({event: {data, method, section}}) => {2325 if ((section === 'balances') && (method === 'Transfer')) {2326 transfer = {2327 from: this.helper.address.normalizeSubstrate(data[0]),2328 to: this.helper.address.normalizeSubstrate(data[1]),2329 amount: BigInt(data[2]),2330 };2331 }2332 });2333 let isSuccess = this.helper.address.normalizeSubstrate(from) === transfer.from;2334 isSuccess = isSuccess && this.helper.address.normalizeSubstrate(to) === transfer.to;2335 isSuccess = isSuccess && BigInt(amount) === transfer.amount;2336 return isSuccess;2337 }23382339 /**2340 * Transfer tokens with the unlock period2341 * @param signer signers Keyring2342 * @param address Substrate address of recipient2343 * @param schedule Schedule params2344 * @example vestedTransfer(signer, recepient.address, 20000, 100, 10, 50 * nominal); // total amount of vested tokens will be 100 * 50 = 50002345 */2346 async vestedTransfer(signer: TSigner, address: TSubstrateAccount, schedule: {start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint}): Promise<void> {2347 const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.vestedTransfer', [address, schedule]);2348 const event = result.result.events2349 .find(e => e.event.section === 'vesting' &&2350 e.event.method === 'VestingScheduleAdded' &&2351 e.event.data[0].toHuman() === signer.address);2352 if (!event) throw Error('Cannot find transfer in events');2353 }23542355 /**2356 * Get schedule for recepient of vested transfer2357 * @param address Substrate address of recipient2358 * @returns 2359 */2360 async getVestingSchedules(address: TSubstrateAccount): Promise<{start: bigint, period: bigint, periodCount: bigint, perPeriod: bigint}[]> {2361 const schedule = (await this.helper.callRpc('api.query.vesting.vestingSchedules', [address])).toJSON();2362 return schedule.map((schedule: any) => {2363 return {2364 start: BigInt(schedule.start),2365 period: BigInt(schedule.period),2366 periodCount: BigInt(schedule.periodCount),2367 perPeriod: BigInt(schedule.perPeriod),2368 };2369 });2370 }23712372 /**2373 * Claim vested tokens2374 * @param signer signers Keyring2375 */2376 async claim(signer: TSigner) {2377 const result = await this.helper.executeExtrinsic(signer, 'api.tx.vesting.claim', []);2378 const event = result.result.events2379 .find(e => e.event.section === 'vesting' &&2380 e.event.method === 'Claimed' &&2381 e.event.data[0].toHuman() === signer.address);2382 if (!event) throw Error('Cannot find claim in events');2383 }2384}23852386class AddressGroup extends HelperGroup<ChainHelperBase> {2387 /**2388 * Normalizes the address to the specified ss58 format, by default ```42```.2389 * @param address substrate address2390 * @param ss58Format format for address conversion, by default ```42```2391 * @example normalizeSubstrate("unjKJQJrRd238pkUZZvzDQrfKuM39zBSnQ5zjAGAGcdRhaJTx") // returns 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY2392 * @returns substrate address converted to normalized (i.e., starting with 5) or specified explicitly representation2393 */2394 normalizeSubstrate(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {2395 return CrossAccountId.normalizeSubstrateAddress(address, ss58Format);2396 }23972398 /**2399 * Get address in the connected chain format2400 * @param address substrate address2401 * @example normalizeSubstrateToChainFormat("5GrwvaEF5zXb26Fz...") // returns unjKJQJrRd238pkUZZ... for Unique Network2402 * @returns address in chain format2403 */2404 normalizeSubstrateToChainFormat(address: TSubstrateAccount): TSubstrateAccount {2405 return this.normalizeSubstrate(address, this.helper.chain.getChainProperties().ss58Format);2406 }24072408 /**2409 * Get substrate mirror of an ethereum address2410 * @param ethAddress ethereum address2411 * @param toChainFormat false for normalized account2412 * @example ethToSubstrate('0x9F0583DbB855d...')2413 * @returns substrate mirror of a provided ethereum address2414 */2415 ethToSubstrate(ethAddress: TEthereumAccount, toChainFormat=false): TSubstrateAccount {2416 return CrossAccountId.translateEthToSub(ethAddress, toChainFormat ? this.helper.chain.getChainProperties().ss58Format : undefined);2417 }24182419 /**2420 * Get ethereum mirror of a substrate address2421 * @param subAddress substrate account2422 * @example substrateToEth("5DnSF6RRjwteE3BrC...")2423 * @returns ethereum mirror of a provided substrate address2424 */2425 substrateToEth(subAddress: TSubstrateAccount): TEthereumAccount {2426 return CrossAccountId.translateSubToEth(subAddress);2427 }24282429 /**2430 * Encode key to substrate address2431 * @param key key for encoding address2432 * @param ss58Format prefix for encoding to the address of the corresponding network2433 * @returns encoded substrate address2434 */2435 encodeSubstrateAddress (key: Uint8Array | string | bigint, ss58Format = 42): string {2436 const u8a :Uint8Array = typeof key === 'string'2437 ? hexToU8a(key)2438 : typeof key === 'bigint'2439 ? hexToU8a(key.toString(16))2440 : key;2441 2442 if (ss58Format < 0 || ss58Format > 16383 || [46, 47].includes(ss58Format)) {2443 throw new Error(`ss58Format is not valid, received ${typeofss58Format} "${ss58Format}"`);2444 }2445 2446 const allowedDecodedLengths = [1, 2, 4, 8, 32, 33];2447 if (!allowedDecodedLengths.includes(u8a.length)) {2448 throw new Error(`key length is not valid, received ${u8a.length}, valid values are ${allowedDecodedLengths.join(', ')}`);2449 }2450 2451 const u8aPrefix = ss58Format < 642452 ? new Uint8Array([ss58Format])2453 : new Uint8Array([2454 ((ss58Format & 0xfc) >> 2) | 0x40,2455 (ss58Format >> 8) | ((ss58Format & 0x03) << 6),2456 ]);24572458 const input = u8aConcat(u8aPrefix, u8a);2459 2460 return base58Encode(u8aConcat(2461 input,2462 blake2AsU8a(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1),2463 ));2464 }24652466 /**2467 * Restore substrate address from bigint representation2468 * @param number decimal representation of substrate address2469 * @returns substrate address2470 */2471 restoreCrossAccountFromBigInt(number: bigint): TSubstrateAccount {2472 if (this.helper.api === null) {2473 throw 'Not connected';2474 }2475 const res = this.helper.api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();2476 if (res === undefined || res === null) {2477 throw 'Restore address error';2478 }2479 return res.toString();2480 }24812482 /**2483 * Convert etherium cross account id to substrate cross account id2484 * @param ethCrossAccount etherium cross account2485 * @returns substrate cross account id2486 */2487 convertCrossAccountFromEthCrossAccount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId {2488 if (ethCrossAccount.sub === '0') {2489 return {Ethereum: ethCrossAccount.eth.toLocaleLowerCase()};2490 }2491 2492 const ss58 = this.restoreCrossAccountFromBigInt(BigInt(ethCrossAccount.sub));2493 return {Substrate: ss58};2494 }24952496 paraSiblingSovereignAccount(paraid: number) {2497 // We are getting a *sibling* parachain sovereign account,2498 // so we need a sibling prefix: encoded(b"sibl") == 0x7369626c2499 const siblingPrefix = '0x7369626c';25002501 const encodedParaId = this.helper.getApi().createType('u32', paraid).toHex(true).substring(2);2502 const suffix = '000000000000000000000000000000000000000000000000';25032504 return siblingPrefix + encodedParaId + suffix;2505 }2506}25072508class StakingGroup extends HelperGroup<UniqueHelper> {2509 /**2510 * Stake tokens for App Promotion2511 * @param signer keyring of signer2512 * @param amountToStake amount of tokens to stake2513 * @param label extra label for log2514 * @returns2515 */2516 async stake(signer: TSigner, amountToStake: bigint, label?: string): Promise<boolean> {2517 if(typeof label === 'undefined') label = `${signer.address} amount: ${amountToStake}`;2518 const _stakeResult = await this.helper.executeExtrinsic(2519 signer, 'api.tx.appPromotion.stake',2520 [amountToStake], true,2521 );2522 // TODO extract info from stakeResult2523 return true;2524 }25252526 /**2527 * Unstake tokens for App Promotion2528 * @param signer keyring of signer2529 * @param amountToUnstake amount of tokens to unstake2530 * @param label extra label for log2531 * @returns block number where balances will be unlocked2532 */2533 async unstake(signer: TSigner, label?: string): Promise<number> {2534 if(typeof label === 'undefined') label = `${signer.address}`;2535 const _unstakeResult = await this.helper.executeExtrinsic(2536 signer, 'api.tx.appPromotion.unstake',2537 [], true,2538 );2539 // TODO extract block number fron events2540 return 1;2541 }25422543 /**2544 * Get total staked amount for address2545 * @param address substrate or ethereum address2546 * @returns total staked amount2547 */2548 async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {2549 if (address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();2550 return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();2551 }25522553 /**2554 * Get total staked per block2555 * @param address substrate or ethereum address2556 * @returns array of stakes. `block` – the number of the block in which the stake was made. `amount` - the number of tokens staked in the block2557 */2558 async getTotalStakedPerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2559 const rawTotalStakerdPerBlock = await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address]);2560 return rawTotalStakerdPerBlock.map(([block, amount]: any[]) => {2561 return {2562 block: block.toBigInt(),2563 amount: amount.toBigInt(),2564 };2565 });2566 }25672568 /**2569 * Get total pending unstake amount for address2570 * @param address substrate or ethereum address2571 * @returns total pending unstake amount2572 */2573 async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {2574 return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();2575 }25762577 /**2578 * Get pending unstake amount per block for address2579 * @param address substrate or ethereum address2580 * @returns array of pending stakes. `block` – the number of the block in which the unstake was made. `amount` - the number of tokens unstaked in the block2581 */2582 async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2583 const rawUnstakedPerBlock = await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address]);2584 const result = rawUnstakedPerBlock.map(([block, amount]: any[]) => {2585 return {2586 block: block.toBigInt(),2587 amount: amount.toBigInt(),2588 };2589 });2590 return result;2591 }2592}25932594class SchedulerGroup extends HelperGroup<UniqueHelper> {2595 constructor(helper: UniqueHelper) {2596 super(helper);2597 }25982599 cancelScheduled(signer: TSigner, scheduledId: string) {2600 return this.helper.executeExtrinsic(2601 signer,2602 'api.tx.scheduler.cancelNamed',2603 [scheduledId],2604 true,2605 );2606 }26072608 changePriority(signer: TSigner, scheduledId: string, priority: number) {2609 return this.helper.executeExtrinsic(2610 signer,2611 'api.tx.scheduler.changeNamedPriority',2612 [scheduledId, priority],2613 true,2614 );2615 }26162617 scheduleAt<T extends UniqueHelper>(2618 executionBlockNumber: number,2619 options: ISchedulerOptions = {},2620 ) {2621 return this.schedule<T>('schedule', executionBlockNumber, options);2622 }26232624 scheduleAfter<T extends UniqueHelper>(2625 blocksBeforeExecution: number,2626 options: ISchedulerOptions = {},2627 ) {2628 return this.schedule<T>('scheduleAfter', blocksBeforeExecution, options);2629 }26302631 schedule<T extends UniqueHelper>(2632 scheduleFn: 'schedule' | 'scheduleAfter',2633 blocksNum: number,2634 options: ISchedulerOptions = {},2635 ) {2636 // eslint-disable-next-line @typescript-eslint/naming-convention2637 const ScheduledHelperType = ScheduledUniqueHelper(this.helper.helperBase);2638 return this.helper.clone(ScheduledHelperType, {2639 scheduleFn,2640 blocksNum,2641 options,2642 }) as T;2643 }2644}26452646class ForeignAssetsGroup extends HelperGroup<UniqueHelper> {2647 async register(signer: TSigner, ownerAddress: TSubstrateAccount, location: any, metadata: IForeignAssetMetadata) {2648 await this.helper.executeExtrinsic(2649 signer,2650 'api.tx.foreignAssets.registerForeignAsset',2651 [ownerAddress, location, metadata],2652 true,2653 );2654 }26552656 async update(signer: TSigner, foreignAssetId: number, location: any, metadata: IForeignAssetMetadata) {2657 await this.helper.executeExtrinsic(2658 signer,2659 'api.tx.foreignAssets.updateForeignAsset',2660 [foreignAssetId, location, metadata],2661 true,2662 );2663 }2664}26652666class XcmGroup<T extends ChainHelperBase> extends HelperGroup<T> {2667 palletName: string;26682669 constructor(helper: T, palletName: string) {2670 super(helper);26712672 this.palletName = palletName;2673 }26742675 async limitedReserveTransferAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number, weightLimit: number) {2676 await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, {Limited: weightLimit}], true);2677 }2678}26792680class XTokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {2681 async transfer(signer: TSigner, currencyId: any, amount: bigint, destination: any, destWeight: number) {2682 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transfer', [currencyId, amount, destination, destWeight], true);2683 }26842685 async transferMultiasset(signer: TSigner, asset: any, destination: any, destWeight: number) {2686 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMultiasset', [asset, destination, destWeight], true);2687 }26882689 async transferMulticurrencies(signer: TSigner, currencies: any[], feeItem: number, destLocation: any, destWeight: number) {2690 await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMulticurrencies', [currencies, feeItem, destLocation, destWeight], true);2691 }2692}26932694class TokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {2695 async accounts(address: string, currencyId: any) {2696 const {free} = (await this.helper.callRpc('api.query.tokens.accounts', [address, currencyId])).toJSON() as any;2697 return BigInt(free);2698 }2699}27002701class AssetsGroup<T extends ChainHelperBase> extends HelperGroup<T> {2702 async create(signer: TSigner, assetId: number, admin: string, minimalBalance: bigint) {2703 await this.helper.executeExtrinsic(signer, 'api.tx.assets.create', [assetId, admin, minimalBalance], true);2704 }27052706 async setMetadata(signer: TSigner, assetId: number, name: string, symbol: string, decimals: number) {2707 await this.helper.executeExtrinsic(signer, 'api.tx.assets.setMetadata', [assetId, name, symbol, decimals], true);2708 }27092710 async mint(signer: TSigner, assetId: number, beneficiary: string, amount: bigint) {2711 await this.helper.executeExtrinsic(signer, 'api.tx.assets.mint', [assetId, beneficiary, amount], true);2712 }27132714 async account(assetId: string | number, address: string) {2715 const accountAsset = (2716 await this.helper.callRpc('api.query.assets.account', [assetId, address])2717 ).toJSON()! as any;27182719 if (accountAsset !== null) {2720 return BigInt(accountAsset['balance']);2721 } else {2722 return null;2723 }2724 }2725}27262727class AcalaAssetRegistryGroup extends HelperGroup<AcalaHelper> {2728 async registerForeignAsset(signer: TSigner, destination: any, metadata: AcalaAssetMetadata) {2729 await this.helper.executeExtrinsic(signer, 'api.tx.assetRegistry.registerForeignAsset', [destination, metadata], true);2730 }2731}27322733class MoonbeamAssetManagerGroup extends HelperGroup<MoonbeamHelper> {2734 makeRegisterForeignAssetProposal(assetInfo: MoonbeamAssetInfo) {2735 const apiPrefix = 'api.tx.assetManager.';27362737 const registerTx = this.helper.constructApiCall(2738 apiPrefix + 'registerForeignAsset',2739 [assetInfo.location, assetInfo.metadata, assetInfo.existentialDeposit, assetInfo.isSufficient],2740 );27412742 const setUnitsTx = this.helper.constructApiCall(2743 apiPrefix + 'setAssetUnitsPerSecond',2744 [assetInfo.location, assetInfo.unitsPerSecond, assetInfo.numAssetsWeightHint],2745 );27462747 const batchCall = this.helper.getApi().tx.utility.batchAll([registerTx, setUnitsTx]);2748 const encodedProposal = batchCall?.method.toHex() || '';2749 return encodedProposal;2750 }27512752 async assetTypeId(location: any) {2753 return await this.helper.callRpc('api.query.assetManager.assetTypeId', [location]);2754 }2755}27562757class MoonbeamDemocracyGroup extends HelperGroup<MoonbeamHelper> {2758 async notePreimage(signer: TSigner, encodedProposal: string) {2759 await this.helper.executeExtrinsic(signer, 'api.tx.democracy.notePreimage', [encodedProposal], true);2760 }27612762 externalProposeMajority(proposalHash: string) {2763 return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposalHash]);2764 }27652766 fastTrack(proposalHash: string, votingPeriod: number, delayPeriod: number) {2767 return this.helper.constructApiCall('api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);2768 }27692770 async referendumVote(signer: TSigner, referendumIndex: number, accountVote: DemocracyStandardAccountVote) {2771 await this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, {Standard: accountVote}], true);2772 }2773}27742775class MoonbeamCollectiveGroup extends HelperGroup<MoonbeamHelper> {2776 collective: string;27772778 constructor(helper: MoonbeamHelper, collective: string) {2779 super(helper);27802781 this.collective = collective;2782 }27832784 async propose(signer: TSigner, threshold: number, proposalHash: string, lengthBound: number) {2785 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.propose`, [threshold, proposalHash, lengthBound], true);2786 }27872788 async vote(signer: TSigner, proposalHash: string, proposalIndex: number, approve: boolean) {2789 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve], true);2790 }27912792 async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: number, lengthBound: number) {2793 await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [proposalHash, proposalIndex, weightBound, lengthBound], true);2794 }27952796 async proposalCount() {2797 return Number(await this.helper.callRpc(`api.query.${this.collective}.proposalCount`, []));2798 }2799}28002801export type ChainHelperBaseConstructor = new(...args: any[]) => ChainHelperBase;2802export type UniqueHelperConstructor = new(...args: any[]) => UniqueHelper;28032804export class UniqueHelper extends ChainHelperBase {2805 balance: BalanceGroup<UniqueHelper>;2806 collection: CollectionGroup;2807 nft: NFTGroup;2808 rft: RFTGroup;2809 ft: FTGroup;2810 staking: StakingGroup;2811 scheduler: SchedulerGroup;2812 foreignAssets: ForeignAssetsGroup;2813 xcm: XcmGroup<UniqueHelper>;2814 xTokens: XTokensGroup<UniqueHelper>;2815 tokens: TokensGroup<UniqueHelper>;28162817 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2818 super(logger, options.helperBase ?? UniqueHelper);28192820 this.balance = new BalanceGroup(this);2821 this.collection = new CollectionGroup(this);2822 this.nft = new NFTGroup(this);2823 this.rft = new RFTGroup(this);2824 this.ft = new FTGroup(this);2825 this.staking = new StakingGroup(this);2826 this.scheduler = new SchedulerGroup(this);2827 this.foreignAssets = new ForeignAssetsGroup(this);2828 this.xcm = new XcmGroup(this, 'polkadotXcm');2829 this.xTokens = new XTokensGroup(this);2830 this.tokens = new TokensGroup(this);2831 }28322833 getSudo<T extends UniqueHelper>() {2834 // eslint-disable-next-line @typescript-eslint/naming-convention2835 const SudoHelperType = SudoHelper(this.helperBase);2836 return this.clone(SudoHelperType) as T;2837 }2838}28392840export class XcmChainHelper extends ChainHelperBase {2841 async connect(wsEndpoint: string, _listeners?: any): Promise<void> {2842 const wsProvider = new WsProvider(wsEndpoint);2843 this.api = new ApiPromise({2844 provider: wsProvider,2845 });2846 await this.api.isReadyOrError;2847 this.network = await UniqueHelper.detectNetwork(this.api);2848 }2849}28502851export class RelayHelper extends XcmChainHelper {2852 xcm: XcmGroup<RelayHelper>;28532854 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2855 super(logger, options.helperBase ?? RelayHelper);28562857 this.xcm = new XcmGroup(this, 'xcmPallet');2858 }2859}28602861export class WestmintHelper extends XcmChainHelper {2862 balance: SubstrateBalanceGroup<WestmintHelper>;2863 xcm: XcmGroup<WestmintHelper>;2864 assets: AssetsGroup<WestmintHelper>;2865 xTokens: XTokensGroup<WestmintHelper>;28662867 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2868 super(logger, options.helperBase ?? WestmintHelper);28692870 this.balance = new SubstrateBalanceGroup(this);2871 this.xcm = new XcmGroup(this, 'polkadotXcm');2872 this.assets = new AssetsGroup(this);2873 this.xTokens = new XTokensGroup(this);2874 }2875}28762877export class MoonbeamHelper extends XcmChainHelper {2878 balance: EthereumBalanceGroup<MoonbeamHelper>;2879 assetManager: MoonbeamAssetManagerGroup;2880 assets: AssetsGroup<MoonbeamHelper>;2881 xTokens: XTokensGroup<MoonbeamHelper>;2882 democracy: MoonbeamDemocracyGroup;2883 collective: {2884 council: MoonbeamCollectiveGroup,2885 techCommittee: MoonbeamCollectiveGroup,2886 };28872888 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2889 super(logger, options.helperBase ?? MoonbeamHelper);28902891 this.balance = new EthereumBalanceGroup(this);2892 this.assetManager = new MoonbeamAssetManagerGroup(this);2893 this.assets = new AssetsGroup(this);2894 this.xTokens = new XTokensGroup(this);2895 this.democracy = new MoonbeamDemocracyGroup(this);2896 this.collective = {2897 council: new MoonbeamCollectiveGroup(this, 'councilCollective'),2898 techCommittee: new MoonbeamCollectiveGroup(this, 'techCommitteeCollective'),2899 };2900 }2901}29022903export class AcalaHelper extends XcmChainHelper {2904 balance: SubstrateBalanceGroup<AcalaHelper>;2905 assetRegistry: AcalaAssetRegistryGroup;2906 xTokens: XTokensGroup<AcalaHelper>;2907 tokens: TokensGroup<AcalaHelper>;29082909 constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2910 super(logger, options.helperBase ?? AcalaHelper);29112912 this.balance = new SubstrateBalanceGroup(this);2913 this.assetRegistry = new AcalaAssetRegistryGroup(this);2914 this.xTokens = new XTokensGroup(this);2915 this.tokens = new TokensGroup(this);2916 }29172918 getSudo<T extends AcalaHelper>() {2919 // eslint-disable-next-line @typescript-eslint/naming-convention2920 const SudoHelperType = SudoHelper(this.helperBase);2921 return this.clone(SudoHelperType) as T;2922 }2923}29242925// eslint-disable-next-line @typescript-eslint/naming-convention2926function ScheduledUniqueHelper<T extends UniqueHelperConstructor>(Base: T) {2927 return class extends Base {2928 scheduleFn: 'schedule' | 'scheduleAfter';2929 blocksNum: number;2930 options: ISchedulerOptions;29312932 constructor(...args: any[]) {2933 const logger = args[0] as ILogger;2934 const options = args[1] as {2935 scheduleFn: 'schedule' | 'scheduleAfter',2936 blocksNum: number,2937 options: ISchedulerOptions2938 };29392940 super(logger);29412942 this.scheduleFn = options.scheduleFn;2943 this.blocksNum = options.blocksNum;2944 this.options = options.options;2945 }29462947 executeExtrinsic(sender: IKeyringPair, scheduledExtrinsic: string, scheduledParams: any[], expectSuccess?: boolean): Promise<ITransactionResult> {2948 const scheduledTx = this.constructApiCall(scheduledExtrinsic, scheduledParams);2949 2950 const mandatorySchedArgs = [2951 this.blocksNum,2952 this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null,2953 this.options.priority ?? null,2954 scheduledTx,2955 ];2956 2957 let schedArgs;2958 let scheduleFn;29592960 if (this.options.scheduledId) {2961 schedArgs = [this.options.scheduledId!, ...mandatorySchedArgs];29622963 if (this.scheduleFn == 'schedule') {2964 scheduleFn = 'scheduleNamed';2965 } else if (this.scheduleFn == 'scheduleAfter') {2966 scheduleFn = 'scheduleNamedAfter';2967 }2968 } else {2969 schedArgs = mandatorySchedArgs;2970 scheduleFn = this.scheduleFn;2971 }29722973 const extrinsic = 'api.tx.scheduler.' + scheduleFn;29742975 return super.executeExtrinsic(2976 sender,2977 extrinsic,2978 schedArgs,2979 expectSuccess,2980 );2981 }2982 };2983}29842985// eslint-disable-next-line @typescript-eslint/naming-convention2986function SudoHelper<T extends ChainHelperBaseConstructor>(Base: T) {2987 return class extends Base {2988 constructor(...args: any[]) {2989 super(...args);2990 }29912992 executeExtrinsic (2993 sender: IKeyringPair,2994 extrinsic: string,2995 params: any[],2996 expectSuccess?: boolean,2997 ): Promise<ITransactionResult> {2998 const call = this.constructApiCall(extrinsic, params);2999 return super.executeExtrinsic(3000 sender,3001 'api.tx.sudo.sudo',3002 [call],3003 expectSuccess,3004 );3005 }3006 };3007}30083009export class UniqueBaseCollection {3010 helper: UniqueHelper;3011 collectionId: number;30123013 constructor(collectionId: number, uniqueHelper: UniqueHelper) {3014 this.collectionId = collectionId;3015 this.helper = uniqueHelper;3016 }30173018 async getData() {3019 return await this.helper.collection.getData(this.collectionId);3020 }30213022 async getLastTokenId() {3023 return await this.helper.collection.getLastTokenId(this.collectionId);3024 }30253026 async doesTokenExist(tokenId: number) {3027 return await this.helper.collection.doesTokenExist(this.collectionId, tokenId);3028 }30293030 async getAdmins() {3031 return await this.helper.collection.getAdmins(this.collectionId);3032 }30333034 async getAllowList() {3035 return await this.helper.collection.getAllowList(this.collectionId);3036 }30373038 async getEffectiveLimits() {3039 return await this.helper.collection.getEffectiveLimits(this.collectionId);3040 }30413042 async getProperties(propertyKeys?: string[] | null) {3043 return await this.helper.collection.getProperties(this.collectionId, propertyKeys);3044 }30453046 async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) {3047 return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj);3048 }30493050 async getOptions() {3051 return await this.helper.collection.getCollectionOptions(this.collectionId);3052 }30533054 async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) {3055 return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress);3056 }30573058 async confirmSponsorship(signer: TSigner) {3059 return await this.helper.collection.confirmSponsorship(signer, this.collectionId);3060 }30613062 async removeSponsor(signer: TSigner) {3063 return await this.helper.collection.removeSponsor(signer, this.collectionId);3064 }30653066 async setLimits(signer: TSigner, limits: ICollectionLimits) {3067 return await this.helper.collection.setLimits(signer, this.collectionId, limits);3068 }30693070 async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount) {3071 return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress);3072 }30733074 async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3075 return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj);3076 }30773078 async addToAllowList(signer: TSigner, addressObj: ICrossAccountId) {3079 return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj);3080 }30813082 async removeFromAllowList(signer: TSigner, addressObj: ICrossAccountId) {3083 return await this.helper.collection.removeFromAllowList(signer, this.collectionId, addressObj);3084 }30853086 async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3087 return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj);3088 }30893090 async setProperties(signer: TSigner, properties: IProperty[]) {3091 return await this.helper.collection.setProperties(signer, this.collectionId, properties);3092 }30933094 async deleteProperties(signer: TSigner, propertyKeys: string[]) {3095 return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys);3096 }30973098 async setPermissions(signer: TSigner, permissions: ICollectionPermissions) {3099 return await this.helper.collection.setPermissions(signer, this.collectionId, permissions);3100 }31013102 async enableNesting(signer: TSigner, permissions: INestingPermissions) {3103 return await this.helper.collection.enableNesting(signer, this.collectionId, permissions);3104 }31053106 async disableNesting(signer: TSigner) {3107 return await this.helper.collection.disableNesting(signer, this.collectionId);3108 }31093110 async burn(signer: TSigner) {3111 return await this.helper.collection.burn(signer, this.collectionId);3112 }31133114 scheduleAt<T extends UniqueHelper>(3115 executionBlockNumber: number,3116 options: ISchedulerOptions = {},3117 ) {3118 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3119 return new UniqueBaseCollection(this.collectionId, scheduledHelper);3120 }31213122 scheduleAfter<T extends UniqueHelper>(3123 blocksBeforeExecution: number,3124 options: ISchedulerOptions = {},3125 ) {3126 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3127 return new UniqueBaseCollection(this.collectionId, scheduledHelper);3128 }31293130 getSudo<T extends UniqueHelper>() {3131 return new UniqueBaseCollection(this.collectionId, this.helper.getSudo<T>());3132 }3133}313431353136export class UniqueNFTCollection extends UniqueBaseCollection {3137 getTokenObject(tokenId: number) {3138 return new UniqueNFToken(tokenId, this);3139 }31403141 async getTokensByAddress(addressObj: ICrossAccountId) {3142 return await this.helper.nft.getTokensByAddress(this.collectionId, addressObj);3143 }31443145 async getToken(tokenId: number, blockHashAt?: string) {3146 return await this.helper.nft.getToken(this.collectionId, tokenId, [], blockHashAt);3147 }31483149 async getTokenOwner(tokenId: number, blockHashAt?: string) {3150 return await this.helper.nft.getTokenOwner(this.collectionId, tokenId, blockHashAt);3151 }31523153 async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {3154 return await this.helper.nft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);3155 }31563157 async getTokenChildren(tokenId: number, blockHashAt?: string) {3158 return await this.helper.nft.getTokenChildren(this.collectionId, tokenId, blockHashAt);3159 }31603161 async getPropertyPermissions(propertyKeys: string[] | null = null) {3162 return await this.helper.nft.getPropertyPermissions(this.collectionId, propertyKeys);3163 }31643165 async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3166 return await this.helper.nft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3167 }31683169 async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId) {3170 return await this.helper.nft.transferToken(signer, this.collectionId, tokenId, addressObj);3171 }31723173 async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3174 return await this.helper.nft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj);3175 }31763177 async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId) {3178 return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj);3179 }31803181 async isTokenApproved(tokenId: number, toAddressObj: ICrossAccountId) {3182 return await this.helper.nft.isTokenApproved(this.collectionId, tokenId, toAddressObj);3183 }31843185 async mintToken(signer: TSigner, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3186 return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties});3187 }31883189 async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]) {3190 return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens);3191 }31923193 async burnToken(signer: TSigner, tokenId: number) {3194 return await this.helper.nft.burnToken(signer, this.collectionId, tokenId);3195 }31963197 async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId) {3198 return await this.helper.nft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj);3199 }32003201 async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3202 return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties);3203 }32043205 async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3206 return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3207 }32083209 async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3210 return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3211 }32123213 async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {3214 return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);3215 }32163217 async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3218 return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);3219 }32203221 scheduleAt<T extends UniqueHelper>(3222 executionBlockNumber: number,3223 options: ISchedulerOptions = {},3224 ) {3225 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3226 return new UniqueNFTCollection(this.collectionId, scheduledHelper);3227 }32283229 scheduleAfter<T extends UniqueHelper>(3230 blocksBeforeExecution: number,3231 options: ISchedulerOptions = {},3232 ) {3233 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3234 return new UniqueNFTCollection(this.collectionId, scheduledHelper);3235 }32363237 getSudo<T extends UniqueHelper>() {3238 return new UniqueNFTCollection(this.collectionId, this.helper.getSudo<T>());3239 }3240}324132423243export class UniqueRFTCollection extends UniqueBaseCollection {3244 getTokenObject(tokenId: number) {3245 return new UniqueRFToken(tokenId, this);3246 }32473248 async getToken(tokenId: number, blockHashAt?: string) {3249 return await this.helper.rft.getToken(this.collectionId, tokenId, [], blockHashAt);3250 }32513252 async getTokensByAddress(addressObj: ICrossAccountId) {3253 return await this.helper.rft.getTokensByAddress(this.collectionId, addressObj);3254 }32553256 async getTop10TokenOwners(tokenId: number) {3257 return await this.helper.rft.getTokenTop10Owners(this.collectionId, tokenId);3258 }32593260 async getTokenBalance(tokenId: number, addressObj: ICrossAccountId) {3261 return await this.helper.rft.getTokenBalance(this.collectionId, tokenId, addressObj);3262 }32633264 async getTokenTotalPieces(tokenId: number) {3265 return await this.helper.rft.getTokenTotalPieces(this.collectionId, tokenId);3266 }32673268 async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3269 return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj);3270 }32713272 async getPropertyPermissions(propertyKeys: string[] | null = null) {3273 return await this.helper.rft.getPropertyPermissions(this.collectionId, propertyKeys);3274 }32753276 async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3277 return await this.helper.rft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3278 }32793280 async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount=1n) {3281 return await this.helper.rft.transferToken(signer, this.collectionId, tokenId, addressObj, amount);3282 }32833284 async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3285 return await this.helper.rft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj, amount);3286 }32873288 async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {3289 return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, amount);3290 }32913292 async repartitionToken(signer: TSigner, tokenId: number, amount: bigint) {3293 return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount);3294 }32953296 async mintToken(signer: TSigner, pieces=1n, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3297 return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties});3298 }32993300 async mintMultipleTokens(signer: TSigner, tokens: {pieces: bigint, owner: ICrossAccountId, properties?: IProperty[]}[]) {3301 return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens);3302 }33033304 async burnToken(signer: TSigner, tokenId: number, amount=1n) {3305 return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, amount);3306 }33073308 async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n) {3309 return await this.helper.rft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, amount);3310 }33113312 async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3313 return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties);3314 }33153316 async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3317 return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3318 }33193320 async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3321 return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3322 }33233324 scheduleAt<T extends UniqueHelper>(3325 executionBlockNumber: number,3326 options: ISchedulerOptions = {},3327 ) {3328 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3329 return new UniqueRFTCollection(this.collectionId, scheduledHelper);3330 }33313332 scheduleAfter<T extends UniqueHelper>(3333 blocksBeforeExecution: number,3334 options: ISchedulerOptions = {},3335 ) {3336 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3337 return new UniqueRFTCollection(this.collectionId, scheduledHelper);3338 }33393340 getSudo<T extends UniqueHelper>() {3341 return new UniqueRFTCollection(this.collectionId, this.helper.getSudo<T>());3342 }3343}334433453346export class UniqueFTCollection extends UniqueBaseCollection {3347 async getBalance(addressObj: ICrossAccountId) {3348 return await this.helper.ft.getBalance(this.collectionId, addressObj);3349 }33503351 async getTotalPieces() {3352 return await this.helper.ft.getTotalPieces(this.collectionId);3353 }33543355 async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3356 return await this.helper.ft.getApprovedTokens(this.collectionId, fromAddressObj, toAddressObj);3357 }33583359 async getTop10Owners() {3360 return await this.helper.ft.getTop10Owners(this.collectionId);3361 }33623363 async mint(signer: TSigner, amount=1n, owner: ICrossAccountId = {Substrate: signer.address}) {3364 return await this.helper.ft.mintTokens(signer, this.collectionId, amount, owner);3365 }33663367 async mintWithOneOwner(signer: TSigner, tokens: {value: bigint}[], owner: ICrossAccountId = {Substrate: signer.address}) {3368 return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, tokens, owner);3369 }33703371 async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3372 return await this.helper.ft.transfer(signer, this.collectionId, toAddressObj, amount);3373 }33743375 async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3376 return await this.helper.ft.transferFrom(signer, this.collectionId, fromAddressObj, toAddressObj, amount);3377 }33783379 async burnTokens(signer: TSigner, amount=1n) {3380 return await this.helper.ft.burnTokens(signer, this.collectionId, amount);3381 }33823383 async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {3384 return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount);3385 }33863387 async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3388 return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);3389 }33903391 scheduleAt<T extends UniqueHelper>(3392 executionBlockNumber: number,3393 options: ISchedulerOptions = {},3394 ) {3395 const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3396 return new UniqueFTCollection(this.collectionId, scheduledHelper);3397 }33983399 scheduleAfter<T extends UniqueHelper>(3400 blocksBeforeExecution: number,3401 options: ISchedulerOptions = {},3402 ) {3403 const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3404 return new UniqueFTCollection(this.collectionId, scheduledHelper);3405 }34063407 getSudo<T extends UniqueHelper>() {3408 return new UniqueFTCollection(this.collectionId, this.helper.getSudo<T>());3409 }3410}341134123413export class UniqueBaseToken {3414 collection: UniqueNFTCollection | UniqueRFTCollection;3415 collectionId: number;3416 tokenId: number;34173418 constructor(tokenId: number, collection: UniqueNFTCollection | UniqueRFTCollection) {3419 this.collection = collection;3420 this.collectionId = collection.collectionId;3421 this.tokenId = tokenId;3422 }34233424 async getNextSponsored(addressObj: ICrossAccountId) {3425 return await this.collection.getTokenNextSponsored(this.tokenId, addressObj);3426 }34273428 async getProperties(propertyKeys?: string[] | null) {3429 return await this.collection.getTokenProperties(this.tokenId, propertyKeys);3430 }34313432 async setProperties(signer: TSigner, properties: IProperty[]) {3433 return await this.collection.setTokenProperties(signer, this.tokenId, properties);3434 }34353436 async deleteProperties(signer: TSigner, propertyKeys: string[]) {3437 return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys);3438 }34393440 async doesExist() {3441 return await this.collection.doesTokenExist(this.tokenId);3442 }34433444 nestingAccount() {3445 return this.collection.helper.util.getTokenAccount(this);3446 }34473448 scheduleAt<T extends UniqueHelper>(3449 executionBlockNumber: number,3450 options: ISchedulerOptions = {},3451 ) {3452 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3453 return new UniqueBaseToken(this.tokenId, scheduledCollection);3454 }34553456 scheduleAfter<T extends UniqueHelper>(3457 blocksBeforeExecution: number,3458 options: ISchedulerOptions = {},3459 ) {3460 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3461 return new UniqueBaseToken(this.tokenId, scheduledCollection);3462 }34633464 getSudo<T extends UniqueHelper>() {3465 return new UniqueBaseToken(this.tokenId, this.collection.getSudo<T>());3466 }3467}346834693470export class UniqueNFToken extends UniqueBaseToken {3471 collection: UniqueNFTCollection;34723473 constructor(tokenId: number, collection: UniqueNFTCollection) {3474 super(tokenId, collection);3475 this.collection = collection;3476 }34773478 async getData(blockHashAt?: string) {3479 return await this.collection.getToken(this.tokenId, blockHashAt);3480 }34813482 async getOwner(blockHashAt?: string) {3483 return await this.collection.getTokenOwner(this.tokenId, blockHashAt);3484 }34853486 async getTopmostOwner(blockHashAt?: string) {3487 return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);3488 }34893490 async getChildren(blockHashAt?: string) {3491 return await this.collection.getTokenChildren(this.tokenId, blockHashAt);3492 }34933494 async nest(signer: TSigner, toTokenObj: IToken) {3495 return await this.collection.nestToken(signer, this.tokenId, toTokenObj);3496 }34973498 async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3499 return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);3500 }35013502 async transfer(signer: TSigner, addressObj: ICrossAccountId) {3503 return await this.collection.transferToken(signer, this.tokenId, addressObj);3504 }35053506 async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3507 return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj);3508 }35093510 async approve(signer: TSigner, toAddressObj: ICrossAccountId) {3511 return await this.collection.approveToken(signer, this.tokenId, toAddressObj);3512 }35133514 async isApproved(toAddressObj: ICrossAccountId) {3515 return await this.collection.isTokenApproved(this.tokenId, toAddressObj);3516 }35173518 async burn(signer: TSigner) {3519 return await this.collection.burnToken(signer, this.tokenId);3520 }35213522 async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId) {3523 return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj);3524 }35253526 scheduleAt<T extends UniqueHelper>(3527 executionBlockNumber: number,3528 options: ISchedulerOptions = {},3529 ) {3530 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3531 return new UniqueNFToken(this.tokenId, scheduledCollection);3532 }35333534 scheduleAfter<T extends UniqueHelper>(3535 blocksBeforeExecution: number,3536 options: ISchedulerOptions = {},3537 ) {3538 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3539 return new UniqueNFToken(this.tokenId, scheduledCollection);3540 }35413542 getSudo<T extends UniqueHelper>() {3543 return new UniqueNFToken(this.tokenId, this.collection.getSudo<T>());3544 }3545}35463547export class UniqueRFToken extends UniqueBaseToken {3548 collection: UniqueRFTCollection;35493550 constructor(tokenId: number, collection: UniqueRFTCollection) {3551 super(tokenId, collection);3552 this.collection = collection;3553 }35543555 async getData(blockHashAt?: string) {3556 return await this.collection.getToken(this.tokenId, blockHashAt);3557 }35583559 async getTop10Owners() {3560 return await this.collection.getTop10TokenOwners(this.tokenId);3561 }35623563 async getBalance(addressObj: ICrossAccountId) {3564 return await this.collection.getTokenBalance(this.tokenId, addressObj);3565 }35663567 async getTotalPieces() {3568 return await this.collection.getTokenTotalPieces(this.tokenId);3569 }35703571 async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) {3572 return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj);3573 }35743575 async transfer(signer: TSigner, addressObj: ICrossAccountId, amount=1n) {3576 return await this.collection.transferToken(signer, this.tokenId, addressObj, amount);3577 }35783579 async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3580 return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj, amount);3581 }35823583 async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3584 return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount);3585 }35863587 async repartition(signer: TSigner, amount: bigint) {3588 return await this.collection.repartitionToken(signer, this.tokenId, amount);3589 }35903591 async burn(signer: TSigner, amount=1n) {3592 return await this.collection.burnToken(signer, this.tokenId, amount);3593 }35943595 async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {3596 return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj, amount);3597 }35983599 scheduleAt<T extends UniqueHelper>(3600 executionBlockNumber: number,3601 options: ISchedulerOptions = {},3602 ) {3603 const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3604 return new UniqueRFToken(this.tokenId, scheduledCollection);3605 }36063607 scheduleAfter<T extends UniqueHelper>(3608 blocksBeforeExecution: number,3609 options: ISchedulerOptions = {},3610 ) {3611 const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3612 return new UniqueRFToken(this.tokenId, scheduledCollection);3613 }36143615 getSudo<T extends UniqueHelper>() {3616 return new UniqueRFToken(this.tokenId, this.collection.getSudo<T>());3617 }3618}