--- a/.docker/Dockerfile-acala.j2 +++ b/.docker/Dockerfile-acala.j2 @@ -38,4 +38,4 @@ FROM ubuntu:22.04 as builder-acala -COPY --from=builder-acala-bin /unique_parachain/Acala/target/production/acala /unique_parachain/Acala/target/production/acala +COPY --from=builder-acala-bin /unique_parachain/Acala/target/production/acala /unique_parachain/acala/target/production/acala --- /dev/null +++ b/.docker/Dockerfile-astar.j2 @@ -0,0 +1,40 @@ +# ===== Rust builder ===== +FROM ubuntu:22.04 as rust-builder +LABEL maintainer="Unique.Network" + +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 ACALA ===== +FROM rust-builder as builder-astar-bin + +WORKDIR /unique_parachain + +RUN git clone --recurse-submodules -b {{ ASTAR_BUILD_BRANCH }} --depth 1 https://github.com/AstarNetwork/Astar.git && \ + cd Astar && \ + cargo build --release + +# ===== BIN ====== + +FROM ubuntu:22.04 as builder-astar + +COPY --from=builder-astar-bin /unique_parachain/Astar/target/release/astar-collator /unique_parachain/astar/target/release/astar --- a/.docker/Dockerfile-xcm.j2 +++ b/.docker/Dockerfile-xcm.j2 @@ -23,6 +23,7 @@ COPY ./xcm-config/launch-config-xcm-{{ NETWORK }}.json ./launch-config-xcm-{{ NETWORK }}.json COPY ./xcm-config/5validators.jsonnet ./5validators.jsonnet +COPY ./xcm-config/6validators.jsonnet ./6validators.jsonnet RUN git clone -b {{ BRANCH }} https://github.com/UniqueNetwork/unique-chain.git && \ cd unique-chain && \ @@ -50,6 +51,7 @@ COPY --from=builder-unique /unique_parachain/launch-config-xcm-{{ NETWORK }}.json /polkadot-launch/ COPY --from=builder-unique /unique_parachain/5validators.jsonnet /polkadot-launch/5validators.jsonnet +COPY --from=builder-unique /unique_parachain/6validators.jsonnet /polkadot-launch/6validators.jsonnet COPY --from=builder-unique /unique_parachain/unique-chain/target/release/unique-collator /unique-chain/target/release/ @@ -57,6 +59,7 @@ COPY --from=uniquenetwork/builder-moonbeam:{{ MOONBEAM_BUILD_BRANCH }} /unique_parachain/moonbeam/target/release/moonbeam /moonbeam/target/release/ COPY --from=uniquenetwork/builder-cumulus:{{ CUMULUS_BUILD_BRANCH }} /unique_parachain/cumulus/target/release/polkadot-parachain /cumulus/target/release/cumulus COPY --from=uniquenetwork/builder-acala:{{ ACALA_BUILD_BRANCH }} /unique_parachain/Acala/target/production/acala /acala/target/release/ +COPY --from=uniquenetwork/builder-astar:{{ ASTAR_BUILD_BRANCH }} /unique_parachain/astar/target/release/astar /astar/target/release/ COPY --from=uniquenetwork/builder-chainql:latest /chainql/target/release/chainql /chainql/target/release/ EXPOSE 9844 @@ -65,6 +68,7 @@ EXPOSE 9946 EXPOSE 9947 EXPOSE 9948 +EXPOSE 9949 CMD export NVM_DIR="$HOME/.nvm" PATH="$PATH:/chainql/target/release" && \ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && \ --- a/.docker/additional/xcm-rococo/Dockerfile-xcm-quartz-rococo.temp +++ b/.docker/additional/xcm-rococo/Dockerfile-xcm-quartz-rococo.temp @@ -2,6 +2,7 @@ FROM uniquenetwork/builder-moonbeam:{{ MOONRIVER_BUILD_BRANCH }} as moonbeam FROM uniquenetwork/builder-cumulus:{{ STATEMINE_BUILD_BRANCH }} as cumulus FROM uniquenetwork/builder-acala:{{ KARURA_BUILD_BRANCH }} as acala +FROM uniquenetwork/builder-astar:{{ SHIDEN_BUILD_BRANCH }} as astar # ===== Rust builder ===== FROM ubuntu:22.04 as rust-builder @@ -62,13 +63,14 @@ yarn install COPY --from=builder-unique /unique_parachain/.docker/additional/xcm-rococo/launch-config-xcm-quartz-rococo.json /polkadot-launch/launch-config.json -COPY --from=builder-unique /unique_parachain/.docker/xcm-config/5validators.jsonnet /polkadot-launch/5validators.jsonnet +COPY --from=builder-unique /unique_parachain/.docker/xcm-config/6validators.jsonnet /polkadot-launch/6validators.jsonnet COPY --from=builder-unique /unique_parachain/target/release/unique-collator /unique-chain/target/release/ COPY --from=polkadot /unique_parachain/polkadot/target/release/polkadot /polkadot/target/release/ COPY --from=moonbeam /unique_parachain/moonbeam/target/release/moonbeam /moonbeam/target/release/ COPY --from=cumulus /unique_parachain/cumulus/target/release/polkadot-parachain /cumulus/target/release/cumulus COPY --from=acala /unique_parachain/Acala/target/production/acala /acala/target/release/ +COPY --from=astar /unique_parachain/astar/target/release/astar /astar/target/release/ COPY --from=uniquenetwork/builder-chainql:latest /chainql/target/release/chainql /chainql/target/release/ EXPOSE 9844 @@ -76,6 +78,7 @@ EXPOSE 9946 EXPOSE 9947 EXPOSE 9948 +EXPOSE 9949 CMD export NVM_DIR="$HOME/.nvm" PATH="$PATH:/chainql/target/release" && \ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && \ --- a/.docker/additional/xcm-rococo/Dockerfile-xcm-unique-rococo.temp +++ b/.docker/additional/xcm-rococo/Dockerfile-xcm-unique-rococo.temp @@ -2,6 +2,7 @@ FROM uniquenetwork/builder-moonbeam:{{ MOONBEAM_BUILD_BRANCH }} as moonbeam FROM uniquenetwork/builder-cumulus:{{ STATEMINT_BUILD_BRANCH }} as cumulus FROM uniquenetwork/builder-acala:{{ ACALA_BUILD_BRANCH }} as acala +FROM uniquenetwork/builder-astar:{{ ASTAR_BUILD_BRANCH }} as astar # ===== Rust builder ===== FROM ubuntu:22.04 as rust-builder @@ -62,13 +63,14 @@ yarn install COPY --from=builder-unique /unique_parachain/.docker/additional/xcm-rococo/launch-config-xcm-unique-rococo.json /polkadot-launch/launch-config.json -COPY --from=builder-unique /unique_parachain/.docker/xcm-config/5validators.jsonnet /polkadot-launch/5validators.jsonnet +COPY --from=builder-unique /unique_parachain/.docker/xcm-config/6validators.jsonnet /polkadot-launch/6validators.jsonnet COPY --from=builder-unique /unique_parachain/target/release/unique-collator /unique-chain/target/release/ COPY --from=polkadot /unique_parachain/polkadot/target/release/polkadot /polkadot/target/release/ COPY --from=moonbeam /unique_parachain/moonbeam/target/release/moonbeam /moonbeam/target/release/ COPY --from=cumulus /unique_parachain/cumulus/target/release/polkadot-parachain /cumulus/target/release/cumulus COPY --from=acala /unique_parachain/Acala/target/production/acala /acala/target/release/ +COPY --from=astar /unique_parachain/astar/target/release/astar /astar/target/release/ COPY --from=uniquenetwork/builder-chainql:latest /chainql/target/release/chainql /chainql/target/release/ EXPOSE 9844 @@ -76,6 +78,7 @@ EXPOSE 9946 EXPOSE 9947 EXPOSE 9948 +EXPOSE 9949 CMD export NVM_DIR="$HOME/.nvm" PATH="$PATH:/chainql/target/release" && \ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && \ --- a/.docker/additional/xcm-rococo/docker-compose-xcm-quartz-rococo.yml +++ b/.docker/additional/xcm-rococo/docker-compose-xcm-quartz-rococo.yml @@ -13,10 +13,12 @@ - 9946 - 9947 - 9948 + - 9949 ports: - 127.0.0.1:9844:9844 - 127.0.0.1:9944:9944 - 127.0.0.1:9946:9946 - 127.0.0.1:9947:9947 - 127.0.0.1:9948:9948 + - 127.0.0.1:9949:9949 --- a/.docker/additional/xcm-rococo/docker-compose-xcm-unique-rococo.yml +++ b/.docker/additional/xcm-rococo/docker-compose-xcm-unique-rococo.yml @@ -13,10 +13,12 @@ - 9946 - 9947 - 9948 + - 9949 ports: - 127.0.0.1:9844:9844 - 127.0.0.1:9944:9944 - 127.0.0.1:9946:9946 - 127.0.0.1:9947:9947 - 127.0.0.1:9948:9948 + - 127.0.0.1:9949:9949 --- a/.docker/additional/xcm-rococo/launch-config-xcm-quartz-rococo.json +++ b/.docker/additional/xcm-rococo/launch-config-xcm-quartz-rococo.json @@ -5,7 +5,7 @@ "chainInitializer": [ "chainql", "--tla-code=spec=import '${spec}'", - "5validators.jsonnet" + "6validators.jsonnet" ], "nodes": [ { @@ -62,8 +62,18 @@ "--unsafe-ws-external", "-lparachain::candidate_validation=debug" ] + }, + { + "name": "ferdie", + "wsPort": 9899, + "rpcPort": 9898, + "port": 30999, + "flags": [ + "--unsafe-rpc-external", + "--unsafe-ws-external", + "-lparachain::candidate_validation=debug" + ] } - ], "genesis": { "runtime": { @@ -155,6 +165,23 @@ ] } ] + }, + { + "bin": "/astar/target/release/astar", + "id": "2007", + "chain": "shiden-dev", + "balance": "1000000000000000000000000", + "nodes": [ + { + "wsPort": 9949, + "port": 31205, + "name": "alice", + "flags": [ + "--unsafe-rpc-external", + "--unsafe-ws-external" + ] + } + ] } ], "simpleParachains": [], @@ -194,7 +221,19 @@ "recipient": 2095, "maxCapacity": 8, "maxMessageSize": 512 - } + }, + { + "sender": 2007, + "recipient": 2095, + "maxCapacity": 8, + "maxMessageSize": 512 + }, + { + "sender": 2095, + "recipient": 2007, + "maxCapacity": 8, + "maxMessageSize": 512 + } ], "finalization": false } --- a/.docker/additional/xcm-rococo/launch-config-xcm-unique-rococo.json +++ b/.docker/additional/xcm-rococo/launch-config-xcm-unique-rococo.json @@ -5,7 +5,7 @@ "chainInitializer": [ "chainql", "--tla-code=spec=import '${spec}'", - "5validators.jsonnet" + "6validators.jsonnet" ], "nodes": [ { @@ -62,8 +62,18 @@ "--unsafe-ws-external", "-lparachain::candidate_validation=debug" ] + }, + { + "name": "ferdie", + "wsPort": 9899, + "rpcPort": 9898, + "port": 30999, + "flags": [ + "--unsafe-rpc-external", + "--unsafe-ws-external", + "-lparachain::candidate_validation=debug" + ] } - ], "genesis": { "runtime": { @@ -155,6 +165,23 @@ ] } ] + }, + { + "bin": "/astar/target/release/astar", + "id": "2006", + "chain": "astar-dev", + "balance": "1000000000000000000000000", + "nodes": [ + { + "wsPort": 9949, + "port": 31205, + "name": "alice", + "flags": [ + "--unsafe-rpc-external", + "--unsafe-ws-external" + ] + } + ] } ], "simpleParachains": [], @@ -194,7 +221,19 @@ "recipient": 2037, "maxCapacity": 8, "maxMessageSize": 512 - } + }, + { + "sender": 2006, + "recipient": 2037, + "maxCapacity": 8, + "maxMessageSize": 512 + }, + { + "sender": 2037, + "recipient": 2006, + "maxCapacity": 8, + "maxMessageSize": 512 + } ], "finalization": false } --- a/.docker/docker-compose.tmp-xcm-tests.j2 +++ b/.docker/docker-compose.tmp-xcm-tests.j2 @@ -11,6 +11,7 @@ - 9946 - 9947 - 9948 + - 9949 ports: - 127.0.0.1:9844:9844 - 127.0.0.1:9933:9933 @@ -18,6 +19,7 @@ - 127.0.0.1:9946:9946 - 127.0.0.1:9947:9947 - 127.0.0.1:9948:9948 + - 127.0.0.1:9949:9949 logging: options: max-size: "1m" --- /dev/null +++ b/.docker/xcm-config/6validators.jsonnet @@ -0,0 +1,57 @@ + +function(spec) + spec { + genesis+: { + runtime+: { + staking+: { + validatorCount: 6, + invulnerables: [ + '5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY', + '5HpG9w8EBLe5XCrbczpwq5TSXvedjrBGCwqxK1iQ7qUsSWFc', + '5Ck5SLSHYac6WFt5UZRSsdJjwmpSZq85fd5TRNAdZQVzEAPT', + '5HKPmK9GYtE1PSLsS1qiYU9xQ9Si1NcEhdeCq9sw5bqu4ns8', + '5FCfAonRZgTFrTd9HREEyeJjDpT397KMzizE6T3DvebLFE7n', + '5CRmqmsiNFExV6VbdmPJViVxrWmkaXXvBrSX8oqBT8R9vmWk', + ], + stakers: [ + [ + '5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY', + '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY', + 100000000000000, + 'Validator', + ], + [ + '5HpG9w8EBLe5XCrbczpwq5TSXvedjrBGCwqxK1iQ7qUsSWFc', + '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty', + 100000000000000, + 'Validator', + ], + [ + '5Ck5SLSHYac6WFt5UZRSsdJjwmpSZq85fd5TRNAdZQVzEAPT', + '5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y', + 100000000000000, + 'Validator', + ], + [ + '5HKPmK9GYtE1PSLsS1qiYU9xQ9Si1NcEhdeCq9sw5bqu4ns8', + '5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy', + 100000000000000, + 'Validator', + ], + [ + '5FCfAonRZgTFrTd9HREEyeJjDpT397KMzizE6T3DvebLFE7n', + '5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw', + 100000000000000, + 'Validator', + ], + [ + '5CRmqmsiNFExV6VbdmPJViVxrWmkaXXvBrSX8oqBT8R9vmWk', + '5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL', + 100000000000000, + 'Validator', + ], + ], + }, + }, + }, + } --- a/.docker/xcm-config/launch-config-xcm-quartz.j2 +++ b/.docker/xcm-config/launch-config-xcm-quartz.j2 @@ -5,7 +5,7 @@ "chainInitializer": [ "chainql", "--tla-code=spec=import '${spec}'", - "5validators.jsonnet" + "6validators.jsonnet" ], "nodes": [ { @@ -62,8 +62,18 @@ "--unsafe-ws-external", "-lparachain::candidate_validation=debug" ] + }, + { + "name": "ferdie", + "wsPort": 9899, + "rpcPort": 9898, + "port": 30999, + "flags": [ + "--unsafe-rpc-external", + "--unsafe-ws-external", + "-lparachain::candidate_validation=debug" + ] } - ], "genesis": { "runtime": { @@ -155,6 +165,23 @@ ] } ] + }, + { + "bin": "/astar/target/release/astar", + "id": "2007", + "chain": "shiden-dev", + "balance": "1000000000000000000000000", + "nodes": [ + { + "wsPort": 9949, + "port": 31205, + "name": "alice", + "flags": [ + "--unsafe-rpc-external", + "--unsafe-ws-external" + ] + } + ] } ], "simpleParachains": [], @@ -194,7 +221,19 @@ "recipient": 2095, "maxCapacity": 8, "maxMessageSize": 512 - } + }, + { + "sender": 2007, + "recipient": 2095, + "maxCapacity": 8, + "maxMessageSize": 512 + }, + { + "sender": 2095, + "recipient": 2007, + "maxCapacity": 8, + "maxMessageSize": 512 + } ], "finalization": false } --- a/.docker/xcm-config/launch-config-xcm-unique.j2 +++ b/.docker/xcm-config/launch-config-xcm-unique.j2 @@ -5,7 +5,7 @@ "chainInitializer": [ "chainql", "--tla-code=spec=import '${spec}'", - "5validators.jsonnet" + "6validators.jsonnet" ], "nodes": [ { @@ -62,8 +62,18 @@ "--unsafe-ws-external", "-lparachain::candidate_validation=debug" ] - } - + }, + { + "name": "ferdie", + "wsPort": 9899, + "rpcPort": 9898, + "port": 30999, + "flags": [ + "--unsafe-rpc-external", + "--unsafe-ws-external", + "-lparachain::candidate_validation=debug" + ] + } ], "genesis": { "runtime": { @@ -93,7 +103,7 @@ "-lxcm=trace,parity_ws::handler=debug,jsonrpsee_core=trace,jsonrpsee-core=trace,jsonrpsee_ws_server=debug", "--unsafe-rpc-external", "--unsafe-ws-external" - ] + ] } ] }, @@ -115,7 +125,7 @@ "flags": [ "--unsafe-rpc-external", "--unsafe-ws-external" - ] + ] } ] }, @@ -133,7 +143,7 @@ "flags": [ "--unsafe-rpc-external", "--unsafe-ws-external", - "--", + "--", "--execution=wasm" ] } @@ -152,9 +162,26 @@ "flags": [ "--unsafe-rpc-external", "--unsafe-ws-external" - ] + ] } ] + }, + { + "bin": "/astar/target/release/astar", + "id": "2006", + "chain": "astar-dev", + "balance": "1000000000000000000000000", + "nodes": [ + { + "wsPort": 9949, + "port": 31205, + "name": "alice", + "flags": [ + "--unsafe-rpc-external", + "--unsafe-ws-external" + ] + } + ] } ], "simpleParachains": [], @@ -194,7 +221,19 @@ "recipient": 2037, "maxCapacity": 8, "maxMessageSize": 512 - } + }, + { + "sender": 2006, + "recipient": 2037, + "maxCapacity": 8, + "maxMessageSize": 512 + }, + { + "sender": 2037, + "recipient": 2006, + "maxCapacity": 8, + "maxMessageSize": 512 + } ], "finalization": false } --- a/.env +++ b/.env @@ -7,6 +7,7 @@ STATEMINT_BUILD_BRANCH=release-parachains-v9370 ACALA_BUILD_BRANCH=2.12.0 MOONBEAM_BUILD_BRANCH=runtime-2100 +ASTAR_BUILD_BRANCH=v4.49.0 UNIQUE_MAINNET_BRANCH=release-v930033-fix-gas-price UNIQUE_REPLICA_FROM=wss://ws.unique.network:443 @@ -14,6 +15,7 @@ STATEMINE_BUILD_BRANCH=release-parachains-v9370 KARURA_BUILD_BRANCH=release-karura-2.15.0 MOONRIVER_BUILD_BRANCH=runtime-2201 +SHIDEN_BUILD_BRANCH=v4.49.0 QUARTZ_MAINNET_BRANCH=release-v930034-fix-gas-price QUARTZ_REPLICA_FROM=wss://ws-quartz.unique.network:443 --- a/.github/workflows/xcm.yml +++ b/.github/workflows/xcm.yml @@ -18,7 +18,7 @@ name: Prepare execution matrix - runs-on: [XL] + runs-on: [self-hosted-ci] outputs: matrix: ${{ steps.create_matrix.outputs.matrix }} @@ -41,8 +41,8 @@ with: matrix: | network {opal}, relay_branch {${{ env.UNIQUEWEST_MAINNET_BRANCH }}}, acala_version {${{ env.ACALA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONBEAM_BUILD_BRANCH }}}, cumulus_version {${{ env.WESTMINT_BUILD_BRANCH }}}, runtest {testXcmOpal} - network {quartz}, relay_branch {${{ env.KUSAMA_MAINNET_BRANCH }}}, acala_version {${{ env.KARURA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONRIVER_BUILD_BRANCH }}}, cumulus_version {${{ env.STATEMINE_BUILD_BRANCH }}}, runtest {testXcmQuartz} - network {unique}, relay_branch {${{ env.POLKADOT_MAINNET_BRANCH }}}, acala_version {${{ env.ACALA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONBEAM_BUILD_BRANCH }}}, cumulus_version {${{ env.STATEMINT_BUILD_BRANCH }}}, runtest {testXcmUnique} + network {quartz}, relay_branch {${{ env.KUSAMA_MAINNET_BRANCH }}}, acala_version {${{ env.KARURA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONRIVER_BUILD_BRANCH }}}, cumulus_version {${{ env.STATEMINE_BUILD_BRANCH }}}, astar_version {${{ env.SHIDEN_BUILD_BRANCH }}}, runtest {testXcmQuartz} + network {unique}, relay_branch {${{ env.POLKADOT_MAINNET_BRANCH }}}, acala_version {${{ env.ACALA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONBEAM_BUILD_BRANCH }}}, cumulus_version {${{ env.STATEMINT_BUILD_BRANCH }}}, astar_version {${{ env.ASTAR_BUILD_BRANCH }}}, runtest {testXcmUnique} xcm-build: @@ -184,7 +184,6 @@ fi shell: bash - # Check CUMULUS version and build it if it doesn't exist in repository - name: Generate ENV related extend Dockerfile file for CUMULUS uses: cuchi/jinja2-action@v1.2.0 @@ -218,6 +217,41 @@ fi shell: bash + + # Check ASTAR version and build it if it doesn't exist in repository + - name: Generate ENV related extend Dockerfile file for ASTAR + uses: cuchi/jinja2-action@v1.2.0 + with: + template: .docker/Dockerfile-astar.j2 + output_file: .docker/Dockerfile-astar.${{ matrix.astar_version }}.yml + variables: | + RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }} + ASTAR_BUILD_BRANCH=${{ matrix.astar_version }} + + - name: Check if the dockerhub repository contains the needed ASTAR version + run: | + # aquire token + TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${{ secrets.CORE_DOCKERHUB_USERNAME }}'", "password": "'${{ secrets.CORE_DOCKERHUB_TOKEN }}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token) + export TOKEN=$TOKEN + + # Get TAGS from DOCKERHUB repository + ASTAR_TAGS=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/uniquenetwork/builder-astar/tags/?page_size=100 | jq -r '."results"[]["name"]') + # Show TAGS + echo "ASTAR TAGS:" + echo $ASTAR_TAGS + # Check correct version ASTAR and build it if it doesn't exist in ASTAR TAGS + if [[ ${ASTAR_TAGS[*]} =~ (^|[[:space:]])"${{ matrix.astar_version }}"($|[[:space:]]) ]]; then + echo "Repository has needed ASTAR version"; + docker pull uniquenetwork/builder-astar:${{ matrix.astar_version }} + else + echo "Repository has not needed ASTAR version, so build it"; + cd .docker/ && docker build --no-cache --file ./Dockerfile-astar.${{ matrix.astar_version }}.yml --tag uniquenetwork/builder-astar:${{ matrix.astar_version }} . + echo "Push needed ASTAR version to the repository"; + docker push uniquenetwork/builder-astar:${{ matrix.astar_version }} + fi + shell: bash + + - name: Generate ENV related extend launch-config file uses: cuchi/jinja2-action@v1.2.0 with: @@ -242,6 +276,7 @@ POLKADOT_LAUNCH_BRANCH=${{ env.POLKADOT_LAUNCH_BRANCH }} BRANCH=${{ github.head_ref }} ACALA_BUILD_BRANCH=${{ matrix.acala_version }} + ASTAR_BUILD_BRANCH=${{ matrix.astar_version }} MOONBEAM_BUILD_BRANCH=${{ matrix.moonbeam_version }} CUMULUS_BUILD_BRANCH=${{ matrix.cumulus_version }} --- a/tests/src/config.ts +++ b/tests/src/config.ts @@ -24,6 +24,8 @@ karuraUrl: process.env.acalaUrl || 'ws://127.0.0.1:9946', moonbeamUrl: process.env.moonbeamUrl || 'ws://127.0.0.1:9947', moonriverUrl: process.env.moonbeamUrl || 'ws://127.0.0.1:9947', + astarUrl: process.env.astarUrl || 'ws://127.0.0.1:9949', + shidenUrl: process.env.shidenUrl || 'ws://127.0.0.1:9949', westmintUrl: process.env.westmintUrl || 'ws://127.0.0.1:9948', statemineUrl: process.env.statemineUrl || 'ws://127.0.0.1:9948', statemintUrl: process.env.statemintUrl || 'ws://127.0.0.1:9948', --- a/tests/src/util/index.ts +++ b/tests/src/util/index.ts @@ -11,7 +11,7 @@ import config from '../config'; import {ChainHelperBase} from './playgrounds/unique'; import {ILogger} from './playgrounds/types'; -import {DevUniqueHelper, SilentLogger, SilentConsole, DevMoonbeamHelper, DevMoonriverHelper, DevAcalaHelper, DevKaruraHelper, DevRelayHelper, DevWestmintHelper, DevStatemineHelper, DevStatemintHelper} from './playgrounds/unique.dev'; +import {DevUniqueHelper, SilentLogger, SilentConsole, DevMoonbeamHelper, DevMoonriverHelper, DevAcalaHelper, DevKaruraHelper, DevRelayHelper, DevWestmintHelper, DevStatemineHelper, DevStatemintHelper, DevAstarHelper, DevShidenHelper} from './playgrounds/unique.dev'; import {dirname} from 'path'; import {fileURLToPath} from 'url'; @@ -101,6 +101,14 @@ return usingPlaygroundsGeneral(DevMoonriverHelper, url, code); }; +export const usingAstarPlaygrounds = (url: string, code: (helper: DevAstarHelper, privateKey: (seed: string) => Promise) => Promise) => { + return usingPlaygroundsGeneral(DevAstarHelper, url, code); +}; + +export const usingShidenPlaygrounds = (url: string, code: (helper: DevShidenHelper, privateKey: (seed: string) => Promise) => Promise) => { + return usingPlaygroundsGeneral(DevShidenHelper, url, code); +}; + export const MINIMUM_DONOR_FUND = 100_000n; export const DONOR_FUNDING = 2_000_000n; --- a/tests/src/util/playgrounds/unique.dev.ts +++ b/tests/src/util/playgrounds/unique.dev.ts @@ -3,7 +3,7 @@ import {stringToU8a} from '@polkadot/util'; import {encodeAddress, mnemonicGenerate} from '@polkadot/util-crypto'; -import {UniqueHelper, MoonbeamHelper, ChainHelperBase, AcalaHelper, RelayHelper, WestmintHelper} from './unique'; +import {UniqueHelper, MoonbeamHelper, ChainHelperBase, AcalaHelper, RelayHelper, WestmintHelper, AstarHelper} from './unique'; import {ApiPromise, Keyring, WsProvider} from '@polkadot/api'; import * as defs from '../../interfaces/definitions'; import {IKeyringPair} from '@polkadot/types/types'; @@ -173,6 +173,28 @@ } } +export class DevAstarHelper extends AstarHelper { + wait: WaitGroup; + + constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) { + options.helperBase = options.helperBase ?? DevAstarHelper; + + super(logger, options); + this.wait = new WaitGroup(this); + } +} + +export class DevShidenHelper extends AstarHelper { + wait: WaitGroup; + + constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) { + options.helperBase = options.helperBase ?? DevShidenHelper; + + super(logger, options); + this.wait = new WaitGroup(this); + } +} + export class DevAcalaHelper extends AcalaHelper { wait: WaitGroup; --- a/tests/src/util/playgrounds/unique.ts +++ b/tests/src/util/playgrounds/unique.ts @@ -3243,6 +3243,26 @@ } } +export class AstarHelper extends XcmChainHelper { + balance: SubstrateBalanceGroup; + assets: AssetsGroup; + xcm: XcmGroup; + + constructor(logger?: ILogger, options: {[key: string]: any} = {}) { + super(logger, options.helperBase ?? AstarHelper); + + this.balance = new SubstrateBalanceGroup(this); + this.assets = new AssetsGroup(this); + this.xcm = new XcmGroup(this, 'polkadotXcm'); + } + + getSudo() { + // eslint-disable-next-line @typescript-eslint/naming-convention + const SudoHelperType = SudoHelper(this.helperBase); + return this.clone(SudoHelperType) as T; + } +} + export class AcalaHelper extends XcmChainHelper { balance: SubstrateBalanceGroup; assetRegistry: AcalaAssetRegistryGroup; --- a/tests/src/xcm/xcmQuartz.test.ts +++ b/tests/src/xcm/xcmQuartz.test.ts @@ -18,12 +18,13 @@ import {blake2AsHex} from '@polkadot/util-crypto'; import config from '../config'; import {XcmV2TraitsError} from '../interfaces'; -import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds} from '../util'; +import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds, usingShidenPlaygrounds} from '../util'; const QUARTZ_CHAIN = 2095; const STATEMINE_CHAIN = 1000; const KARURA_CHAIN = 2000; const MOONRIVER_CHAIN = 2023; +const SHIDEN_CHAIN = 2007; const STATEMINE_PALLET_INSTANCE = 50; @@ -31,10 +32,13 @@ const statemineUrl = config.statemineUrl; const karuraUrl = config.karuraUrl; const moonriverUrl = config.moonriverUrl; +const shidenUrl = config.shidenUrl; const RELAY_DECIMALS = 12; const STATEMINE_DECIMALS = 12; const KARURA_DECIMALS = 12; +const SHIDEN_DECIMALS = 18n; +const QTZ_DECIMALS = 18n; const TRANSFER_AMOUNT = 2000000000000000000000000n; @@ -978,3 +982,216 @@ expect(qtzFees == 0n).to.be.true; }); }); + +describeXCM('[XCM] Integration test: Exchanging tokens with Shiden', () => { + let alice: IKeyringPair; + let sender: IKeyringPair; + + const QTZ_ASSET_ID_ON_SHIDEN = 1; + const QTZ_MINIMAL_BALANCE_ON_SHIDEN = 1n; + + // Quartz -> Shiden + const shidenInitialBalance = 1n * (10n ** SHIDEN_DECIMALS); // 1 SHD, existential deposit required to actually create the account on Shiden + const unitsPerSecond = 228_000_000_000n; // This is Phala's value. What will be ours? + const qtzToShidenTransferred = 10n * (10n ** QTZ_DECIMALS); // 10 QTZ + const qtzToShidenArrived = 9_999_999_999_088_000_000n; // 9.999 ... QTZ, Shiden takes a commision in foreign tokens + const senderIinitialBalanceQTZ = 100n * (10n ** QTZ_DECIMALS); // How many QTZ sender has initially + const senderBalanceAfterXCM = 89_946678090945539197n; // 89.94... QTZ after XCM call + + // Shiden -> Quartz + const qtzFromShidenTransfered = 5n * (10n ** QTZ_DECIMALS); // 5 QTZ + const qtzOnShidenLeft = qtzToShidenArrived - qtzFromShidenTransfered; // 4.999_999_999_088_000_000n QTZ + + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + alice = await privateKey('//Alice'); + [sender] = await helper.arrange.createAccounts([100n], alice); + console.log('sender', sender.address); + + // Set the default version to wrap the first message to other chains. + await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION); + }); + + await usingShidenPlaygrounds(shidenUrl, async (helper) => { + console.log('1. Create foreign asset and metadata'); + // TODO update metadata with values from production + await helper.assets.create( + alice, + QTZ_ASSET_ID_ON_SHIDEN, + alice.address, + QTZ_MINIMAL_BALANCE_ON_SHIDEN, + ); + + await helper.assets.setMetadata( + alice, + QTZ_ASSET_ID_ON_SHIDEN, + 'Cross chain QTZ', + 'xcQTZ', + Number(QTZ_DECIMALS), + ); + + console.log('2. Register asset location on Shiden'); + const assetLocation = { + V1: { + parents: 1, + interior: { + X1: { + Parachain: QUARTZ_CHAIN, + }, + }, + }, + }; + + await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, QTZ_ASSET_ID_ON_SHIDEN]); + + console.log('3. Set QTZ payment for XCM execution on Shiden'); + await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]); + + console.log('4. Transfer 1 SDN to recipient to create the account (needed due to existential balance)'); + await helper.balance.transferToSubstrate(alice, sender.address, shidenInitialBalance); + }); + }); + + itSub('Should connect and send QTZ to Shiden', async ({helper}) => { + const destination = { + V2: { + parents: 1, + interior: { + X1: { + Parachain: SHIDEN_CHAIN, + }, + }, + }, + }; + + const beneficiary = { + V2: { + parents: 0, + interior: { + X1: { + AccountId32: { + network: 'Any', + id: sender.addressRaw, + }, + }, + }, + }, + }; + + const assets = { + V2: [ + { + id: { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + fun: { + Fungible: qtzToShidenTransferred, + }, + }, + ], + }; + + // Initial balance is 100 QTZ + const balanceBefore = await helper.balance.getSubstrate(sender.address); + console.log(`Initial balance is: ${balanceBefore}`); + expect(balanceBefore).to.eq(senderIinitialBalanceQTZ); + + const feeAssetItem = 0; + await helper.xcm.limitedReserveTransferAssets(sender, destination, beneficiary, assets, feeAssetItem, 'Unlimited'); + + // Balance after reserve transfer is less than 90 + const balanceAfter = await helper.balance.getSubstrate(sender.address); + console.log(`QTZ Balance on Quartz after XCM is: ${balanceAfter}`); + console.log(`Quartz's QTZ commission is: ${balanceBefore - balanceAfter}`); + expect(balanceAfter).to.eq(senderBalanceAfterXCM); + + await usingShidenPlaygrounds(shidenUrl, async (helper) => { + await helper.wait.newBlocks(3); + const xcQTZbalance = await helper.assets.account(QTZ_ASSET_ID_ON_SHIDEN, sender.address); + const shidenBalance = await helper.balance.getSubstrate(sender.address); + + console.log(`xcQTZ balance on Shiden after XCM is: ${xcQTZbalance}`); + console.log(`Shiden's QTZ commission is: ${qtzToShidenTransferred - xcQTZbalance!}`); + + expect(xcQTZbalance).to.eq(qtzToShidenArrived); + // SHD balance does not changed: + expect(shidenBalance).to.eq(shidenInitialBalance); + }); + }); + + itSub('Should connect to Shiden and send QTZ back', async ({helper}) => { + await usingShidenPlaygrounds(shidenUrl, async (helper) => { + const destination = { + V1: { + parents: 1, + interior: { + X1: { + Parachain: QUARTZ_CHAIN, + }, + }, + }, + }; + + const beneficiary = { + V1: { + parents: 0, + interior: { + X1: { + AccountId32: { + network: 'Any', + id: sender.addressRaw, + }, + }, + }, + }, + }; + + const assets = { + V1: [ + { + id: { + Concrete: { + parents: 1, + interior: { + X1: { + Parachain: QUARTZ_CHAIN, + }, + }, + }, + }, + fun: { + Fungible: qtzFromShidenTransfered, + }, + }, + ], + }; + + // Initial balance is 1 SDN + const balanceSDNbefore = await helper.balance.getSubstrate(sender.address); + console.log(`SDN balance is: ${balanceSDNbefore}, it does not changed`); + expect(balanceSDNbefore).to.eq(shidenInitialBalance); + + const feeAssetItem = 0; + // this is non-standard polkadotXcm extension for Astar only. It calls InitiateReserveWithdraw + await helper.executeExtrinsic(sender, 'api.tx.polkadotXcm.reserveWithdrawAssets', [destination, beneficiary, assets, feeAssetItem]); + + // Balance after reserve transfer is less than 1 SDN + const xcQTZbalance = await helper.assets.account(QTZ_ASSET_ID_ON_SHIDEN, sender.address); + const balanceSDN = await helper.balance.getSubstrate(sender.address); + console.log(`xcQTZ balance on Shiden after XCM is: ${xcQTZbalance}`); + + // Assert: xcQTZ balance correctly decreased + expect(xcQTZbalance).to.eq(qtzOnShidenLeft); + // Assert: SDN balance is 0.996... + expect(balanceSDN / (10n ** (SHIDEN_DECIMALS - 3n))).to.eq(996n); + }); + + await helper.wait.newBlocks(3); + const balanceQTZ = await helper.balance.getSubstrate(sender.address); + console.log(`QTZ Balance on Quartz after XCM is: ${balanceQTZ}`); + expect(balanceQTZ).to.eq(senderBalanceAfterXCM + qtzFromShidenTransfered); + }); +}); --- a/tests/src/xcm/xcmUnique.test.ts +++ b/tests/src/xcm/xcmUnique.test.ts @@ -18,12 +18,13 @@ import {blake2AsHex} from '@polkadot/util-crypto'; import config from '../config'; import {XcmV2TraitsError} from '../interfaces'; -import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds, usingStatemintPlaygrounds} from '../util'; +import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds, usingStatemintPlaygrounds, usingAstarPlaygrounds} from '../util'; const UNIQUE_CHAIN = 2037; const STATEMINT_CHAIN = 1000; const ACALA_CHAIN = 2000; const MOONBEAM_CHAIN = 2004; +const ASTAR_CHAIN = 2006; const STATEMINT_PALLET_INSTANCE = 50; @@ -31,10 +32,13 @@ const statemintUrl = config.statemintUrl; const acalaUrl = config.acalaUrl; const moonbeamUrl = config.moonbeamUrl; +const astarUrl = config.astarUrl; const RELAY_DECIMALS = 12; const STATEMINT_DECIMALS = 12; const ACALA_DECIMALS = 12; +const ASTAR_DECIMALS = 18n; +const UNQ_DECIMALS = 18n; const TRANSFER_AMOUNT = 2000000000000000000000000n; @@ -980,3 +984,271 @@ expect(unqFees == 0n).to.be.true; }); }); + +describeXCM('[XCM] Integration test: Exchanging tokens with Astar', () => { + let alice: IKeyringPair; + let randomAccount: IKeyringPair; + + const UNQ_ASSET_ID_ON_SHIDEN = 1; + const UNQ_MINIMAL_BALANCE_ON_SHIDEN = 1n; + + // Unique -> Astar + const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); // 1 ASTR, existential deposit required to actually create the account on Shiden. + const unitsPerSecond = 228_000_000_000n; // This is Phala's value. What will be ours? + const unqToAstarTransferred = 10n * (10n ** UNQ_DECIMALS); // 10 UNQ + const unqToAstarArrived = 9_999_999_999_088_000_000n; // 9.999 ... UNQ, Shiden takes a commision in foreign tokens + const senderIinitialBalanceUNQ = 100n * (10n ** UNQ_DECIMALS); // How many UNQ sender has initially + const senderBalanceAfterXCM = 89_946678090945539197n; // 89.94... UNQ after XCM call + + // Astar -> Unique + const unqFromAstarTransfered = 5n * (10n ** UNQ_DECIMALS); // 5 UNQ + const unqOnAstarLeft = unqToAstarArrived - unqFromAstarTransfered; // 4.999_999_999_088_000_000n UNQ + + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + alice = await privateKey('//Alice'); + [randomAccount] = await helper.arrange.createAccounts([100n], alice); + console.log('randomAccount', randomAccount.address); + + // Set the default version to wrap the first message to other chains. + await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION); + }); + + await usingAstarPlaygrounds(astarUrl, async (helper) => { + console.log('1. Create foreign asset and metadata'); + // TODO update metadata with values from production + await helper.assets.create( + alice, + UNQ_ASSET_ID_ON_SHIDEN, + alice.address, + UNQ_MINIMAL_BALANCE_ON_SHIDEN, + ); + + await helper.assets.setMetadata( + alice, + UNQ_ASSET_ID_ON_SHIDEN, + 'Cross chain UNQ', + 'xcUNQ', + Number(UNQ_DECIMALS), + ); + + console.log('2. Register asset location on Astar'); + const assetLocation = { + V1: { + parents: 1, + interior: { + X1: { + Parachain: UNIQUE_CHAIN, + }, + }, + }, + }; + + await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, UNQ_ASSET_ID_ON_SHIDEN]); + + console.log('3. Set UNQ payment for XCM execution on Astar'); + await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]); + + console.log('4. Transfer 1 ASTR to recipient to create the account (needed due to existential balance)'); + await helper.balance.transferToSubstrate(alice, randomAccount.address, astarInitialBalance); + }); + }); + + itSub('Should connect and send UNQ to Astar', async ({helper}) => { + const destination = { + V2: { + parents: 1, + interior: { + X1: { + Parachain: ASTAR_CHAIN, + }, + }, + }, + }; + + const beneficiary = { + V2: { + parents: 0, + interior: { + X1: { + AccountId32: { + network: 'Any', + id: randomAccount.addressRaw, + }, + }, + }, + }, + }; + + const assets = { + V2: [ + { + id: { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + fun: { + Fungible: unqToAstarTransferred, + }, + }, + ], + }; + + // Initial balance is 100 UNQ + const balanceBefore = await helper.balance.getSubstrate(randomAccount.address); + console.log(`Initial balance is: ${balanceBefore}`); + expect(balanceBefore).to.eq(senderIinitialBalanceUNQ); + + const feeAssetItem = 0; + await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited'); + + // Balance after reserve transfer is less than 90 + const balanceAfter = await helper.balance.getSubstrate(randomAccount.address); + console.log(`UNQ Balance on Unique after XCM is: ${balanceAfter}`); + console.log(`Unique's UNQ commission is: ${balanceBefore - balanceAfter}`); + expect(balanceAfter).to.eq(senderBalanceAfterXCM); + + await usingAstarPlaygrounds(astarUrl, async (helper) => { + await helper.wait.newBlocks(3); + const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_SHIDEN, randomAccount.address); + const astarBalance = await helper.balance.getSubstrate(randomAccount.address); + + console.log(`xcUNQ balance on Astar after XCM is: ${xcUNQbalance}`); + console.log(`Astar's UNQ commission is: ${unqToAstarTransferred - xcUNQbalance!}`); + + expect(xcUNQbalance).to.eq(unqToAstarArrived); + // Astar balance does not changed + expect(astarBalance).to.eq(astarInitialBalance); + }); + }); + + itSub('Should connect to Astar and send UNQ back', async ({helper}) => { + await usingAstarPlaygrounds(astarUrl, async (helper) => { + const destination = { + V1: { + parents: 1, + interior: { + X1: { + Parachain: UNIQUE_CHAIN, + }, + }, + }, + }; + + const beneficiary = { + V1: { + parents: 0, + interior: { + X1: { + AccountId32: { + network: 'Any', + id: randomAccount.addressRaw, + }, + }, + }, + }, + }; + + const assets = { + V1: [ + { + id: { + Concrete: { + parents: 1, + interior: { + X1: { + Parachain: UNIQUE_CHAIN, + }, + }, + }, + }, + fun: { + Fungible: unqFromAstarTransfered, + }, + }, + ], + }; + + // Initial balance is 1 ASTR + const balanceASTRbefore = await helper.balance.getSubstrate(randomAccount.address); + console.log(`ASTR balance is: ${balanceASTRbefore}, it does not changed`); + expect(balanceASTRbefore).to.eq(astarInitialBalance); + + const feeAssetItem = 0; + // this is non-standard polkadotXcm extension for Astar only. It calls InitiateReserveWithdraw + await helper.executeExtrinsic(randomAccount, 'api.tx.polkadotXcm.reserveWithdrawAssets', [destination, beneficiary, assets, feeAssetItem]); + + const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_SHIDEN, randomAccount.address); + const balanceAstar = await helper.balance.getSubstrate(randomAccount.address); + console.log(`xcUNQ balance on Astar after XCM is: ${xcUNQbalance}`); + + // Assert: xcUNQ balance correctly decreased + expect(xcUNQbalance).to.eq(unqOnAstarLeft); + // Assert: ASTR balance is 0.996... + expect(balanceAstar / (10n ** (ASTAR_DECIMALS - 3n))).to.eq(996n); + }); + + await helper.wait.newBlocks(3); + const balanceUNQ = await helper.balance.getSubstrate(randomAccount.address); + console.log(`UNQ Balance on Unique after XCM is: ${balanceUNQ}`); + expect(balanceUNQ).to.eq(senderBalanceAfterXCM + unqFromAstarTransfered); + }); + + itSub.skip('Should not accept limitedReserveTransfer of UNQ from ASTAR', async ({helper}) => { + await usingAstarPlaygrounds(astarUrl, async (helper) => { + const destination = { + V1: { + parents: 1, + interior: { + X1: { + Parachain: UNIQUE_CHAIN, + }, + }, + }, + }; + + const beneficiary = { + V1: { + parents: 0, + interior: { + X1: { + AccountId32: { + network: 'Any', + id: randomAccount.addressRaw, + }, + }, + }, + }, + }; + + const assets = { + V1: [ + { + id: { + Concrete: { + parents: 1, + interior: { + X1: { + Parachain: UNIQUE_CHAIN, + }, + }, + }, + }, + fun: { + Fungible: unqFromAstarTransfered, + }, + }, + ], + }; + + // Initial balance is 1 ASTAR + expect(await helper.balance.getSubstrate(randomAccount.address)).to.eq(astarInitialBalance); + + const feeAssetItem = 0; + // TODO: expect rejected: + await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited'); + }); + }); +});