├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github ├── dependabot.yml └── workflows │ ├── check.yml │ ├── ci.yml │ └── update.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .prettierignore ├── .vscode └── settings.json ├── .yarn └── releases │ └── yarn-4.1.1.cjs ├── .yarnrc.yml ├── README.md ├── helpers ├── api │ ├── index.ts │ └── query.ts └── index.ts ├── networks ├── acala-next.ts ├── acala.ts ├── all.ts ├── assethub.ts ├── astar.ts ├── bifrost.ts ├── centrifuge.ts ├── crust.ts ├── darwinia.ts ├── hydraDX.ts ├── index.ts ├── interlay.ts ├── moonbeam.ts ├── parallel.ts ├── phala.ts ├── polkadot.ts ├── types.ts └── unique.ts ├── package.json ├── scripts ├── configs │ ├── acala.yml │ ├── altair.yml │ ├── astar.yml │ ├── basilisk.yml │ ├── bifrost.yml │ ├── bifrostpolkadot.yml │ ├── centrifuge.yml │ ├── crab.yml │ ├── crust.yml │ ├── heiko.yml │ ├── hydraDX.yml │ ├── interlay.yml │ ├── karura.yml │ ├── khala.yml │ ├── kintsugi.yml │ ├── kusama.yml │ ├── moonbeam.yml │ ├── moonriver.yml │ ├── parallel.yml │ ├── phala.yml │ ├── polkadot.yml │ ├── quartz.yml │ ├── shiden.yml │ ├── statemine.yml │ ├── statemint.yml │ └── unique.yml ├── run-all.sh └── update-env.ts ├── tests ├── acala │ ├── __snapshots__ │ │ ├── dex.test.ts.snap │ │ ├── homa.test.ts.snap │ │ └── stable-asset.test.ts.snap │ ├── aggregated-dex.test.ts │ ├── dex.test.ts │ ├── homa.test.ts │ └── stable-asset.test.ts ├── bridge-sdk │ ├── __snapshots__ │ │ ├── kusama.test.ts.snap │ │ └── polkadot.test.ts.snap │ ├── kusama.test.ts │ ├── polkadot.test.ts │ └── shared.ts └── xcm-transfer │ ├── __snapshots__ │ ├── kusama-para.test.ts.snap │ ├── kusama-relay.test.ts.snap │ ├── polkadot-para.test.ts.snap │ └── polkadot-relay.test.ts.snap │ ├── kusama-para.test.ts │ ├── kusama-relay.test.ts │ ├── playground.test.ts │ ├── polkadot-para.test.ts │ ├── polkadot-relay.test.ts │ └── shared.ts ├── tsconfig.json ├── vitest.config.mts ├── wasm ├── acala-2240.wasm ├── acala_runtime.wasm ├── karura-2240.wasm └── karura_runtime.wasm └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | indent_style=tab 4 | indent_size=tab 5 | tab_width=4 6 | end_of_line=lf 7 | charset=utf-8 8 | trim_trailing_whitespace=true 9 | max_line_length=120 10 | insert_final_newline=true 11 | 12 | [*.{yml,yaml}] 13 | indent_style=space 14 | indent_size=2 15 | tab_width=8 16 | end_of_line=lf 17 | 18 | [*.{js,ts}] 19 | indent_style=space 20 | tab_width=2 21 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .eslintrc.js 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | parserOptions: { project: 'tsconfig.json' }, 5 | plugins: ['@typescript-eslint', 'import', 'sort-imports-es6-autofix'], 6 | extends: [ 7 | 'eslint:recommended', 8 | 'plugin:@typescript-eslint/recommended', 9 | 'prettier', 10 | 'plugin:import/recommended', 11 | 'plugin:import/typescript', 12 | ], 13 | rules: { 14 | '@typescript-eslint/no-empty-function': 'off', 15 | '@typescript-eslint/explicit-module-boundary-types': 'off', 16 | 'sort-imports-es6-autofix/sort-imports-es6': 'error', 17 | '@typescript-eslint/no-explicit-any': 'off', 18 | '@typescript-eslint/ban-ts-comment': 'off', 19 | '@typescript-eslint/no-unused-vars': [ 20 | 'warn', 21 | { 22 | argsIgnorePattern: '^_', 23 | varsIgnorePattern: '^_', 24 | caughtErrorsIgnorePattern: '^_', 25 | }, 26 | ], 27 | }, 28 | settings: { 29 | 'import/resolver': { 30 | typescript: { 31 | project: 'tsconfig.json', 32 | }, 33 | }, 34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: periodic check 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 0,12 * * *' 7 | 8 | env: 9 | DB_PATH: ./db.sqlite 10 | 11 | jobs: 12 | tests: 13 | timeout-minutes: 30 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | tests: [xcm-transfer, acala, bridge-sdk] 18 | runs-on: [self-hosted, linux] 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | submodules: recursive 23 | - name: setup node 24 | uses: actions/setup-node@v4 25 | with: 26 | node-version: 18.x 27 | - name: Setup yarn 28 | run: npm install -g yarn 29 | - name: setup node env 30 | uses: actions/setup-node@v4 31 | with: 32 | node-version: 18.x 33 | cache: 'yarn' 34 | - run: yarn --immutable 35 | - run: yarn update-env 36 | timeout-minutes: 5 37 | - run: yarn test tests/${{ matrix.tests }} 38 | - uses: ravsamhq/notify-slack-action@v2 39 | if: ${{ failure() }} 40 | with: 41 | status: ${{ job.status }} 42 | env: 43 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 44 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | DB_PATH: ./db.sqlite 11 | 12 | jobs: 13 | lint: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | submodules: recursive 19 | - name: Use Node.js 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: 18.x 23 | cache: 'yarn' 24 | - run: yarn --immutable 25 | - run: yarn lint 26 | tests: 27 | timeout-minutes: 30 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | tests: [xcm-transfer, acala, bridge-sdk] 32 | runs-on: [self-hosted, linux] 33 | steps: 34 | - uses: actions/checkout@v4 35 | with: 36 | submodules: recursive 37 | - name: setup node 38 | uses: actions/setup-node@v4 39 | with: 40 | node-version: 18.x 41 | - name: Setup yarn 42 | run: npm install -g yarn 43 | - name: setup node env 44 | uses: actions/setup-node@v4 45 | with: 46 | node-version: 18.x 47 | cache: 'yarn' 48 | - run: yarn --immutable 49 | - run: yarn update-env 50 | - run: yarn test tests/${{ matrix.tests }} 51 | -------------------------------------------------------------------------------- /.github/workflows/update.yml: -------------------------------------------------------------------------------- 1 | name: Update Snapshots 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | permissions: 7 | contents: write # required for push commit 8 | pull-requests: write # required for create pr 9 | 10 | env: 11 | DB_PATH: ./db.sqlite 12 | GH_TOKEN: ${{ github.token }} 13 | 14 | jobs: 15 | update: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | submodules: recursive 21 | - name: setup node 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: 18.x 25 | - name: Setup yarn 26 | run: npm install -g yarn 27 | - name: setup node env 28 | uses: actions/setup-node@v4 29 | with: 30 | node-version: 18.x 31 | cache: 'yarn' 32 | - run: yarn --immutable 33 | - run: yarn update-env 34 | - run: yarn test -u 35 | - name: Commit and Create PR 36 | uses: actions/github-script@v6 37 | with: 38 | script: | 39 | const branchName = `update-snapshots-${context.sha.slice(0, 7)}` 40 | await exec.exec(`git config user.email "hello@acala.network"`) 41 | await exec.exec(`git config user.name "Acala Github Action Bot"`) 42 | await exec.exec(`git checkout -b ${branchName}`) 43 | await exec.exec(`git`, ['commit', '-am', 'update snapshots']) 44 | await exec.exec(`git push origin HEAD:${branchName}`) 45 | await github.rest.pulls.create({ 46 | owner: context.repo.owner, 47 | repo: context.repo.repo, 48 | title: 'Update snapshots', 49 | head: branchName, 50 | base: 'master', 51 | body: 'Update snapshots', 52 | }) 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # IDE 10 | .idea 11 | 12 | # Diagnostic reports (https://nodejs.org/api/report.html) 13 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 14 | 15 | # Runtime data 16 | pids 17 | *.pid 18 | *.seed 19 | *.pid.lock 20 | 21 | # Directory for instrumented libs generated by jscoverage/JSCover 22 | lib-cov 23 | 24 | # Coverage directory used by tools like istanbul 25 | coverage 26 | *.lcov 27 | 28 | # nyc test coverage 29 | .nyc_output 30 | 31 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 32 | .grunt 33 | 34 | # Bower dependency directory (https://bower.io/) 35 | bower_components 36 | 37 | # node-waf configuration 38 | .lock-wscript 39 | 40 | # Compiled binary addons (https://nodejs.org/api/addons.html) 41 | build/Release 42 | 43 | # Dependency directories 44 | node_modules/ 45 | jspm_packages/ 46 | 47 | # TypeScript v1 declaration files 48 | typings/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Microbundle cache 60 | .rpt2_cache/ 61 | .rts2_cache_cjs/ 62 | .rts2_cache_es/ 63 | .rts2_cache_umd/ 64 | 65 | # Optional REPL history 66 | .node_repl_history 67 | 68 | # Output of 'npm pack' 69 | *.tgz 70 | 71 | # Yarn Integrity file 72 | .yarn-integrity 73 | 74 | # dotenv environment variables file 75 | .env 76 | .env.test 77 | 78 | # parcel-bundler cache (https://parceljs.org/) 79 | .cache 80 | 81 | # Next.js build output 82 | .next 83 | 84 | # Nuxt.js build / generate output 85 | .nuxt 86 | dist 87 | 88 | # Gatsby files 89 | .cache/ 90 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 91 | # https://nextjs.org/blog/next-9-1#public-directory-support 92 | # public 93 | 94 | # vuepress build output 95 | .vuepress/dist 96 | 97 | # Serverless directories 98 | .serverless/ 99 | 100 | # FuseBox cache 101 | .fusebox/ 102 | 103 | # DynamoDB Local files 104 | .dynamodb/ 105 | 106 | # TernJS port file 107 | .tern-port 108 | 109 | .yarn/* 110 | !.yarn/releases 111 | !.yarn/patches 112 | !.yarn/plugins 113 | !.yarn/sdks 114 | 115 | *.sqlite 116 | *.sqlite-shm 117 | *.sqlite-wal 118 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn lint-staged 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .yarn 2 | *.yml 3 | *.md 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib" 3 | } 4 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | yarnPath: .yarn/releases/yarn-4.1.1.cjs 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # e2e-tests 2 | 3 | End to end tests for Acala and Karura. 4 | 5 | Tests are powered by [Chopsticks](http://github.com/AcalaNetwork/chopsticks) to always run with latest mainnet block. 6 | 7 | ## Running tests 8 | 9 | All tests: 10 | `yarn test` 11 | 12 | Run one test only: 13 | `yarn test ./tests/xcm-transfer/kusama-relay.test.ts` 14 | 15 | Or you can just use a keywork since it is using vitest and use regex to find tests: 16 | `yarn test xcm` 17 | 18 | ## Check compatibility with upcoming runtime 19 | 20 | If you don't expect breaking change, simply add `{NETWORK}_WASM=wasm/runtime/path` to `.env` file to override the runtime and run the tests. 21 | 22 | If there are expected breaking change, you can add a new network with the new runtime and add new tests using the new network. Check other tests as a reference. 23 | 24 | ## Contributing 25 | 26 | This repo is using [vitest](https://vitest.dev) as the test runner. Most of the tests are written as [snapshot tests](https://vitest.dev/guide/snapshot.html#snapshot). The test will run and save the result as snapshot in a `.snap` file, and next time when the test runs again, it will compare the result with the snapshot. This eliminates the need to write assertions and make the test more readable. 27 | 28 | There is [periodic check](https://github.com/AcalaNetwork/e2e-tests/actions/workflows/check.yml) Github Action to run the tests against latest mainnet block to detect compatibility issues with live networks. 29 | 30 | It is recommended use `yarn update-env` to update the `.env` file with latest block number before running the tests. This ensures tests are always running against the same blocks so that block data can be cached and reused to speed up test running time. Once you have a working test, update the blocks number again and rerun the tests to ensure the tests are block number indpendent. Use `redact` and event filters to make the snapshot be consistent regardless the block number. 31 | 32 | ### Files 33 | 34 | - [networks](./networks) - network configs 35 | - [tests](./tests) - tests 36 | - [wasm](./wasm) - wasm runtime files to test compatibility with upcoming versions 37 | 38 | ### Debugging Tips 39 | 40 | - Move the failed test to [playground.test.ts](./tests/xcm-transfer/playground.test.ts) to only run the failed test. 41 | - Add `--update-snapshots` to automatically update snapshots and use git diff tool to compare the changes. 42 | - For failed CI tests, check the block numbers from the `update-env` steps in the logs to local `.env` file to be able to run the tests with the same block height. 43 | - Remove the system events filter to see all the events in snapshots. 44 | - e.g. Replace `checkSystemEvents(toChain, 'parachainSystem', 'dmpQueue')` to `checkSystemEvents(toChain)` 45 | - Insert `await chain.pause()` to pause the test and inspect the Chopsticks instance in the console. The connection details will be displayed in the console log. 46 | - Edit the timeout in `vitest.config.ts` to avoid timeout error. 47 | - Try log the extrinsic hex and replay it in the Chopsticks instance to debug the issue. 48 | - Try replicate the issue in Chopsticks directly to create a minimal reproducible case. 49 | - Once you are able to reproduce the issue in Chopsticks, you may add bunch logs in the runtime and make a wasm and override it. Then use `--runtime-log-level 5` to display logs. 50 | 51 | ### Writing tests 52 | 53 | #### Add new network 54 | 55 | - Create new network config in [networks](./networks) folder. 56 | - Update [networks/all.ts](./networks/all.ts) to include the new network. 57 | - Add Subway config in [scripts/configs](./scripts/configs) folder. 58 | - Update [run-all.sh](./scripts/run-all.sh) to include the new network. 59 | 60 | #### Add new xcm test 61 | 62 | - Checkout other tests as a reference and see if you can find something similar as a base case. 63 | - Starts writing in [playground.test.ts](./tests/xcm-transfer/playground.test.ts) and move to the appropriate test file once it is ready. 64 | - Add `-u` to automatically update snapshots and manually inspect the generated snapshot file to ensure it is expected. 65 | 66 | ### Environment variables 67 | 68 | - `{NETWORK_NAME}_BLOCK_NUMBER` - block number to run tests against 69 | - `{NETWORK_NAME}_ENDPOINT` - endpoint to connect to 70 | - `{NETWORK_NAME}_WASM` - override wasm runtime 71 | - `DB_URL` - path to db file for caching 72 | 73 | Example `.env` file 74 | 75 | ``` 76 | POLKADOT_BLOCK_NUMBER=15943997 77 | KUSAMA_BLOCK_NUMBER=18333291 78 | POLKADOT9420_BLOCK_NUMBER=15943997 79 | KUSAMA9420_BLOCK_NUMBER=18333291 80 | STATEMINT_BLOCK_NUMBER=3956812 81 | STATEMINE_BLOCK_NUMBER=4689863 82 | ACALA_BLOCK_NUMBER=3785107 83 | KARURA_BLOCK_NUMBER=4535779 84 | ASTAR_BLOCK_NUMBER=3776318 85 | SHIDEN_BLOCK_NUMBER=4203165 86 | ACALA2180_BLOCK_NUMBER=3785107 87 | KARURA2180_BLOCK_NUMBER=4535779 88 | MOONBEAM_BLOCK_NUMBER=3769096 89 | MOONRIVER_BLOCK_NUMBER=4446853 90 | HYDRADX_BLOCK_NUMBER=2750787 91 | BASILISK_BLOCK_NUMBER=3559987 92 | BIFROSTPOLKADOT_BLOCK_NUMBER=2522864 93 | BIFROST_BLOCK_NUMBER=4361576 94 | ALTAIR_BLOCK_NUMBER=3282796 95 | CENTRIFUGE_BLOCK_NUMBER=3161458 96 | PARALLEL_BLOCK_NUMBER=3706152 97 | HEIKO_BLOCK_NUMBER=3710234 98 | 99 | 100 | ACALA_ENDPOINT=ws://0.0.0.0:9000 101 | ACALA2180_ENDPOINT=ws://0.0.0.0:9000 102 | KARURA_ENDPOINT=ws://0.0.0.0:9001 103 | KARURA2180_ENDPOINT=ws://0.0.0.0:9001 104 | KUSAMA_ENDPOINT=ws://0.0.0.0:9002 105 | KUSAMA9420_ENDPOINT=ws://0.0.0.0:9002 106 | POLKADOT_ENDPOINT=ws://0.0.0.0:9003 107 | POLKADOT9420_ENDPOINT=ws://0.0.0.0:9003 108 | STATEMINE_ENDPOINT=ws://0.0.0.0:9004 109 | STATEMINT_ENDPOINT=ws://0.0.0.0:9005 110 | BASILISK_ENDPOINT=ws://0.0.0.0:9006 111 | HYDRADX_ENDPOINT=ws://0.0.0.0:9007 112 | MOONBREAM_ENDPOINT=ws://0.0.0.0:9008 113 | MOONRIVER_ENDPOINT=ws://0.0.0.0:9009 114 | ASTAR_BLOCK_ENDPOINT=ws://0.0.0.0:9010 115 | SHIDEN_BLOCK_ENDPOINT=ws://0.0.0.0:9011 116 | BIFROST_BLOCK_ENDPOINT=ws://0.0.0.0:9012 117 | ALTAIR_BLOCK_ENDPOINT=ws://0.0.0.0:9013 118 | HEIKO_BLOCK_ENDPOINT=ws://0.0.0.0:9014 119 | BIFROSTPOLKADOT_BLOCK_ENDPOINT=ws://0.0.0.0:9015 120 | PARALLEL_BLOCK_ENDPOINT=ws://0.0.0.0:9016 121 | CENTRIFUGE_BLOCK_ENDPOINT=ws://0.0.0.0:9017 122 | 123 | DB_PATH=./db.sqlite 124 | ``` 125 | 126 | Use specific block number for tests and db cache can signficantly improve test running speed. 127 | 128 | Run `yarn update-env` to update .env file with latest block number. 129 | 130 | To debug failing tests on CI, find the block number config from CI log and put them in .env to run the test with the same block height. 131 | 132 | ### Use Subway to catch RPC responses 133 | 134 | Use [subway](http://github.com/AcalaNetwork/subway) to run local endpoints to catch RPC responses for additonal improved test running speed. 135 | 136 | - Install Subway: `cargo install --git https://github.com/AcalaNetwork/subway.git` 137 | - Run: `./scripts/run-all.sh` 138 | 139 | ## To do 140 | 1. Enhance XCM tests by using Bridge SDK in additonal to Polkadot.js 141 | -------------------------------------------------------------------------------- /helpers/api/index.ts: -------------------------------------------------------------------------------- 1 | import { ApiPromise } from '@polkadot/api' 2 | 3 | export const xtokens = { 4 | relaychainV2: (acc: any) => ({ 5 | V1: { 6 | parents: 1, 7 | interior: { 8 | X1: { 9 | AccountId32: { 10 | network: 'Any', 11 | id: acc, 12 | }, 13 | }, 14 | }, 15 | }, 16 | }), 17 | relaychainV3: (acc: any) => ({ 18 | V3: { 19 | parents: 1, 20 | interior: { 21 | X1: { 22 | AccountId32: { 23 | id: acc, 24 | }, 25 | }, 26 | }, 27 | }, 28 | }), 29 | parachainV2: (paraId: number) => (acc: any) => ({ 30 | V1: { 31 | parents: 1, 32 | interior: { 33 | X2: [ 34 | { Parachain: paraId }, 35 | { 36 | AccountId32: { 37 | network: 'Any', 38 | id: acc, 39 | }, 40 | }, 41 | ], 42 | }, 43 | }, 44 | }), 45 | parachainAccountId20V3: (paraId: number) => (acc: any) => ({ 46 | V3: { 47 | parents: 1, 48 | interior: { 49 | X2: [ 50 | { Parachain: paraId }, 51 | { 52 | AccountKey20: { 53 | key: acc, 54 | }, 55 | }, 56 | ], 57 | }, 58 | }, 59 | }), 60 | parachainV3: (paraId: number) => (acc: any) => ({ 61 | V3: { 62 | parents: 1, 63 | interior: { 64 | X2: [ 65 | { Parachain: paraId }, 66 | { 67 | AccountId32: { 68 | id: acc, 69 | }, 70 | }, 71 | ], 72 | }, 73 | }, 74 | }), 75 | transfer: 76 | (token: any, amount: any, dest: (dest: any) => any, weight: any = 'Unlimited') => 77 | ({ api }: { api: ApiPromise }, acc: any) => 78 | api.tx.xTokens.transfer(token, amount, dest(acc), weight), 79 | transferMulticurrencies: 80 | (token: any, amount: any, feeToken: any, feeAmount: any, dest: (dest: any) => any) => 81 | ({ api }: { api: ApiPromise }, acc: any) => 82 | api.tx.xTokens.transferMulticurrencies( 83 | [ 84 | [token, amount], 85 | [feeToken, feeAmount], 86 | ], 87 | 1, 88 | dest(acc), 89 | 'Unlimited', 90 | ), 91 | } 92 | 93 | export const xcmPallet = { 94 | parachainV2: (parents: number, paraId: number) => ({ 95 | V1: { 96 | parents, 97 | interior: { 98 | X1: { Parachain: paraId }, 99 | }, 100 | }, 101 | }), 102 | relaychainV3: (acc: any) => ({ 103 | V3: { 104 | parents: 1, 105 | interior: { 106 | X1: { 107 | AccountId32: { 108 | network: 'Any', 109 | id: acc, 110 | }, 111 | }, 112 | }, 113 | }, 114 | }), 115 | parachainV3: (parents: number, paraId: any) => ({ 116 | V3: { 117 | parents, 118 | interior: { 119 | X1: { Parachain: paraId }, 120 | }, 121 | }, 122 | }), 123 | parachainV4: (parents: number, paraId: any) => ({ 124 | V4: { 125 | parents, 126 | interior: { 127 | X1: [{ Parachain: paraId }], 128 | }, 129 | }, 130 | }), 131 | 132 | limitedTeleportAssets: 133 | (token: any, amount: any, dest: any) => 134 | ({ api }: { api: ApiPromise }, acc: any) => 135 | (api.tx.xcmPallet || api.tx.polkadotXcm).limitedTeleportAssets( 136 | dest, 137 | { 138 | V3: { 139 | parents: 0, 140 | interior: { 141 | X1: { 142 | AccountId32: { 143 | // network: 'Any', 144 | id: acc, 145 | }, 146 | }, 147 | }, 148 | }, 149 | }, 150 | { 151 | V3: [ 152 | { 153 | id: token, 154 | fun: { Fungible: amount }, 155 | }, 156 | ], 157 | }, 158 | 0, 159 | 'Unlimited', 160 | ), 161 | limitedReserveTransferAssetsV2: 162 | (token: any, amount: any, dest: any) => 163 | ({ api }: { api: ApiPromise }, acc: any) => 164 | (api.tx.xcmPallet || api.tx.polkadotXcm).limitedReserveTransferAssets( 165 | dest, 166 | { 167 | V1: { 168 | parents: 0, 169 | interior: { 170 | X1: { 171 | AccountId32: { 172 | network: 'Any', 173 | id: acc, 174 | }, 175 | }, 176 | }, 177 | }, 178 | }, 179 | { 180 | V1: [ 181 | { 182 | id: token, 183 | fun: { Fungible: amount }, 184 | }, 185 | ], 186 | }, 187 | 0, 188 | 'Unlimited', 189 | ), 190 | limitedReserveTransferAssetsV3: 191 | (token: any, amount: any, dest: any) => 192 | ({ api }: { api: ApiPromise }, acc: any) => 193 | (api.tx.xcmPallet || api.tx.polkadotXcm).limitedReserveTransferAssets( 194 | dest, 195 | { 196 | V3: { 197 | parents: 0, 198 | interior: { 199 | X1: { 200 | AccountId32: { 201 | id: acc, 202 | }, 203 | }, 204 | }, 205 | }, 206 | }, 207 | { 208 | V3: [ 209 | { 210 | id: token, 211 | fun: { Fungible: amount }, 212 | }, 213 | ], 214 | }, 215 | 0, 216 | 'Unlimited', 217 | ), 218 | transferAssetsV4: 219 | (token: any, amount: any, dest: any) => 220 | ({ api }: { api: ApiPromise }, acc: any) => 221 | (api.tx.xcmPallet || api.tx.polkadotXcm).transferAssets( 222 | dest, 223 | { 224 | V4: { 225 | parents: 0, 226 | interior: { 227 | X1: [ 228 | { 229 | AccountId32: { 230 | id: acc, 231 | }, 232 | network: undefined, 233 | }, 234 | ], 235 | }, 236 | }, 237 | }, 238 | { 239 | V4: [ 240 | { 241 | id: token, 242 | fun: { Fungible: amount }, 243 | }, 244 | ], 245 | }, 246 | 0, 247 | 'Unlimited', 248 | ), 249 | } 250 | 251 | export const tx = { 252 | xtokens, 253 | xcmPallet, 254 | } 255 | 256 | export const query = { 257 | balances: ({ api }: { api: ApiPromise }, address: string) => api.query.system.account(address), 258 | tokens: 259 | (token: any) => 260 | ({ api }: { api: ApiPromise }, address: string) => 261 | api.query.tokens.accounts(address, token), 262 | assets: 263 | (token: number | bigint) => 264 | ({ api }: { api: ApiPromise }, address: string) => 265 | api.query.assets.account(token, address), 266 | evm: 267 | (contract: string, slot: string) => 268 | ({ api }: { api: ApiPromise }, _address: string) => 269 | api.query.evm.accountStorages(contract, slot), 270 | } 271 | -------------------------------------------------------------------------------- /helpers/api/query.ts: -------------------------------------------------------------------------------- 1 | import { ApiPromise } from '@polkadot/api' 2 | 3 | export const queryBalance = (api: ApiPromise, address: string) => { 4 | return api.query.system.account(address) 5 | } 6 | 7 | export const queryTokenBalance = (api: ApiPromise, token: object, address: string) => { 8 | return api.query.tokens.accounts(address, token) 9 | } 10 | 11 | export const queryRedeemRequests = (api: ApiPromise, address: string) => { 12 | return api.query.homa.redeemRequests(address) 13 | } 14 | 15 | export const queryPositions = (api: ApiPromise, token: string, address: string) => { 16 | return api.query.loans.positions({ Token: token }, address) 17 | } 18 | 19 | export const querySharesAndWithdrawnRewards = (api: ApiPromise, poolsId: object, address: string) => { 20 | return api.query.rewards.sharesAndWithdrawnRewards(poolsId, address) 21 | } 22 | -------------------------------------------------------------------------------- /helpers/index.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'vitest' 2 | 3 | import { withExpect } from '@acala-network/chopsticks-testing' 4 | 5 | const { check, checkEvents, checkHrmp, checkSystemEvents, checkUmp } = withExpect((x: any) => ({ 6 | toMatchSnapshot(msg?: string): void { 7 | expect(x).toMatchSnapshot(msg) 8 | }, 9 | toMatch(value: any, _msg?: string): void { 10 | expect(x).toMatch(value) 11 | }, 12 | toMatchObject(value: any, _msg?: string): void { 13 | expect(x).toMatchObject(value) 14 | }, 15 | })) 16 | 17 | export { check, checkEvents, checkHrmp, checkSystemEvents, checkUmp } 18 | 19 | export * from '@acala-network/chopsticks-testing' 20 | -------------------------------------------------------------------------------- /networks/acala-next.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | import acalaConfig, { Vars } from './acala' 4 | 5 | export default { 6 | ...acalaConfig, 7 | polkadot: { 8 | ...acalaConfig.polkadot, 9 | name: 'acalaNext' as const, 10 | }, 11 | kusama: { 12 | ...acalaConfig.kusama, 13 | name: 'karuraNext' as const, 14 | }, 15 | config: (opt) => ({ 16 | ...acalaConfig.config(opt), 17 | options: { 18 | wasmOverride: { 19 | polkadot: './wasm/acala_runtime.wasm', 20 | kusama: './wasm/karura_runtime.wasm', 21 | }[opt.network], 22 | }, 23 | }), 24 | } satisfies Config 25 | -------------------------------------------------------------------------------- /networks/acala.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | export type Vars = { 4 | relayToken: string 5 | relayLiquidToken: string 6 | stableToken: string 7 | } 8 | 9 | export default { 10 | polkadot: { 11 | name: 'acala' as const, 12 | endpoint: ['wss://acala-rpc.aca-api.network', 'wss://acala-rpc.dwellir.com'], 13 | relayToken: 'DOT', 14 | relayLiquidToken: 'LDOT', 15 | stableToken: 'AUSD', 16 | }, 17 | kusama: { 18 | name: 'karura' as const, 19 | endpoint: [ 20 | 'wss://karura-rpc.aca-api.network', 21 | 'wss://rpc-karura.luckyfriday.io', 22 | 'wss://karura.api.onfinality.io/public-ws', 23 | ], 24 | relayToken: 'KSM', 25 | relayLiquidToken: 'LKSM', 26 | stableToken: 'KUSD', 27 | }, 28 | config: ({ alice, relayToken, relayLiquidToken, stableToken }) => ({ 29 | storages: { 30 | System: { 31 | account: [[[alice.address], { providers: 4, data: { free: 10 * 1e12 } }]], 32 | }, 33 | Tokens: { 34 | accounts: [ 35 | [[alice.address, { Token: relayToken }], { free: 10 * 1e12 }], 36 | [[alice.address, { Token: relayLiquidToken }], { free: 100 * 1e12 }], 37 | [[alice.address, { Token: stableToken }], { free: 1000 * 1e12 }], 38 | ], 39 | }, 40 | Sudo: { 41 | key: alice.address, 42 | }, 43 | EvmAccounts: { 44 | accounts: [[['0x82a258cb20e2adb4788153cd5eb5839615ece9a0'], alice.address]], 45 | evmAddresses: [[[alice.address], '0x82a258cb20e2adb4788153cd5eb5839615ece9a0']], 46 | }, 47 | Homa: { 48 | // avoid impact test outcome 49 | $removePrefix: ['redeemRequests', 'unbondings', 'toBondPool'], 50 | // so that bump era won't trigger unbond 51 | relayChainCurrentEra: 100, 52 | }, 53 | PolkadotXcm: { 54 | // avoid sending xcm version change notifications to makes things faster 55 | $removePrefix: ['versionNotifyTargets', 'versionNotifiers'], 56 | }, 57 | }, 58 | }), 59 | } satisfies Config 60 | 61 | export const acala = { 62 | paraId: 2000, 63 | paraAccount: '13YMK2eYoAvStnzReuxBjMrAvPXmmdsURwZvc62PrdXimbNy', 64 | dot: { Token: 'DOT' }, 65 | ldot: { Token: 'LDOT' }, 66 | dai: { Erc20: '0x54a37a01cd75b616d63e0ab665bffdb0143c52ae' }, 67 | wbtc: { ForeignAsset: 5 }, 68 | ausd: { Token: 'AUSD' }, 69 | aca: { Token: 'ACA' }, 70 | lcdot: { LiquidCrowdloan: 13 }, 71 | } as const 72 | 73 | export const karura = { 74 | paraId: 2000, 75 | paraAccount: '13YMK2eYoAvStnzReuxBjMrAvPXmmdsURwZvc62PrdXimbNy', 76 | ksm: { Token: 'KSM' }, 77 | lksm: { Token: 'LKSM' }, 78 | usdt: { ForeignAsset: 7 }, 79 | rmrk: { ForeignAsset: 0 }, 80 | dai: { Erc20: '0x4bb6afb5fa2b07a5d1c499e1c3ddb5a15e709a71' }, 81 | ausd: { Token: 'KUSD' }, 82 | kar: { Token: 'KAR' }, 83 | } as const 84 | -------------------------------------------------------------------------------- /networks/all.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | import acalaConfig from './acala' 4 | import acalaNextConfig from './acala-next' 5 | import assethubConfig from './assethub' 6 | import astarConfig from './astar' 7 | import bifrostConfig from './bifrost' 8 | // import centrifugeConfig from './centrifuge' 9 | import crustConfig from './crust' 10 | import darwiniaConfig from './darwinia' 11 | import hydraDXConfig from './hydraDX' 12 | import interlayConfig from './interlay' 13 | import moonbeamConfig from './moonbeam' 14 | // import parallelConfig from './parallel' 15 | // import phalaConfig from './phala' 16 | import polkadotConfig from './polkadot' 17 | import uniqueConfig from './unique' 18 | 19 | const all = { 20 | polkadot: polkadotConfig, 21 | assethub: assethubConfig, 22 | acala: acalaConfig, 23 | astar: astarConfig, 24 | acalaNext: acalaNextConfig, 25 | moonbeam: moonbeamConfig, 26 | hydraDX: hydraDXConfig, 27 | bifrost: bifrostConfig, 28 | // centrifuge: centrifugeConfig, 29 | // parallel: parallelConfig, 30 | crust: crustConfig, 31 | unique: uniqueConfig, 32 | interlay: interlayConfig, 33 | // phala: phalaConfig, 34 | darwinia: darwiniaConfig, 35 | } satisfies Record 36 | 37 | export default all 38 | -------------------------------------------------------------------------------- /networks/assethub.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | export default { 4 | polkadot: { 5 | name: 'assetHubPolkadot' as const, 6 | endpoint: 'wss://statemint-rpc-tn.dwellir.com', 7 | }, 8 | kusama: { 9 | name: 'assetHubKusama' as const, 10 | endpoint: 'wss://statemine-rpc-tn.dwellir.com', 11 | }, 12 | config: ({ alice }) => ({ 13 | storages: { 14 | System: { 15 | account: [[[alice.address], { providers: 1, data: { free: 1000e10 } }]], 16 | }, 17 | Assets: { 18 | account: [ 19 | [[assetHubKusama.usdtIndex, alice.address], { balance: 1000e6 }], // USDT 20 | ], 21 | }, 22 | }, 23 | }), 24 | } satisfies Config 25 | 26 | export const assetHubPolkadot = { 27 | paraId: 1000, 28 | dot: { Concrete: { parents: 1, interior: 'Here' } }, 29 | wbtc: { Concrete: { parents: 0, interior: { X2: [{ PalletInstance: 50 }, { GeneralIndex: 21 }] } } }, 30 | wbtcIndex: 21, 31 | } as const 32 | 33 | export const assetHubKusama = { 34 | paraId: 1000, 35 | ksm: { Concrete: { parents: 1, interior: 'Here' } }, 36 | usdt: { Concrete: { parents: 0, interior: { X2: [{ PalletInstance: 50 }, { GeneralIndex: 1984 }] } } }, 37 | usdtIndex: 1984, 38 | } as const 39 | -------------------------------------------------------------------------------- /networks/astar.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | export type Vars = { 4 | relayToken: string 5 | aUSDToken: string 6 | } 7 | 8 | export default { 9 | polkadot: { 10 | name: 'astar' as const, 11 | endpoint: 'wss://rpc.astar.network', 12 | relayToken: '340282366920938463463374607431768211455', 13 | aUSDToken: '18446744073709551617', 14 | }, 15 | kusama: { 16 | name: 'shiden' as const, 17 | endpoint: ['wss://rpc.shiden.astar.network', 'wss://shiden-rpc.dwellir.com'], 18 | relayToken: '340282366920938463463374607431768211455', 19 | aUSDToken: '18446744073709551616', 20 | }, 21 | config: ({ alice, relayToken, aUSDToken }) => ({ 22 | storages: { 23 | System: { 24 | account: [[[alice.address], { providers: 1, data: { free: '100000000000000000000' } }]], 25 | }, 26 | Assets: { 27 | account: [ 28 | [[relayToken, alice.address], { balance: 10 * 1e12 }], 29 | [[aUSDToken, alice.address], { balance: 10 * 1e12 }], 30 | ], 31 | }, 32 | Sudo: { 33 | key: alice.address, 34 | }, 35 | PolkadotXcm: { 36 | // avoid sending xcm version change notifications to makes things faster 37 | $removePrefix: ['versionNotifyTargets', 'versionNotifiers', 'supportedVersion'], 38 | }, 39 | }, 40 | }), 41 | } satisfies Config 42 | 43 | export const astar = { 44 | paraId: 2006, 45 | paraAccount: '13YMK2eZzuFY1WZGagpYtTgbWBWGdoUD2CtrPj1mQPjY8Ldc', 46 | dot: 340282366920938463463374607431768211455n, 47 | astr: { Concrete: { parents: 0, interior: 'Here' } }, 48 | aca: 18446744073709551616n, 49 | usdt: 4294969280n, 50 | } as const 51 | 52 | export const shiden = { 53 | paraId: 2007, 54 | paraAccount: 'F7fq1jNy74AqkJ1DP4KqSrWtnTGtXfNVoDwFhTvvPxUvJaq', 55 | ksm: 340282366920938463463374607431768211455n, 56 | sdn: { Concrete: { parents: 0, interior: 'Here' } }, 57 | kar: 18446744073709551618n, 58 | usdt: 4294969280n, 59 | } as const 60 | -------------------------------------------------------------------------------- /networks/bifrost.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | export default { 4 | polkadot: { 5 | name: 'bifrostPolkadot' as const, 6 | endpoint: 'wss://hk.p.bifrost-rpc.liebi.com/ws', 7 | }, 8 | kusama: { 9 | name: 'bifrost' as const, 10 | endpoint: 'wss://bifrost-rpc.liebi.com/ws', 11 | }, 12 | config: ({ alice }) => ({ 13 | storages: { 14 | System: { 15 | Account: [[[alice.address], { providers: 1, data: { free: 1000e12 } }]], 16 | }, 17 | }, 18 | }), 19 | } satisfies Config 20 | 21 | export const basilisk = { 22 | paraId: 2001, 23 | } 24 | export const bifrostPolkadot = { 25 | paraId: 2030, 26 | } 27 | -------------------------------------------------------------------------------- /networks/centrifuge.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | export default { 4 | polkadot: { 5 | name: 'centrifuge' as const, 6 | endpoint: 'wss://fullnode.centrifuge.io', 7 | }, 8 | kusama: { 9 | name: 'altair' as const, 10 | endpoint: 'wss://fullnode.altair.centrifuge.io', 11 | }, 12 | config: ({ alice }) => ({ 13 | storages: { 14 | System: { 15 | Account: [[[alice.address], { providers: 1, data: { free: '1000000000000000000000' } }]], 16 | }, 17 | OrmlTokens: { 18 | accounts: [[[alice.address, 'AUSD'], { free: 10 * 1e12 }]], 19 | }, 20 | }, 21 | }), 22 | } satisfies Config 23 | 24 | export const altair = { 25 | paraId: 2088, 26 | } 27 | 28 | export const basilisk = { 29 | paraId: 2031, 30 | } 31 | -------------------------------------------------------------------------------- /networks/crust.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | export default { 4 | polkadot: { 5 | name: 'crustPolkadot' as const, 6 | endpoint: 'wss://crust-parachain.crustapps.net', 7 | }, 8 | kusama: { 9 | name: 'crust' as const, 10 | endpoint: 'wss://rpc-shadow.crust.network/', 11 | }, 12 | config: ({ alice }) => ({ 13 | storages: { 14 | System: { 15 | account: [[[alice.address], { providers: 1, data: { free: 1000 * 1e12 } }]], 16 | }, 17 | }, 18 | }), 19 | } satisfies Config 20 | 21 | export const crust = { 22 | paraId: 2012, 23 | } 24 | 25 | export const crustPolkadot = { 26 | paraId: 2008, 27 | } 28 | -------------------------------------------------------------------------------- /networks/darwinia.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | export default { 4 | polkadot: { 5 | name: 'darwinia' as const, 6 | endpoint: 'wss://darwinia-rpc.dwellir.com', 7 | }, 8 | kusama: { 9 | name: 'crab' as const, 10 | endpoint: 'wss://darwiniacrab-rpc.dwellir.com', 11 | }, 12 | config: ({ alice }) => ({ 13 | storages: { 14 | System: { 15 | Account: [[[alice.address], { providers: 1, data: { free: '1000000000000000000000' } }]], 16 | }, 17 | }, 18 | }), 19 | } satisfies Config 20 | 21 | export const darwinia = { 22 | paraId: 2046, 23 | } 24 | 25 | export const crab = { 26 | paraId: 2105, 27 | } 28 | -------------------------------------------------------------------------------- /networks/hydraDX.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | export type Vars = { 4 | relayToken: number 5 | dai: number 6 | } 7 | 8 | export default { 9 | polkadot: { 10 | name: 'hydraDX' as const, 11 | endpoint: 'wss://rpc.hydradx.cloud', 12 | relayToken: 5, 13 | dai: 2, 14 | }, 15 | kusama: { 16 | name: 'basilisk' as const, 17 | endpoint: 'wss://basilisk-rpc.dwellir.com', 18 | relayToken: 1, 19 | dai: 13, 20 | }, 21 | config: ({ alice, relayToken, dai }) => ({ 22 | storages: { 23 | System: { 24 | Account: [[[alice.address], { providers: 1, data: { free: 1000 * 1e12 } }]], 25 | }, 26 | Tokens: { 27 | Accounts: [ 28 | [[alice.address, relayToken], { free: 1000 * 1e12 }], 29 | [[alice.address, dai], { free: 100n * 10n ** 18n }], 30 | ], 31 | }, 32 | }, 33 | }), 34 | } satisfies Config 35 | 36 | export const hydraDX = { 37 | paraId: 2034, 38 | dai: 2, 39 | } 40 | 41 | export const basilisk = { 42 | paraId: 2090, 43 | dai: 13, 44 | } 45 | -------------------------------------------------------------------------------- /networks/index.ts: -------------------------------------------------------------------------------- 1 | import { SetupOption, setupContext } from '@acala-network/chopsticks-testing' 2 | import { connectParachains, connectVertical } from '@acala-network/chopsticks' 3 | import { config as dotenvConfig } from 'dotenv' 4 | 5 | import { testingPairs } from '../helpers' 6 | 7 | import { Config, Context, NetworkKind } from './types' 8 | import networkDefs from './all' 9 | 10 | dotenvConfig() 11 | 12 | const toNumber = (value: string | undefined): number | undefined => { 13 | if (value === undefined) { 14 | return undefined 15 | } 16 | 17 | return Number(value) 18 | } 19 | 20 | export type Network = Awaited> & { 21 | options: SetupOption 22 | config: (typeof networkDefs)[keyof typeof networkDefs][NetworkKind] 23 | } 24 | export type NetworkNames = (typeof networkDefs)[keyof typeof networkDefs][NetworkKind]['name'] 25 | 26 | export const networkCreator = {} as Record< 27 | NetworkNames, 28 | (options?: Partial) => (ctx: Context) => Promise 29 | > 30 | 31 | const relaychains = ['polkadot', 'kusama'] as const 32 | 33 | for (const def of Object.values(networkDefs)) { 34 | for (const relaychain of relaychains) { 35 | const config = def[relaychain] 36 | const { endpoint, name } = config 37 | const upperName = name.toUpperCase() 38 | networkCreator[name] = (options?: Partial) => async (ctx: Context) => { 39 | const setupConfig = (def as Config).config({ 40 | network: relaychain, 41 | ...config, 42 | ...ctx, 43 | }) 44 | 45 | const finalOptions: SetupOption = { 46 | timeout: 600000, 47 | wasmOverride: process.env[`${upperName}_WASM`], 48 | blockNumber: toNumber(process.env[`${upperName}_BLOCK_NUMBER`]), 49 | endpoint: process.env[`${upperName}_ENDPOINT`] ?? endpoint, 50 | db: process.env.DB_PATH, 51 | port: 0, 52 | allowUnresolvedImports: true, 53 | runtimeLogLevel: process.env.RUNTIME_LOG_LEVEL ? Number(process.env.RUNTIME_LOG_LEVEL) : 0, 54 | ...setupConfig.options, 55 | ...options, 56 | } 57 | 58 | const network = await setupContext(finalOptions) 59 | 60 | if (setupConfig.storages) { 61 | await network.dev.setStorage(setupConfig.storages) 62 | } 63 | 64 | return { 65 | ...network, 66 | config, 67 | options: finalOptions, 68 | } 69 | } 70 | } 71 | } 72 | 73 | export const createContext = (keyringType: 'ed25519' | 'sr25519' = 'ed25519') => testingPairs(keyringType) 74 | 75 | export const createNetworks = async ( 76 | networkOptions: Partial | undefined>>, 77 | context = createContext(), 78 | ) => { 79 | const ret = {} as Record 80 | 81 | let wasmOverriden = false 82 | 83 | for (const [name, options] of Object.entries(networkOptions) as [NetworkNames, Partial | undefined][]) { 84 | ret[name] = await networkCreator[name](options)(context) 85 | wasmOverriden ||= !!ret[name].options.wasmOverride 86 | } 87 | 88 | const relaychainName = Object.keys(ret).filter( 89 | (x) => x.startsWith('polkadot') || x.startsWith('kusama'), 90 | )[0] as NetworkKind 91 | const { [relaychainName]: relaychain, ...parachains } = ret 92 | 93 | if (relaychain) { 94 | for (const parachain of Object.values(parachains)) { 95 | await connectVertical(relaychain.chain, parachain.chain) 96 | } 97 | } 98 | 99 | const parachainList = Object.values(parachains).map((i) => i.chain) 100 | if (parachainList.length > 0) { 101 | await connectParachains(parachainList) 102 | } 103 | 104 | if (wasmOverriden) { 105 | // trigger runtime upgrade if needed (due to wasm override) 106 | for (const chain of Object.values(ret)) { 107 | await chain.dev.newBlock() 108 | } 109 | // handle xcm version message if needed (due to wasm override triggered xcm version upgrade) 110 | for (const chain of Object.values(ret)) { 111 | await chain.dev.newBlock() 112 | } 113 | } 114 | 115 | return ret 116 | } 117 | -------------------------------------------------------------------------------- /networks/interlay.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | export type Vars = { 3 | btc: string 4 | native: string 5 | LiquidToken: number 6 | } 7 | 8 | export default { 9 | polkadot: { 10 | name: 'interlay' as const, 11 | endpoint: 'wss://api.interlay.io/parachain', 12 | btc: 'IBTC', 13 | native: 'INTR', 14 | LiquidToken: 1, 15 | }, 16 | kusama: { 17 | name: 'kintsugi' as const, 18 | endpoint: 'wss://api-kusama.interlay.io/parachain', 19 | btc: 'KBTC', 20 | native: 'KINT', 21 | LiquidToken: 2, 22 | }, 23 | config: ({ alice, btc, native, LiquidToken }) => ({ 24 | storages: { 25 | System: { 26 | Account: [[[alice.address], { providers: 1, data: { free: 1000 * 1e12 } }]], 27 | }, 28 | Tokens: { 29 | Accounts: [ 30 | [[alice.address, { ForeignAsset: LiquidToken }], { free: 100 * 1e12 }], 31 | [[alice.address, { Token: native }], { free: 1000 * 1e12 }], 32 | [[alice.address, { Token: btc }], { free: 3 * 1e8 }], 33 | ], 34 | }, 35 | }, 36 | }), 37 | } satisfies Config 38 | 39 | export const interlay = { 40 | paraId: 2032, 41 | } 42 | 43 | export const kintsugi = { 44 | paraId: 2092, 45 | } 46 | -------------------------------------------------------------------------------- /networks/moonbeam.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | export default { 4 | polkadot: { 5 | name: 'moonbeam' as const, 6 | endpoint: 'wss://wss.api.moonbeam.network', 7 | }, 8 | kusama: { 9 | name: 'moonriver' as const, 10 | endpoint: 'wss://wss.api.moonriver.moonbeam.network', 11 | }, 12 | config: ({ alith }) => ({ 13 | storages: { 14 | System: { 15 | Account: [[[alith.address], { providers: 1, data: { free: 1000n * 10n ** 18n } }]], 16 | }, 17 | AuthorFilter: { 18 | EligibleRatio: 100, 19 | EligibleCount: 100, 20 | }, 21 | }, 22 | }), 23 | } satisfies Config 24 | 25 | export const moonbeam = { 26 | paraId: 2004, 27 | dot: 42259045809535163221576417993425387648n, 28 | parachainDot: { parents: 1, interior: 'Here' }, 29 | } as const 30 | 31 | export const moonriver = { 32 | paraId: 2023, 33 | } as const 34 | -------------------------------------------------------------------------------- /networks/parallel.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | export type Vars = { 4 | ausd: number 5 | acalaNativeToken: number 6 | } 7 | 8 | export default { 9 | polkadot: { 10 | name: 'parallel' as const, 11 | endpoint: 'wss://parallel-rpc.dwellir.com', 12 | ausd: 104, 13 | acalaNativeToken: 108, 14 | }, 15 | kusama: { 16 | name: 'heiko' as const, 17 | endpoint: 'wss://heiko-rpc.parallel.fi', 18 | ausd: 103, 19 | acalaNativeToken: 107, 20 | }, 21 | config: ({ alice, ausd, acalaNativeToken }) => ({ 22 | storages: { 23 | System: { 24 | account: [[[alice.address], { providers: 1, data: { free: 1000 * 1e12 } }]], 25 | }, 26 | Assets: { 27 | account: [ 28 | [[acalaNativeToken, alice.address], { balance: 100 * 1e12 }], 29 | [[ausd, alice.address], { balance: 100 * 1e12 }], 30 | ], 31 | }, 32 | }, 33 | }), 34 | } satisfies Config 35 | 36 | export const parallel = { 37 | paraId: 2012, 38 | } 39 | 40 | export const heiko = { 41 | paraId: 2085, 42 | } 43 | -------------------------------------------------------------------------------- /networks/phala.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | export type Vars = { 4 | aUSDToken: string 5 | } 6 | 7 | export default { 8 | polkadot: { 9 | name: 'phala' as const, 10 | endpoint: 'wss://phala-rpc.dwellir.com', 11 | aUSDToken: '3', 12 | }, 13 | kusama: { 14 | name: 'khala' as const, 15 | endpoint: 'wss://khala-rpc.dwellir.com', 16 | aUSDToken: '4', 17 | }, 18 | config: ({ alice, aUSDToken }) => ({ 19 | storages: { 20 | System: { 21 | Account: [[[alice.address], { providers: 1, data: { free: '1000000000000000' } }]], 22 | }, 23 | Assets: { 24 | account: [[[aUSDToken, alice.address], { balance: 100 * 1e12 }]], 25 | }, 26 | }, 27 | }), 28 | } satisfies Config 29 | 30 | export const phala = { 31 | paraId: 2035, 32 | } 33 | 34 | export const khala = { 35 | paraId: 2004, 36 | } 37 | -------------------------------------------------------------------------------- /networks/polkadot.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | export default { 4 | polkadot: { 5 | name: 'polkadot' as const, 6 | endpoint: ['wss://rpc.ibp.network/polkadot', 'wss://polkadot-rpc.dwellir.com', 'wss://rpc.polkadot.io'], 7 | }, 8 | kusama: { 9 | name: 'kusama' as const, 10 | endpoint: ['wss://kusama-rpc.dwellir.com', 'wss://rpc.ibp.network/kusama', 'wss://kusama-rpc.polkadot.io'], 11 | }, 12 | config: ({ alice }) => ({ 13 | storages: { 14 | System: { 15 | Account: [[[alice.address], { providers: 1, data: { free: 10 * 1e12 } }]], 16 | }, 17 | ParasDisputes: { 18 | // those can makes block building super slow 19 | $removePrefix: ['disputes'], 20 | }, 21 | Dmp: { 22 | // clear existing dmp to avoid impact test result 23 | $removePrefix: ['downwardMessageQueues'], 24 | }, 25 | }, 26 | }), 27 | } satisfies Config 28 | 29 | export const polkadot = { 30 | dot: { Concrete: { parents: 0, interior: 'Here' } }, 31 | } as const 32 | 33 | export const kusama = { 34 | ksm: { Concrete: { parents: 0, interior: 'Here' } }, 35 | } as const 36 | -------------------------------------------------------------------------------- /networks/types.ts: -------------------------------------------------------------------------------- 1 | import { SetupOption } from '@acala-network/chopsticks-testing' 2 | import { testingPairs } from '../helpers' 3 | 4 | export type NetworkKind = 'polkadot' | 'kusama' 5 | 6 | export type NetworkConfig = { 7 | name: string 8 | endpoint: string | string[] 9 | } 10 | 11 | export type Context = ReturnType 12 | 13 | export type FullContext = Context & 14 | NetworkConfig & { 15 | network: NetworkKind 16 | } 17 | 18 | export type Config = { 19 | polkadot?: NetworkConfig & T 20 | kusama?: NetworkConfig & T 21 | config(context: FullContext & T): { 22 | storages?: Record> 23 | options?: Partial 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /networks/unique.ts: -------------------------------------------------------------------------------- 1 | import { Config } from './types' 2 | 3 | export default { 4 | polkadot: { 5 | name: 'unique' as const, 6 | endpoint: 'wss://us-ws.unique.network', 7 | }, 8 | kusama: { 9 | name: 'quartz' as const, 10 | endpoint: 'wss://asia-ws-quartz.unique.network', 11 | }, 12 | config: ({ alice }) => ({ 13 | storages: { 14 | System: { 15 | account: [[[alice.address], { providers: 1, data: { free: 1000 * 1e12 } }]], 16 | }, 17 | }, 18 | }), 19 | } satisfies Config 20 | 21 | export const unique = { 22 | paraId: 2037, 23 | } 24 | 25 | export const quartz = { 26 | paraId: 2095, 27 | } 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e2e-tests", 3 | "private": true, 4 | "scripts": { 5 | "lint": "tsc --noEmit && eslint . --ext .js,.ts && prettier --check .", 6 | "fix": "eslint . --ext .js,.ts --fix && prettier -w .", 7 | "prepare": "husky install", 8 | "test": "LOG_LEVEL=error vitest", 9 | "test:ui": "LOG_LEVEL=error vitest --ui", 10 | "update-env": "tsx scripts/update-env.ts" 11 | }, 12 | "resolutions": { 13 | "@polkadot/api": "15.10.2", 14 | "@polkadot/api-derive": "15.10.2", 15 | "@polkadot/types": "15.10.2", 16 | "@acala-network/api": "^6.1.3", 17 | "@acala-network/sdk": "4.1.14", 18 | "@acala-network/sdk-core": "4.1.14" 19 | }, 20 | "dependencies": { 21 | "@acala-network/chopsticks": "^1.0.5-1", 22 | "@acala-network/chopsticks-testing": "^1.0.5-1", 23 | "@acala-network/sdk": "4.1.14", 24 | "@acala-network/sdk-core": "4.1.14", 25 | "@polkadot/api": "15.10.2", 26 | "@polkadot/util": "13.4.4", 27 | "@polkawallet/bridge": "^0.1.7-13", 28 | "@swc/core": "^1.6.1", 29 | "axios": "^1.7.2", 30 | "dotenv": "^16.4.5", 31 | "lodash": "^4.17.21", 32 | "typescript": "^5.4.5", 33 | "unplugin-swc": "^1.4.5", 34 | "vitest": "^1.6.0" 35 | }, 36 | "devDependencies": { 37 | "@types/lodash": "^4.17.5", 38 | "@types/node": "^20.14.4", 39 | "@typescript-eslint/eslint-plugin": "^6.21.0", 40 | "@typescript-eslint/parser": "^6.21.0", 41 | "@vitest/ui": "^1.6.0", 42 | "eslint": "^8.57.0", 43 | "eslint-config-prettier": "^9.1.0", 44 | "eslint-import-resolver-typescript": "^3.6.1", 45 | "eslint-plugin-import": "^2.29.1", 46 | "eslint-plugin-sort-imports-es6-autofix": "^0.6.0", 47 | "husky": "^9.0.11", 48 | "lint-staged": "^15.2.7", 49 | "prettier": "^3.3.2", 50 | "tsx": "^4.15.6" 51 | }, 52 | "prettier": { 53 | "tabWidth": 2, 54 | "semi": false, 55 | "singleQuote": true 56 | }, 57 | "lint-staged": { 58 | "*.ts": "eslint --cache --fix", 59 | "*.{ts,css}": "prettier --write" 60 | }, 61 | "packageManager": "yarn@4.1.1" 62 | } 63 | -------------------------------------------------------------------------------- /scripts/configs/acala.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://acala-rpc.aca-api.network 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/altair.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://fullnode.altair.centrifuge.io:443 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/astar.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://astar-rpc.dwellir.com:443 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/basilisk.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://basilisk-rpc.dwellir.com:443 5 | - wss://rpc.basilisk.cloud:443 6 | event_bus: 7 | substrate_api: 8 | stale_timeout_seconds: 60 9 | cache: 10 | default_ttl_seconds: 0 11 | default_size: 2000 12 | merge_subscription: 13 | keep_alive_seconds: 60 14 | server: 15 | port: ${PORT} 16 | listen_address: '0.0.0.0' 17 | max_connections: 2000 18 | 19 | middlewares: 20 | methods: 21 | - response 22 | - inject_params 23 | - cache 24 | - upstream 25 | subscriptions: 26 | - merge_subscription 27 | - upstream 28 | 29 | rpcs: substrate 30 | -------------------------------------------------------------------------------- /scripts/configs/bifrost.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://bifrost-rpc.liebi.com/ws 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/bifrostpolkadot.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://bifrost-polkadot.api.onfinality.io:443/public-ws 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/centrifuge.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://centrifuge-parachain.api.onfinality.io:443/public-ws 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/crab.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://crab-rpc.darwinia.network 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/crust.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://crust-parachain.crustapps.net 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/heiko.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://heiko-rpc.parallel.fi:443 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/hydraDX.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://hydradx-rpc.dwellir.com:443 5 | - wss://rpc.hydradx.cloud:443 6 | event_bus: 7 | substrate_api: 8 | stale_timeout_seconds: 60 9 | cache: 10 | default_ttl_seconds: 0 11 | default_size: 2000 12 | merge_subscription: 13 | keep_alive_seconds: 60 14 | server: 15 | port: ${PORT} 16 | listen_address: '0.0.0.0' 17 | max_connections: 2000 18 | 19 | middlewares: 20 | methods: 21 | - response 22 | - inject_params 23 | - cache 24 | - upstream 25 | subscriptions: 26 | - merge_subscription 27 | - upstream 28 | 29 | rpcs: substrate 30 | -------------------------------------------------------------------------------- /scripts/configs/interlay.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://interlay-rpc.dwellir.com:443 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/karura.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://karura-rpc.aca-api.network 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/khala.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://khala-rpc.dwellir.com:443 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/kintsugi.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://kintsugi-rpc.dwellir.com:443 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/kusama.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://kusama-rpc.polkadot.io 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/moonbeam.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://wss.api.moonbeam.network:443 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/moonriver.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://wss.api.moonriver.moonbeam.network:443 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/parallel.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://parallel-rpc.dwellir.com 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/phala.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://phala-rpc.dwellir.com:443 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/polkadot.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://rpc.polkadot.io:443 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/quartz.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://ws-quartz.unique.network:443 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/shiden.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://rpc.shiden.astar.network 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/statemine.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://statemine-rpc-tn.dwellir.com 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/statemint.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://statemint-rpc-tn.dwellir.com 5 | event_bus: 6 | substrate_api: 7 | stale_timeout_seconds: 60 8 | cache: 9 | default_ttl_seconds: 0 10 | default_size: 2000 11 | merge_subscription: 12 | keep_alive_seconds: 60 13 | server: 14 | port: ${PORT} 15 | listen_address: '0.0.0.0' 16 | max_connections: 2000 17 | 18 | middlewares: 19 | methods: 20 | - response 21 | - inject_params 22 | - cache 23 | - upstream 24 | subscriptions: 25 | - merge_subscription 26 | - upstream 27 | 28 | rpcs: substrate 29 | -------------------------------------------------------------------------------- /scripts/configs/unique.yml: -------------------------------------------------------------------------------- 1 | extensions: 2 | client: 3 | endpoints: 4 | - wss://eu-ws.unique.network:443 5 | - wss://ws.unique.network:443 6 | event_bus: 7 | substrate_api: 8 | stale_timeout_seconds: 60 9 | cache: 10 | default_ttl_seconds: 0 11 | default_size: 2000 12 | merge_subscription: 13 | keep_alive_seconds: 60 14 | server: 15 | port: ${PORT} 16 | listen_address: '0.0.0.0' 17 | max_connections: 2000 18 | 19 | middlewares: 20 | methods: 21 | - response 22 | - inject_params 23 | - cache 24 | - upstream 25 | subscriptions: 26 | - merge_subscription 27 | - upstream 28 | 29 | rpcs: substrate 30 | -------------------------------------------------------------------------------- /scripts/run-all.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd "$(dirname "$0")" 4 | 5 | PORT=9000 subway --config configs/acala.yml & 6 | PORT=9001 subway --config configs/karura.yml & 7 | PORT=9002 subway --config configs/kusama.yml & 8 | PORT=9003 subway --config configs/polkadot.yml & 9 | PORT=9004 subway --config configs/statemine.yml & 10 | PORT=9005 subway --config configs/statemint.yml & 11 | PORT=9006 subway --config configs/basilisk.yml & 12 | PORT=9007 subway --config configs/hydraDX.yml & 13 | PORT=9008 subway --config configs/moonbeam.yml & 14 | PORT=9009 subway --config configs/moonriver.yml & 15 | PORT=9010 subway --config configs/astar.yml & 16 | PORT=9011 subway --config configs/shiden.yml & 17 | PORT=9012 subway --config configs/bifrost.yml & 18 | PORT=9013 subway --config configs/altair.yml & 19 | PORT=9014 subway --config configs/heiko.yml & 20 | PORT=9015 subway --config configs/bifrostpolkadot.yml & 21 | PORT=9016 subway --config configs/parallel.yml & 22 | PORT=9017 subway --config configs/centrifuge.yml & 23 | PORT=9018 subway --config configs/crust.yml & 24 | PORT=9019 subway --config configs/quartz.yml & 25 | PORT=9020 subway --config configs/unique.yml & 26 | PORT=9021 subway --config configs/interlay.yml & 27 | PORT=9022 subway --config configs/kintsugi.yml & 28 | PORT=9023 subway --config configs/khala.yml & 29 | PORT=9024 subway --config configs/phala.yml & 30 | PORT=9025 subway --config configs/crab.yml & 31 | trap 'kill $(jobs -p)' EXIT 32 | 33 | wait 34 | -------------------------------------------------------------------------------- /scripts/update-env.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | 3 | import { ApiPromise, WsProvider } from '@polkadot/api' 4 | import networkDefs from '../networks/all' 5 | 6 | const readEnvFile = () => { 7 | try { 8 | return fs.readFileSync('.env', 'utf8').toString() 9 | } catch (_err) { 10 | return '' 11 | } 12 | } 13 | 14 | const main = async () => { 15 | let envFile = readEnvFile() 16 | 17 | // comment out current ones 18 | envFile = envFile.replaceAll(/(^[A-Z0-9]+_BLOCK_NUMBER=\d+)/gm, '# $1') 19 | 20 | // prepend new ones 21 | const blockNumbers: Promise[] = [] 22 | for (const { polkadot, kusama } of Object.values(networkDefs)) { 23 | for (const { name, endpoint } of [polkadot, kusama]) { 24 | const fn = async () => { 25 | const api = await ApiPromise.create({ provider: new WsProvider(endpoint), noInitWarn: true }) 26 | const header = await api.rpc.chain.getHeader() 27 | const blockNumber = header.number.toNumber() 28 | return `${name.toUpperCase()}_BLOCK_NUMBER=${blockNumber}` 29 | } 30 | blockNumbers.push(fn()) 31 | } 32 | } 33 | 34 | const blockNumbersStr = (await Promise.all(blockNumbers)).join('\n') 35 | 36 | envFile = blockNumbersStr + '\n\n' + envFile 37 | 38 | console.log(blockNumbersStr) 39 | 40 | fs.writeFileSync('.env', envFile) 41 | } 42 | 43 | main() 44 | .catch(console.error) 45 | .finally(() => process.exit(0)) 46 | -------------------------------------------------------------------------------- /tests/acala/__snapshots__/stable-asset.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`acala stable asset > mint overflow > events 1`] = ` 4 | [ 5 | { 6 | "data": { 7 | "dispatchError": { 8 | "Arithmetic": "Overflow", 9 | }, 10 | "dispatchInfo": { 11 | "class": "Normal", 12 | "paysFee": "Yes", 13 | "weight": { 14 | "proofSize": "(rounded 17000)", 15 | "refTime": "(rounded 1300000000)", 16 | }, 17 | }, 18 | }, 19 | "method": "ExtrinsicFailed", 20 | "section": "system", 21 | }, 22 | ] 23 | `; 24 | 25 | exports[`acala stable asset > swap > events 1`] = ` 26 | [ 27 | { 28 | "data": { 29 | "a": "(number)", 30 | "balances": [ 31 | "(number)", 32 | "(number)", 33 | ], 34 | "inputAmount": "(number)", 35 | "inputAsset": { 36 | "Token": "DOT", 37 | }, 38 | "minOutputAmount": "(number)", 39 | "outputAmount": "(number)", 40 | "outputAsset": { 41 | "Token": "LDOT", 42 | }, 43 | "poolId": "(number)", 44 | "swapper": "23y3WetbNi6rDMgHmyRDjgpb7PnhgPotuPPawxruTMLYTLzG", 45 | "totalSupply": "(number)", 46 | }, 47 | "method": "TokenSwapped", 48 | "section": "stableAsset", 49 | }, 50 | ] 51 | `; 52 | 53 | exports[`acala stable asset > swap overflow > events 1`] = ` 54 | [ 55 | { 56 | "data": { 57 | "dispatchError": { 58 | "Arithmetic": "Overflow", 59 | }, 60 | "dispatchInfo": { 61 | "class": "Normal", 62 | "paysFee": "Yes", 63 | "weight": { 64 | "proofSize": "(rounded 11000)", 65 | "refTime": "(rounded 2900000000)", 66 | }, 67 | }, 68 | }, 69 | "method": "ExtrinsicFailed", 70 | "section": "system", 71 | }, 72 | ] 73 | `; 74 | 75 | exports[`acala stable asset > with liquidity > 'RedeemedProportion' > events 1`] = ` 76 | [ 77 | { 78 | "data": { 79 | "a": "(number)", 80 | "balances": [ 81 | "(number)", 82 | "(number)", 83 | ], 84 | "feeAmount": "(number)", 85 | "inputAmount": "(number)", 86 | "minOutputAmounts": [ 87 | "(number)", 88 | "(number)", 89 | ], 90 | "outputAmounts": [ 91 | "(number)", 92 | "(number)", 93 | ], 94 | "poolId": "(number)", 95 | "redeemer": "23y3WetbNi6rDMgHmyRDjgpb7PnhgPotuPPawxruTMLYTLzG", 96 | "totalSupply": "(number)", 97 | }, 98 | "method": "RedeemedProportion", 99 | "section": "stableAsset", 100 | }, 101 | ] 102 | `; 103 | 104 | exports[`acala stable asset > with liquidity > 'RedeemedSingle' > events 1`] = ` 105 | [ 106 | { 107 | "data": { 108 | "a": "(number)", 109 | "balances": [ 110 | "(number)", 111 | "(number)", 112 | ], 113 | "feeAmount": "(number)", 114 | "inputAmount": "(number)", 115 | "minOutputAmount": "(number)", 116 | "outputAmount": "(number)", 117 | "outputAsset": { 118 | "Token": "DOT", 119 | }, 120 | "poolId": "(number)", 121 | "redeemer": "23y3WetbNi6rDMgHmyRDjgpb7PnhgPotuPPawxruTMLYTLzG", 122 | "totalSupply": "(number)", 123 | }, 124 | "method": "RedeemedSingle", 125 | "section": "stableAsset", 126 | }, 127 | ] 128 | `; 129 | 130 | exports[`acala stable asset > with liquidity > mint > system events 1`] = ` 131 | [ 132 | { 133 | "data": { 134 | "a": "(number)", 135 | "balances": [ 136 | "(number)", 137 | "(number)", 138 | ], 139 | "feeAmount": "(number)", 140 | "inputAmounts": [ 141 | "(number)", 142 | "(number)", 143 | ], 144 | "minOutputAmount": "(number)", 145 | "minter": "23y3WetbNi6rDMgHmyRDjgpb7PnhgPotuPPawxruTMLYTLzG", 146 | "outputAmount": "(number)", 147 | "poolId": "(number)", 148 | "totalSupply": "(number)", 149 | }, 150 | "method": "Minted", 151 | "section": "stableAsset", 152 | }, 153 | ] 154 | `; 155 | 156 | exports[`karura stable asset > mint overflow > events 1`] = ` 157 | [ 158 | { 159 | "data": { 160 | "dispatchError": { 161 | "Arithmetic": "Overflow", 162 | }, 163 | "dispatchInfo": { 164 | "class": "Normal", 165 | "paysFee": "Yes", 166 | "weight": { 167 | "proofSize": "(rounded 17000)", 168 | "refTime": "(rounded 1300000000)", 169 | }, 170 | }, 171 | }, 172 | "method": "ExtrinsicFailed", 173 | "section": "system", 174 | }, 175 | ] 176 | `; 177 | 178 | exports[`karura stable asset > swap > events 1`] = ` 179 | [ 180 | { 181 | "data": { 182 | "a": "(number)", 183 | "balances": [ 184 | "(number)", 185 | "(number)", 186 | ], 187 | "inputAmount": "(number)", 188 | "inputAsset": { 189 | "Token": "KSM", 190 | }, 191 | "minOutputAmount": "(number)", 192 | "outputAmount": "(number)", 193 | "outputAsset": { 194 | "Token": "LKSM", 195 | }, 196 | "poolId": "(number)", 197 | "swapper": "rPizfonc8MPuEsMxufAytHjpRW7a2YrXWHKibaJXe9ZtjKx", 198 | "totalSupply": "(number)", 199 | }, 200 | "method": "TokenSwapped", 201 | "section": "stableAsset", 202 | }, 203 | ] 204 | `; 205 | 206 | exports[`karura stable asset > swap overflow > events 1`] = ` 207 | [ 208 | { 209 | "data": { 210 | "dispatchError": { 211 | "Arithmetic": "Overflow", 212 | }, 213 | "dispatchInfo": { 214 | "class": "Normal", 215 | "paysFee": "Yes", 216 | "weight": { 217 | "proofSize": "(rounded 11000)", 218 | "refTime": "(rounded 2900000000)", 219 | }, 220 | }, 221 | }, 222 | "method": "ExtrinsicFailed", 223 | "section": "system", 224 | }, 225 | ] 226 | `; 227 | 228 | exports[`karura stable asset > with liquidity > 'RedeemedProportion' > events 1`] = ` 229 | [ 230 | { 231 | "data": { 232 | "a": "(number)", 233 | "balances": [ 234 | "(number)", 235 | "(number)", 236 | ], 237 | "feeAmount": "(number)", 238 | "inputAmount": "(number)", 239 | "minOutputAmounts": [ 240 | "(number)", 241 | "(number)", 242 | ], 243 | "outputAmounts": [ 244 | "(number)", 245 | "(number)", 246 | ], 247 | "poolId": "(number)", 248 | "redeemer": "rPizfonc8MPuEsMxufAytHjpRW7a2YrXWHKibaJXe9ZtjKx", 249 | "totalSupply": "(number)", 250 | }, 251 | "method": "RedeemedProportion", 252 | "section": "stableAsset", 253 | }, 254 | ] 255 | `; 256 | 257 | exports[`karura stable asset > with liquidity > 'RedeemedSingle' > events 1`] = ` 258 | [ 259 | { 260 | "data": { 261 | "a": "(number)", 262 | "balances": [ 263 | "(number)", 264 | "(number)", 265 | ], 266 | "feeAmount": "(number)", 267 | "inputAmount": "(number)", 268 | "minOutputAmount": "(number)", 269 | "outputAmount": "(number)", 270 | "outputAsset": { 271 | "Token": "KSM", 272 | }, 273 | "poolId": "(number)", 274 | "redeemer": "rPizfonc8MPuEsMxufAytHjpRW7a2YrXWHKibaJXe9ZtjKx", 275 | "totalSupply": "(number)", 276 | }, 277 | "method": "RedeemedSingle", 278 | "section": "stableAsset", 279 | }, 280 | ] 281 | `; 282 | 283 | exports[`karura stable asset > with liquidity > mint > system events 1`] = ` 284 | [ 285 | { 286 | "data": { 287 | "a": "(number)", 288 | "balances": [ 289 | "(number)", 290 | "(number)", 291 | ], 292 | "feeAmount": "(number)", 293 | "inputAmounts": [ 294 | "(number)", 295 | "(number)", 296 | ], 297 | "minOutputAmount": "(number)", 298 | "minter": "rPizfonc8MPuEsMxufAytHjpRW7a2YrXWHKibaJXe9ZtjKx", 299 | "outputAmount": "(number)", 300 | "poolId": "(number)", 301 | "totalSupply": "(number)", 302 | }, 303 | "method": "Minted", 304 | "section": "stableAsset", 305 | }, 306 | ] 307 | `; 308 | -------------------------------------------------------------------------------- /tests/acala/aggregated-dex.test.ts: -------------------------------------------------------------------------------- 1 | import { afterAll, beforeAll, describe, expect, it } from 'vitest' 2 | import { sendTransaction } from '@acala-network/chopsticks-testing' 3 | 4 | import { Network, createContext, createNetworks } from '../../networks' 5 | import { acala, karura } from '../../networks/acala' 6 | import { checkEvents } from '../../helpers' 7 | 8 | describe.each([ 9 | { 10 | name: 'karura', 11 | swapPath: [ 12 | { 13 | Dex: [karura.ksm, karura.kar, karura.lksm, karura.ausd], 14 | }, 15 | { 16 | Taiga: [1, 0, 2], 17 | }, 18 | ], 19 | }, 20 | { 21 | name: 'acala', 22 | swapPath: [ 23 | { 24 | Dex: [acala.aca, acala.ausd, acala.ldot], 25 | }, 26 | { 27 | Taiga: [0, 1, 0], 28 | }, 29 | ], 30 | }, 31 | ] as const)('$name aggregatedDex', async ({ name, swapPath }) => { 32 | let chain: Network 33 | const ctx = createContext() 34 | const { alice, keyring } = ctx 35 | 36 | beforeAll(async () => { 37 | const networks = await createNetworks({ [name]: undefined }, ctx) 38 | chain = networks[name] 39 | const meta = await chain.chain.head.meta 40 | if (meta.registry.chainSS58) { 41 | keyring.setSS58Format(meta.registry.chainSS58) 42 | } 43 | 44 | // restore Homa.toBondPool to correct liquid token exchange rate 45 | const apiAt = await chain.api.at(await chain.api.rpc.chain.getBlockHash(chain.chain.head.number - 3)) 46 | const toBondPool: bigint = ((await apiAt.query.homa.toBondPool()) as any).toBigInt() 47 | await chain.dev.setStorage({ 48 | Homa: { 49 | toBondPool: toBondPool + 10n * 10n ** 10n, 50 | }, 51 | }) 52 | }) 53 | 54 | afterAll(async () => { 55 | await chain.teardown() 56 | }) 57 | 58 | it('swapWithExactSupply', async () => { 59 | const tx = await sendTransaction( 60 | chain.api.tx.aggregatedDex.swapWithExactSupply(swapPath as any, 1e10, 0).signAsync(alice), 61 | ) 62 | 63 | await chain.chain.newBlock() 64 | 65 | await checkEvents(tx, 'dex').toMatchObject([ 66 | expect.objectContaining({ 67 | method: 'Swap', 68 | section: 'dex', 69 | data: expect.objectContaining({ 70 | trader: alice.address, 71 | path: expect.arrayContaining(swapPath[0].Dex as any), 72 | liquidityChanges: expect.arrayContaining([1e10]), 73 | }), 74 | }), 75 | ]) 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /tests/acala/dex.test.ts: -------------------------------------------------------------------------------- 1 | import { afterEach, beforeEach, describe, it } from 'vitest' 2 | import { sendTransaction, testingPairs } from '@acala-network/chopsticks-testing' 3 | 4 | import { Network, createNetworks } from '../../networks' 5 | import { acala, karura } from '../../networks/acala' 6 | import { checkEvents } from '../../helpers' 7 | import { query } from '../../helpers/api' 8 | 9 | describe.each([ 10 | { 11 | name: 'karura', 12 | swapPair: [karura.ksm, karura.lksm], 13 | }, 14 | { 15 | name: 'acala', 16 | swapPair: [acala.ausd, acala.ldot], 17 | }, 18 | ] as const)(`$name dex`, async ({ name, swapPair }) => { 19 | const { alice } = testingPairs() 20 | 21 | let chain: Network 22 | 23 | beforeEach(async () => { 24 | const { [name]: chain1 } = await createNetworks({ [name]: undefined }) 25 | 26 | chain = chain1 27 | }) 28 | 29 | afterEach(async () => { 30 | await chain.teardown() 31 | }) 32 | 33 | it.each([ 34 | { 35 | name: 'swapWithExactSupply', 36 | tx: () => chain.api.tx.dex.swapWithExactSupply(swapPair as any, 1e12, 0), 37 | }, 38 | { 39 | name: 'swapWithExactTarget', 40 | tx: () => chain.api.tx.dex.swapWithExactTarget(swapPair as any, 1e12, 1e15), 41 | }, 42 | ] as const)('$name works', async ({ name, tx }) => { 43 | const _name = name 44 | const tx0 = await sendTransaction(tx().signAsync(alice)) 45 | 46 | await chain.chain.newBlock() 47 | 48 | await checkEvents(tx0, 'dex', 'tokens').redact({ number: true }).toMatchSnapshot() 49 | }) 50 | 51 | it.each([true, false])(`addLiquidity removeLiquidity works with stake %s`, async (stake) => { 52 | const tx0 = await sendTransaction( 53 | chain.api.tx.dex.addLiquidity(swapPair[0], swapPair[1], 1e12, 1e13, 0, stake).signAsync(alice), 54 | ) 55 | 56 | await chain.chain.newBlock() 57 | 58 | await checkEvents(tx0, 'dex', 'incentives', 'tokens').redact({ number: true }).toMatchSnapshot('addLiquidity') 59 | 60 | let lpAmount 61 | if (stake) { 62 | lpAmount = ( 63 | await chain.api.query.rewards.sharesAndWithdrawnRewards({ Dex: { DexShare: swapPair } }, alice.address) 64 | )[0] 65 | } else { 66 | lpAmount = ((await query.tokens({ DexShare: swapPair })(chain, alice.address)) as any).free 67 | } 68 | 69 | const tx1 = await sendTransaction( 70 | chain.api.tx.dex.removeLiquidity(swapPair[0], swapPair[1], lpAmount, 0, 0, stake).signAsync(alice), 71 | ) 72 | 73 | await chain.chain.newBlock() 74 | 75 | await checkEvents(tx1, 'dex', 'incentives', 'tokens').redact({ number: true }).toMatchSnapshot('removeLiquidity') 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /tests/acala/homa.test.ts: -------------------------------------------------------------------------------- 1 | import { afterEach, beforeEach, describe, it } from 'vitest' 2 | import { sendTransaction, testingPairs } from '@acala-network/chopsticks-testing' 3 | 4 | import { Network, createNetworks } from '../../networks' 5 | import { checkEvents, checkSystemEvents, checkUmp } from '../../helpers' 6 | 7 | describe.each([ 8 | { 9 | name: 'karura', 10 | relay: 'kusama', 11 | unbond: { para: 4981210, relay: 19226890, era: 5521 }, 12 | }, 13 | { 14 | name: 'acala', 15 | relay: 'polkadot', 16 | unbond: { para: 4225795, relay: 16829283, era: 1168 }, 17 | }, 18 | ] as const)('$name homa', async ({ name, relay, unbond }) => { 19 | let relaychain: Network 20 | let parachain: Network 21 | 22 | const { alice } = testingPairs() 23 | 24 | describe('with latest block', async () => { 25 | beforeEach(async () => { 26 | const { [name]: parachain1, [relay]: relaychain1 } = await createNetworks({ 27 | [name]: undefined, 28 | [relay]: undefined, 29 | }) 30 | 31 | relaychain = relaychain1 32 | parachain = parachain1 33 | }) 34 | 35 | afterEach(async () => { 36 | await relaychain.teardown() 37 | await parachain.teardown() 38 | }) 39 | 40 | it('Homa stake works', async () => { 41 | const tx0 = await sendTransaction(parachain.api.tx.homa.mint(1e12).signAsync(alice, { nonce: 0 })) 42 | const tx1 = await sendTransaction( 43 | parachain.api.tx.sudo.sudo(parachain.api.tx.homa.forceBumpCurrentEra(0)).signAsync(alice, { nonce: 1 }), 44 | ) 45 | 46 | await parachain.chain.newBlock() 47 | 48 | await checkEvents(tx0, 'homa').redact({ number: true }).toMatchSnapshot() 49 | await checkEvents(tx1, { section: 'homa', method: 'CurrentEraBumped' }).toMatchSnapshot() 50 | await checkUmp(parachain).redact({ number: true, hex: true }).toMatchSnapshot() 51 | 52 | await relaychain.chain.newBlock() 53 | 54 | await checkSystemEvents(relaychain, 'ump', 'staking', 'messageQueue') 55 | .redact({ address: true, number: true }) 56 | .toMatchSnapshot() 57 | }) 58 | 59 | it('Homa redeem unbond works', async () => { 60 | const tx0 = await sendTransaction(parachain.api.tx.homa.requestRedeem(1e12, false).signAsync(alice, { nonce: 0 })) 61 | const tx1 = await sendTransaction( 62 | parachain.api.tx.sudo.sudo(parachain.api.tx.homa.forceBumpCurrentEra(0)).signAsync(alice, { nonce: 1 }), 63 | ) 64 | 65 | await parachain.chain.newBlock() 66 | 67 | await checkEvents(tx0, { section: 'homa', method: 'RequestedRedeem' }).toMatchSnapshot() 68 | await checkEvents(tx1, { section: 'homa', method: 'RedeemedByUnbond' }).toMatchSnapshot() 69 | 70 | await relaychain.chain.newBlock() 71 | 72 | await checkSystemEvents(relaychain, 'ump', 'staking', 'messageQueue').redact({ address: true }).toMatchSnapshot() 73 | }) 74 | }) 75 | 76 | describe('with specific block', () => { 77 | beforeEach(async () => { 78 | const { [name]: parachain1, [relay]: relaychain1 } = await createNetworks({ 79 | [name]: { 80 | blockNumber: unbond.para, 81 | }, 82 | [relay]: { 83 | blockNumber: unbond.relay, 84 | }, 85 | }) 86 | 87 | relaychain = relaychain1 88 | parachain = parachain1 89 | 90 | await parachain.dev.setStorage({ 91 | Homa: { 92 | relayChainCurrentEra: unbond.era, 93 | }, 94 | }) 95 | 96 | return async () => { 97 | await relaychain.teardown() 98 | await parachain.teardown() 99 | } 100 | }) 101 | 102 | it('unbond withdraw works', async () => { 103 | const tx = await sendTransaction( 104 | parachain.api.tx.sudo.sudo(parachain.api.tx.homa.forceBumpCurrentEra(1)).signAsync(alice), 105 | ) 106 | await parachain.chain.newBlock() 107 | await checkEvents(tx, { section: 'homa', method: 'CurrentEraBumped' }).toMatchSnapshot() 108 | await checkUmp(parachain).toMatchSnapshot() 109 | 110 | await relaychain.chain.newBlock() 111 | await checkSystemEvents(relaychain, 'ump', 'staking', 'messageQueue').toMatchSnapshot() 112 | }) 113 | }) 114 | }) 115 | -------------------------------------------------------------------------------- /tests/acala/stable-asset.test.ts: -------------------------------------------------------------------------------- 1 | import { afterEach, beforeEach, describe, it } from 'vitest' 2 | import { sendTransaction } from '@acala-network/chopsticks-testing' 3 | 4 | import { Network, createContext, createNetworks } from '../../networks' 5 | import { checkEvents, checkSystemEvents } from '../../helpers' 6 | import { query } from '../../helpers/api' 7 | 8 | describe.each(['karura', 'acala'] as const)('%s stable asset', async (name) => { 9 | let chain: Network 10 | 11 | const ctx = createContext() 12 | const { alice } = ctx 13 | 14 | beforeEach(async () => { 15 | const { [name]: chain1 } = await createNetworks({ [name]: undefined }, ctx) 16 | chain = chain1 17 | 18 | // restore Homa.toBondPool to correct liquid token exchange rate 19 | const apiAt = await chain.api.at(await chain.api.rpc.chain.getBlockHash(chain.chain.head.number - 3)) 20 | const toBondPool: bigint = ((await apiAt.query.homa.toBondPool()) as any).toBigInt() 21 | await chain.dev.setStorage({ 22 | Homa: { 23 | toBondPool: toBondPool + 100n * 10n ** 10n, 24 | }, 25 | }) 26 | }) 27 | 28 | afterEach(async () => { 29 | await chain.teardown() 30 | }) 31 | 32 | it('swap', async () => { 33 | const tx0 = await sendTransaction(chain.api.tx.stableAsset.swap(0, 0, 1, 1e12, 1e11, 2).signAsync(alice)) 34 | 35 | await chain.chain.newBlock() 36 | 37 | await checkEvents(tx0, { section: 'stableAsset', method: 'TokenSwapped' }) 38 | .redact({ number: true }) 39 | .toMatchSnapshot() 40 | }) 41 | 42 | describe('with liquidity', () => { 43 | beforeEach(async () => { 44 | await sendTransaction(chain.api.tx.stableAsset.mint(0, [1e12, 1e12], 0).signAsync(alice)) 45 | 46 | await chain.chain.newBlock() 47 | }) 48 | 49 | it('mint', async () => { 50 | await checkSystemEvents(chain, { section: 'stableAsset', method: 'Minted' }) 51 | .redact({ number: true }) 52 | .toMatchSnapshot() 53 | }) 54 | 55 | it.each([ 56 | { 57 | tx: (x: any) => chain.api.tx.stableAsset.redeemSingle(0, x, 0, 0, 2), 58 | event: 'RedeemedSingle', 59 | }, 60 | { 61 | tx: (x: any) => chain.api.tx.stableAsset.redeemProportion(0, x, [0, 0]), 62 | event: 'RedeemedProportion', 63 | }, 64 | ] as const)('$event', async ({ tx, event }) => { 65 | const balData: any = await query.tokens({ StableAssetPoolToken: 0 })(chain, alice.address) 66 | 67 | const tx0 = await sendTransaction(tx(balData.free).signAsync(alice)) 68 | 69 | await chain.chain.newBlock() 70 | 71 | await checkEvents(tx0, { section: 'stableAsset', method: event }).redact({ number: true }).toMatchSnapshot() 72 | }) 73 | }) 74 | 75 | it('mint overflow', async () => { 76 | const mintAmount = 68056473384187692692674921486353642291n 77 | const tx0 = await sendTransaction(chain.api.tx.stableAsset.mint(0, [0, mintAmount], 0).signAsync(alice)) 78 | 79 | await chain.chain.newBlock() 80 | 81 | await checkEvents(tx0, 'system').toMatchSnapshot() 82 | }) 83 | 84 | it('swap overflow', async () => { 85 | const swapAmount = 68056473384187692692674921486353642291n 86 | const tx0 = await sendTransaction(chain.api.tx.stableAsset.swap(0, 1, 0, swapAmount, 0, 2).signAsync(alice)) 87 | 88 | await chain.chain.newBlock() 89 | 90 | await checkEvents(tx0, 'system').toMatchSnapshot() 91 | }) 92 | }) 93 | -------------------------------------------------------------------------------- /tests/bridge-sdk/__snapshots__/kusama.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`'assetHubKusama' to 'karura' using bridgeSDK cross-chain 'USDT' > Cross-chain using BridgeSDK works > after 1`] = ` 4 | { 5 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 6 | "decimals": 6, 7 | "fromChain": 998, 8 | "toChain": "(rounded 2)", 9 | } 10 | `; 11 | 12 | exports[`'assetHubKusama' to 'karura' using bridgeSDK cross-chain 'USDT' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.0009)"`; 13 | 14 | exports[`'assetHubKusama' to 'karura' using bridgeSDK cross-chain 'USDT' > Cross-chain using BridgeSDK works > initial 1`] = ` 15 | { 16 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 17 | "decimals": 6, 18 | "fromChain": 1000, 19 | "toChain": 0, 20 | } 21 | `; 22 | 23 | exports[`'assetHubKusama' to 'kusama' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > after 1`] = ` 24 | { 25 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 26 | "decimals": 12, 27 | "fromChain": "(rounded 8)", 28 | "toChain": "(rounded 12)", 29 | } 30 | `; 31 | 32 | exports[`'assetHubKusama' to 'kusama' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.00009)"`; 33 | 34 | exports[`'assetHubKusama' to 'kusama' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > initial 1`] = ` 35 | { 36 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 37 | "decimals": 12, 38 | "fromChain": 10, 39 | "toChain": 10, 40 | } 41 | `; 42 | 43 | exports[`'bifrost' to 'karura' using bridgeSDK cross-chain 'BNC' > Cross-chain using BridgeSDK works > after 1`] = ` 44 | { 45 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 46 | "decimals": 12, 47 | "fromChain": "(rounded 998)", 48 | "toChain": "(rounded 1.99)", 49 | } 50 | `; 51 | 52 | exports[`'bifrost' to 'karura' using bridgeSDK cross-chain 'BNC' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.01)"`; 53 | 54 | exports[`'bifrost' to 'karura' using bridgeSDK cross-chain 'BNC' > Cross-chain using BridgeSDK works > initial 1`] = ` 55 | { 56 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 57 | "decimals": 12, 58 | "fromChain": 1000, 59 | "toChain": 0, 60 | } 61 | `; 62 | 63 | exports[`'karura' to 'assetHubKusama' using bridgeSDK cross-chain 'USDT' > Cross-chain using BridgeSDK works > after 1`] = ` 64 | { 65 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 66 | "decimals": 6, 67 | "fromChain": 998, 68 | "toChain": "(rounded 1000)", 69 | } 70 | `; 71 | 72 | exports[`'karura' to 'assetHubKusama' using bridgeSDK cross-chain 'USDT' > Cross-chain using BridgeSDK works > initial 1`] = ` 73 | { 74 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 75 | "decimals": 6, 76 | "fromChain": 1000, 77 | "toChain": 1000, 78 | } 79 | `; 80 | 81 | exports[`'karura' to 'bifrost' using bridgeSDK cross-chain 'KUSD' > Cross-chain using BridgeSDK works > after 1`] = ` 82 | { 83 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 84 | "decimals": 12, 85 | "fromChain": 8, 86 | "toChain": "(rounded 1.9)", 87 | } 88 | `; 89 | 90 | exports[`'karura' to 'bifrost' using bridgeSDK cross-chain 'KUSD' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.05)"`; 91 | 92 | exports[`'karura' to 'bifrost' using bridgeSDK cross-chain 'KUSD' > Cross-chain using BridgeSDK works > initial 1`] = ` 93 | { 94 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 95 | "decimals": 12, 96 | "fromChain": 10, 97 | "toChain": 0, 98 | } 99 | `; 100 | 101 | exports[`'karura' to 'kintsugi' using bridgeSDK cross-chain 'KINT' > Cross-chain using BridgeSDK works > after 1`] = ` 102 | { 103 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 104 | "decimals": 12, 105 | "fromChain": 998, 106 | "toChain": "(rounded 1000)", 107 | } 108 | `; 109 | 110 | exports[`'karura' to 'kintsugi' using bridgeSDK cross-chain 'KINT' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.0002)"`; 111 | 112 | exports[`'karura' to 'kintsugi' using bridgeSDK cross-chain 'KINT' > Cross-chain using BridgeSDK works > initial 1`] = ` 113 | { 114 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 115 | "decimals": 12, 116 | "fromChain": 1000, 117 | "toChain": 1000, 118 | } 119 | `; 120 | 121 | exports[`'karura' to 'kintsugi' using bridgeSDK cross-chain 'LKSM' > Cross-chain using BridgeSDK works > after 1`] = ` 122 | { 123 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 124 | "decimals": 12, 125 | "fromChain": 98, 126 | "toChain": "(rounded 102)", 127 | } 128 | `; 129 | 130 | exports[`'karura' to 'kintsugi' using bridgeSDK cross-chain 'LKSM' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.0002)"`; 131 | 132 | exports[`'karura' to 'kintsugi' using bridgeSDK cross-chain 'LKSM' > Cross-chain using BridgeSDK works > initial 1`] = ` 133 | { 134 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 135 | "decimals": 12, 136 | "fromChain": 100, 137 | "toChain": 100, 138 | } 139 | `; 140 | 141 | exports[`'karura' to 'kusama' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > after 1`] = ` 142 | { 143 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 144 | "decimals": 12, 145 | "fromChain": 8, 146 | "toChain": "(rounded 12)", 147 | } 148 | `; 149 | 150 | exports[`'karura' to 'kusama' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.00009)"`; 151 | 152 | exports[`'karura' to 'kusama' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > initial 1`] = ` 153 | { 154 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 155 | "decimals": 12, 156 | "fromChain": 10, 157 | "toChain": 10, 158 | } 159 | `; 160 | 161 | exports[`'karura' to 'shiden' using bridgeSDK cross-chain 'KUSD' > Cross-chain using BridgeSDK works > after 1`] = ` 162 | { 163 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 164 | "decimals": 12, 165 | "fromChain": 8, 166 | "toChain": "(rounded 12)", 167 | } 168 | `; 169 | 170 | exports[`'karura' to 'shiden' using bridgeSDK cross-chain 'KUSD' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.0005)"`; 171 | 172 | exports[`'karura' to 'shiden' using bridgeSDK cross-chain 'KUSD' > Cross-chain using BridgeSDK works > initial 1`] = ` 173 | { 174 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 175 | "decimals": 12, 176 | "fromChain": 10, 177 | "toChain": 10, 178 | } 179 | `; 180 | 181 | exports[`'kintsugi' to 'karura' using bridgeSDK cross-chain 'KINT' > Cross-chain using BridgeSDK works > after 1`] = ` 182 | { 183 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 184 | "decimals": 12, 185 | "fromChain": "(rounded 998)", 186 | "toChain": "(rounded 2)", 187 | } 188 | `; 189 | 190 | exports[`'kintsugi' to 'karura' using bridgeSDK cross-chain 'KINT' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.0002)"`; 191 | 192 | exports[`'kintsugi' to 'karura' using bridgeSDK cross-chain 'KINT' > Cross-chain using BridgeSDK works > initial 1`] = ` 193 | { 194 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 195 | "decimals": 12, 196 | "fromChain": 1000, 197 | "toChain": 0, 198 | } 199 | `; 200 | 201 | exports[`'kintsugi' to 'karura' using bridgeSDK cross-chain 'LKSM' > Cross-chain using BridgeSDK works > after 1`] = ` 202 | { 203 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 204 | "decimals": 12, 205 | "fromChain": 98, 206 | "toChain": "(rounded 102)", 207 | } 208 | `; 209 | 210 | exports[`'kintsugi' to 'karura' using bridgeSDK cross-chain 'LKSM' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.0001)"`; 211 | 212 | exports[`'kintsugi' to 'karura' using bridgeSDK cross-chain 'LKSM' > Cross-chain using BridgeSDK works > initial 1`] = ` 213 | { 214 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 215 | "decimals": 12, 216 | "fromChain": 100, 217 | "toChain": 100, 218 | } 219 | `; 220 | 221 | exports[`'kusama' to 'assetHubKusama' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > after 1`] = ` 222 | { 223 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 224 | "decimals": 12, 225 | "fromChain": "(rounded 8)", 226 | "toChain": "(rounded 12)", 227 | } 228 | `; 229 | 230 | exports[`'kusama' to 'assetHubKusama' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.0001)"`; 231 | 232 | exports[`'kusama' to 'assetHubKusama' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > initial 1`] = ` 233 | { 234 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 235 | "decimals": 12, 236 | "fromChain": 10, 237 | "toChain": 10, 238 | } 239 | `; 240 | 241 | exports[`'kusama' to 'basilisk' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > after 1`] = ` 242 | { 243 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 244 | "decimals": 12, 245 | "fromChain": "(rounded 8)", 246 | "toChain": "(rounded 1000)", 247 | } 248 | `; 249 | 250 | exports[`'kusama' to 'basilisk' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > initial 1`] = ` 251 | { 252 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 253 | "decimals": 12, 254 | "fromChain": 10, 255 | "toChain": 1000, 256 | } 257 | `; 258 | 259 | exports[`'kusama' to 'karura' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > after 1`] = ` 260 | { 261 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 262 | "decimals": 12, 263 | "fromChain": "(rounded 8)", 264 | "toChain": "(rounded 12)", 265 | } 266 | `; 267 | 268 | exports[`'kusama' to 'karura' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.00002)"`; 269 | 270 | exports[`'kusama' to 'karura' using bridgeSDK cross-chain 'KSM' > Cross-chain using BridgeSDK works > initial 1`] = ` 271 | { 272 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 273 | "decimals": 12, 274 | "fromChain": 10, 275 | "toChain": 10, 276 | } 277 | `; 278 | 279 | exports[`'shiden' to 'karura' using bridgeSDK cross-chain 'KUSD' > Cross-chain using BridgeSDK works > after 1`] = ` 280 | { 281 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 282 | "decimals": 12, 283 | "fromChain": 8, 284 | "toChain": "(rounded 12)", 285 | } 286 | `; 287 | 288 | exports[`'shiden' to 'karura' using bridgeSDK cross-chain 'KUSD' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.002)"`; 289 | 290 | exports[`'shiden' to 'karura' using bridgeSDK cross-chain 'KUSD' > Cross-chain using BridgeSDK works > initial 1`] = ` 291 | { 292 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 293 | "decimals": 12, 294 | "fromChain": 10, 295 | "toChain": 10, 296 | } 297 | `; 298 | -------------------------------------------------------------------------------- /tests/bridge-sdk/__snapshots__/polkadot.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`'acala' to 'assetHubPolkadot' using bridgeSDK cross-chain 'USDT' > Cross-chain using BridgeSDK works > after 1`] = ` 4 | { 5 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 6 | "decimals": 6, 7 | "fromChain": 998, 8 | "toChain": "(rounded 1000)", 9 | } 10 | `; 11 | 12 | exports[`'acala' to 'assetHubPolkadot' using bridgeSDK cross-chain 'USDT' > Cross-chain using BridgeSDK works > fee 1`] = `0`; 13 | 14 | exports[`'acala' to 'assetHubPolkadot' using bridgeSDK cross-chain 'USDT' > Cross-chain using BridgeSDK works > initial 1`] = ` 15 | { 16 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 17 | "decimals": 6, 18 | "fromChain": 1000, 19 | "toChain": 1000, 20 | } 21 | `; 22 | 23 | exports[`'acala' to 'astar' using bridgeSDK cross-chain 'AUSD' > Cross-chain using BridgeSDK works > after 1`] = ` 24 | { 25 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 26 | "decimals": 12, 27 | "fromChain": 8, 28 | "toChain": "(rounded 12)", 29 | } 30 | `; 31 | 32 | exports[`'acala' to 'astar' using bridgeSDK cross-chain 'AUSD' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.00006)"`; 33 | 34 | exports[`'acala' to 'astar' using bridgeSDK cross-chain 'AUSD' > Cross-chain using BridgeSDK works > initial 1`] = ` 35 | { 36 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 37 | "decimals": 12, 38 | "fromChain": 10, 39 | "toChain": 10, 40 | } 41 | `; 42 | 43 | exports[`'acala' to 'interlay' using bridgeSDK cross-chain 'INTR' > Cross-chain using BridgeSDK works > after 1`] = ` 44 | { 45 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 46 | "decimals": 10, 47 | "fromChain": 8, 48 | "toChain": "(rounded 100000)", 49 | } 50 | `; 51 | 52 | exports[`'acala' to 'interlay' using bridgeSDK cross-chain 'INTR' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.002)"`; 53 | 54 | exports[`'acala' to 'interlay' using bridgeSDK cross-chain 'INTR' > Cross-chain using BridgeSDK works > initial 1`] = ` 55 | { 56 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 57 | "decimals": 10, 58 | "fromChain": 10, 59 | "toChain": 100000, 60 | } 61 | `; 62 | 63 | exports[`'acala' to 'polkadot' using bridgeSDK cross-chain 'DOT' > Cross-chain using BridgeSDK works > after 1`] = ` 64 | { 65 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 66 | "decimals": 10, 67 | "fromChain": 998, 68 | "toChain": "(rounded 1000)", 69 | } 70 | `; 71 | 72 | exports[`'acala' to 'polkadot' using bridgeSDK cross-chain 'DOT' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.002)"`; 73 | 74 | exports[`'acala' to 'polkadot' using bridgeSDK cross-chain 'DOT' > Cross-chain using BridgeSDK works > initial 1`] = ` 75 | { 76 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 77 | "decimals": 10, 78 | "fromChain": 1000, 79 | "toChain": 1000, 80 | } 81 | `; 82 | 83 | exports[`'assetHubPolkadot' to 'acala' using bridgeSDK cross-chain 'USDT' > Cross-chain using BridgeSDK works > after 1`] = ` 84 | { 85 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 86 | "decimals": 6, 87 | "fromChain": 998, 88 | "toChain": "(rounded 2)", 89 | } 90 | `; 91 | 92 | exports[`'assetHubPolkadot' to 'acala' using bridgeSDK cross-chain 'USDT' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.0009)"`; 93 | 94 | exports[`'assetHubPolkadot' to 'acala' using bridgeSDK cross-chain 'USDT' > Cross-chain using BridgeSDK works > initial 1`] = ` 95 | { 96 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 97 | "decimals": 6, 98 | "fromChain": 1000, 99 | "toChain": 0, 100 | } 101 | `; 102 | 103 | exports[`'assetHubPolkadot' to 'polkadot' using bridgeSDK cross-chain 'DOT' > Cross-chain using BridgeSDK works > after 1`] = ` 104 | { 105 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 106 | "decimals": 10, 107 | "fromChain": "(rounded 998)", 108 | "toChain": "(rounded 1000)", 109 | } 110 | `; 111 | 112 | exports[`'assetHubPolkadot' to 'polkadot' using bridgeSDK cross-chain 'DOT' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.002)"`; 113 | 114 | exports[`'assetHubPolkadot' to 'polkadot' using bridgeSDK cross-chain 'DOT' > Cross-chain using BridgeSDK works > initial 1`] = ` 115 | { 116 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 117 | "decimals": 10, 118 | "fromChain": 1000, 119 | "toChain": 1000, 120 | } 121 | `; 122 | 123 | exports[`'astar' to 'acala' using bridgeSDK cross-chain 'AUSD' > Cross-chain using BridgeSDK works > after 1`] = ` 124 | { 125 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 126 | "decimals": 12, 127 | "fromChain": 8, 128 | "toChain": "(rounded 1000)", 129 | } 130 | `; 131 | 132 | exports[`'astar' to 'acala' using bridgeSDK cross-chain 'AUSD' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.001)"`; 133 | 134 | exports[`'astar' to 'acala' using bridgeSDK cross-chain 'AUSD' > Cross-chain using BridgeSDK works > initial 1`] = ` 135 | { 136 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 137 | "decimals": 12, 138 | "fromChain": 10, 139 | "toChain": 1000, 140 | } 141 | `; 142 | 143 | exports[`'interlay' to 'acala' using bridgeSDK cross-chain 'INTR' > Cross-chain using BridgeSDK works > after 1`] = ` 144 | { 145 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 146 | "decimals": 10, 147 | "fromChain": "(rounded 100000)", 148 | "toChain": "(rounded 1.99)", 149 | } 150 | `; 151 | 152 | exports[`'interlay' to 'acala' using bridgeSDK cross-chain 'INTR' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.007)"`; 153 | 154 | exports[`'interlay' to 'acala' using bridgeSDK cross-chain 'INTR' > Cross-chain using BridgeSDK works > initial 1`] = ` 155 | { 156 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 157 | "decimals": 10, 158 | "fromChain": 100000, 159 | "toChain": 0, 160 | } 161 | `; 162 | 163 | exports[`'polkadot' to 'acala' using bridgeSDK cross-chain 'DOT' > Cross-chain using BridgeSDK works > after 1`] = ` 164 | { 165 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 166 | "decimals": 10, 167 | "fromChain": "(rounded 998)", 168 | "toChain": "(rounded 1000)", 169 | } 170 | `; 171 | 172 | exports[`'polkadot' to 'acala' using bridgeSDK cross-chain 'DOT' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.00008)"`; 173 | 174 | exports[`'polkadot' to 'acala' using bridgeSDK cross-chain 'DOT' > Cross-chain using BridgeSDK works > initial 1`] = ` 175 | { 176 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 177 | "decimals": 10, 178 | "fromChain": 1000, 179 | "toChain": 1000, 180 | } 181 | `; 182 | 183 | exports[`'polkadot' to 'assetHubPolkadot' using bridgeSDK cross-chain 'DOT' > Cross-chain using BridgeSDK works > after 1`] = ` 184 | { 185 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 186 | "decimals": 10, 187 | "fromChain": "(rounded 998)", 188 | "toChain": "(rounded 1000)", 189 | } 190 | `; 191 | 192 | exports[`'polkadot' to 'assetHubPolkadot' using bridgeSDK cross-chain 'DOT' > Cross-chain using BridgeSDK works > fee 1`] = `"(rounded 0.002)"`; 193 | 194 | exports[`'polkadot' to 'assetHubPolkadot' using bridgeSDK cross-chain 'DOT' > Cross-chain using BridgeSDK works > initial 1`] = ` 195 | { 196 | "address": "5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu", 197 | "decimals": 10, 198 | "fromChain": 1000, 199 | "toChain": 1000, 200 | } 201 | `; 202 | -------------------------------------------------------------------------------- /tests/bridge-sdk/kusama.test.ts: -------------------------------------------------------------------------------- 1 | import { buildTests } from './shared' 2 | 3 | const tests = [ 4 | { 5 | from: 'karura', 6 | to: 'kusama', 7 | token: 'KSM', 8 | }, 9 | { 10 | from: 'kusama', 11 | to: 'karura', 12 | token: 'KSM', 13 | }, 14 | { 15 | from: 'kusama', 16 | to: 'basilisk', 17 | token: 'KSM', 18 | ignoreFee: true, 19 | }, 20 | // { 21 | // from: 'basilisk', 22 | // to: 'kusama', 23 | // token: 'KSM', 24 | // }, 25 | { 26 | from: 'assetHubKusama', 27 | to: 'kusama', 28 | token: 'KSM', 29 | }, 30 | { 31 | from: 'kusama', 32 | to: 'assetHubKusama', 33 | token: 'KSM', 34 | }, 35 | { 36 | from: 'assetHubKusama', 37 | to: 'karura', 38 | token: 'USDT', 39 | }, 40 | { 41 | from: 'karura', 42 | to: 'assetHubKusama', 43 | token: 'USDT', 44 | ignoreFee: true, 45 | }, 46 | // { 47 | // from: 'basilisk', 48 | // to: 'karura', 49 | // token: 'BSX', 50 | // }, 51 | // { 52 | // from: 'karura', 53 | // to: 'basilisk', 54 | // token: 'BSX', 55 | // }, 56 | // { 57 | // from: 'karura', 58 | // to: 'moonriver', 59 | // token: 'KAR', 60 | // }, 61 | { 62 | from: 'karura', 63 | to: 'bifrost', 64 | token: 'KUSD', 65 | precision: 2, 66 | }, 67 | { 68 | from: 'bifrost', 69 | to: 'karura', 70 | token: 'BNC', 71 | }, 72 | // { 73 | // from: 'altair', 74 | // to: 'karura', 75 | // token: 'AIR', 76 | // }, 77 | // { 78 | // from: 'karura', 79 | // to: 'altair', 80 | // token: 'AIR', 81 | // }, 82 | { 83 | from: 'shiden', 84 | to: 'karura', 85 | token: 'KUSD', 86 | }, 87 | { 88 | from: 'karura', 89 | to: 'shiden', 90 | token: 'KUSD', 91 | }, 92 | { 93 | from: 'karura', 94 | to: 'kintsugi', 95 | token: 'KINT', 96 | }, 97 | { 98 | from: 'kintsugi', 99 | to: 'karura', 100 | token: 'KINT', 101 | }, 102 | { 103 | from: 'karura', 104 | to: 'kintsugi', 105 | token: 'LKSM', 106 | }, 107 | { 108 | from: 'kintsugi', 109 | to: 'karura', 110 | token: 'LKSM', 111 | }, 112 | // // btc 113 | // // { 114 | // // from: 'karura', 115 | // // to: 'kintsugi', 116 | // // token: 'KBTC', 117 | // // fee: 0.07407407407400002 118 | // // }, 119 | // // { 120 | // // from: 'kintsugi', 121 | // // to: 'karura', 122 | // // token: 'KBTC', 123 | // // fee: 0.008012799999999931 124 | // // }, 125 | 126 | // { 127 | // from: 'crab', 128 | // to: 'karura', 129 | // token: 'CRAB', 130 | // }, 131 | // { 132 | // from: 'khala', 133 | // to: 'karura', 134 | // token: 'KUSD', 135 | // }, 136 | // { 137 | // from: 'karura', 138 | // to: 'khala', 139 | // token: 'KUSD', 140 | // }, 141 | // Chopsticks are currently not supported. 142 | // { 143 | // from: 'crust', 144 | // to: 'karura', 145 | // token: 'CSM', 146 | // fee: 0.008082399999999934 147 | // }, 148 | // { 149 | // from: 'karura', 150 | // to: 'crust', 151 | // token: 'CSM', 152 | // fee: 0.002080000000000082 153 | // }, 154 | // { 155 | // from: 'unique', 156 | // to: 'acala', 157 | // token: 'UNQ', 158 | // fee: 0.008082399999999934 159 | // }, 160 | // { 161 | // from: 'quartz', 162 | // to: 'karura', 163 | // token: 'QTZ', 164 | // }, 165 | // { 166 | // from: 'karura', 167 | // to: 'quartz', 168 | // token: 'QTZ', 169 | // }, 170 | ] as const 171 | 172 | buildTests(tests) 173 | -------------------------------------------------------------------------------- /tests/bridge-sdk/polkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { buildTests } from './shared' 2 | 3 | const tests = [ 4 | { 5 | from: 'acala', 6 | to: 'polkadot', 7 | token: 'DOT', 8 | }, 9 | { 10 | from: 'polkadot', 11 | to: 'acala', 12 | token: 'DOT', 13 | }, 14 | { 15 | from: 'acala', 16 | to: 'assetHubPolkadot', 17 | token: 'USDT', 18 | }, 19 | { 20 | from: 'assetHubPolkadot', 21 | to: 'acala', 22 | token: 'USDT', 23 | }, 24 | { 25 | from: 'polkadot', 26 | to: 'assetHubPolkadot', 27 | token: 'DOT', 28 | }, 29 | { 30 | from: 'assetHubPolkadot', 31 | to: 'polkadot', 32 | token: 'DOT', 33 | }, 34 | // { 35 | // from: 'acala', 36 | // to: 'moonbeam', 37 | // token: 'AUSD', 38 | // }, 39 | { 40 | from: 'astar', 41 | to: 'acala', 42 | token: 'AUSD', 43 | }, 44 | { 45 | from: 'acala', 46 | to: 'astar', 47 | token: 'AUSD', 48 | }, 49 | { 50 | from: 'interlay', 51 | to: 'acala', 52 | token: 'INTR', 53 | }, 54 | { 55 | from: 'acala', 56 | to: 'interlay', 57 | token: 'INTR', 58 | }, 59 | 60 | // btc 61 | // { 62 | // from: 'interlay', 63 | // to: 'acala', 64 | // token: 'IBTC', 65 | // fee: 0.008012799999999931 66 | // }, 67 | // { 68 | // from: 'acala', 69 | // to: 'interlay', 70 | // token: 'IBTC', 71 | // fee: 0.008012799999999931 72 | // }, 73 | 74 | // Chopsticks are currently not supported. 75 | // { 76 | // from: 'crust', 77 | // to: 'karura', 78 | // token: 'CSM', 79 | // fee: 0.008082399999999934 80 | // }, 81 | // { 82 | // from: 'karura', 83 | // to: 'crust', 84 | // token: 'CSM', 85 | // fee: 0.002080000000000082 86 | // }, 87 | // { 88 | // from: 'unique', 89 | // to: 'acala', 90 | // token: 'UNQ', 91 | // fee: 0.008082399999999934 92 | // }, 93 | ] as const 94 | 95 | buildTests(tests) 96 | -------------------------------------------------------------------------------- /tests/bridge-sdk/shared.ts: -------------------------------------------------------------------------------- 1 | import { ApiPromise } from '@polkadot/api' 2 | import { FixedPointNumber } from '@acala-network/sdk-core' 3 | import { afterEach, beforeEach, describe, expect, it } from 'vitest' 4 | import { sendTransaction, testingPairs } from '@acala-network/chopsticks-testing' 5 | 6 | import { AcalaAdapter } from '@polkawallet/bridge/adapters/acala/acala' 7 | import { AltairAdapter } from '@polkawallet/bridge/adapters/centrifuge' 8 | import { AssetHubKusamaAdapter, AssetHubPolkadotAdapter } from '@polkawallet/bridge/adapters/assethub' 9 | import { AstarAdapter, ShidenAdapter } from '@polkawallet/bridge/adapters/astar' 10 | import { BasiliskAdapter } from '@polkawallet/bridge/adapters/hydradx' 11 | import { BifrostAdapter } from '@polkawallet/bridge/adapters/bifrost' 12 | import { Bridge } from '@polkawallet/bridge' 13 | import { CrabAdapter } from '@polkawallet/bridge/adapters/darwinia' 14 | import { InterlayAdapter, KintsugiAdapter } from '@polkawallet/bridge/adapters/interlay' 15 | import { KaruraAdapter } from '@polkawallet/bridge/adapters/acala' 16 | import { KhalaAdapter } from '@polkawallet/bridge/adapters/phala' 17 | import { KusamaAdapter, PolkadotAdapter } from '@polkawallet/bridge/adapters/polkadot' 18 | import { MoonbeamAdapter, MoonriverAdapter } from '@polkawallet/bridge/adapters/moonbeam' 19 | import { QuartzAdapter, UniqueAdapter } from '@polkawallet/bridge/adapters/unique' 20 | import { ShadowAdapter } from '@polkawallet/bridge/adapters/crust' 21 | 22 | import { Network, NetworkNames, createNetworks } from '../../networks' 23 | import { check } from '../../helpers' 24 | 25 | export type TestTtype = { 26 | from: NetworkNames 27 | to: NetworkNames 28 | token: string 29 | ignoreFee?: boolean 30 | precision?: number 31 | } 32 | 33 | export const buildTests = (tests: ReadonlyArray) => { 34 | for (const { from, to, token, ignoreFee, precision } of tests) { 35 | describe(`'${from}' to '${to}' using bridgeSDK cross-chain '${token}'`, async () => { 36 | let fromchain: Network 37 | let tochain: Network 38 | 39 | const { alice } = testingPairs() 40 | 41 | beforeEach(async () => { 42 | const { [from]: fromchain1, [to]: tochain1 } = await createNetworks({ 43 | [from]: undefined, 44 | [to]: undefined, 45 | }) 46 | if (from == 'karura') { 47 | await fromchain1.dev.setStorage({ 48 | Tokens: { 49 | Accounts: [ 50 | [[alice.address, { Token: 'KINT' }], { free: '1000000000000000' }], 51 | [[alice.address, { Token: 'KBTC' }], { free: 3 * 1e8 }], 52 | [[alice.address, { ForeignAsset: 7 }], { free: 1000e6 }], 53 | [[alice.address, { ForeignAsset: 12 }], { free: '100000000000000000000' }], 54 | [[alice.address, { Token: 'KUSD' }], { free: 10 * 1e12 }], 55 | ], 56 | }, 57 | }) 58 | } 59 | if (from == 'acala') { 60 | await fromchain1.dev.setStorage({ 61 | Tokens: { 62 | Accounts: [ 63 | [[alice.address, { ForeignAsset: 1 }], { free: 10 * 1e12 }], 64 | [[alice.address, { ForeignAsset: 4 }], { free: 10 * 1e10 }], 65 | [[alice.address, { ForeignAsset: 3 }], { free: 3 * 1e8 }], 66 | [[alice.address, { ForeignAsset: 12 }], { free: 1000e6 }], 67 | [[alice.address, { Token: 'AUSD' }], { free: 10 * 1e12 }], 68 | ], 69 | }, 70 | }) 71 | } 72 | if (to == 'karura') { 73 | await tochain1.dev.setStorage({ 74 | Tokens: { 75 | Accounts: [ 76 | [[alice.address, { Token: 'KUSD' }], { free: 10 * 1e12 }], 77 | [[alice.address, { Token: 'AUSD' }], { free: 10 * 1e12 }], 78 | ], 79 | }, 80 | }) 81 | } 82 | tochain = tochain1 83 | fromchain = fromchain1 84 | }) 85 | 86 | afterEach(async () => { 87 | await tochain.teardown() 88 | await fromchain.teardown() 89 | }) 90 | 91 | async function sleep(ms: number) { 92 | return new Promise((resolve) => setTimeout(resolve, ms)) 93 | } 94 | 95 | async function chooseAdapter(chain: string, api: ApiPromise) { 96 | const adapters = { 97 | karura: KaruraAdapter, 98 | kusama: KusamaAdapter, 99 | moonriver: MoonriverAdapter, 100 | assetHubKusama: AssetHubKusamaAdapter, 101 | basilisk: BasiliskAdapter, 102 | polkadot: PolkadotAdapter, 103 | assetHubPolkadot: AssetHubPolkadotAdapter, 104 | moonbeam: MoonbeamAdapter, 105 | acala: AcalaAdapter, 106 | bifrost: BifrostAdapter, 107 | altair: AltairAdapter, 108 | shiden: ShidenAdapter, 109 | crust: ShadowAdapter, 110 | quartz: QuartzAdapter, 111 | unique: UniqueAdapter, 112 | astar: AstarAdapter, 113 | interlay: InterlayAdapter, 114 | kintsugi: KintsugiAdapter, 115 | khala: KhalaAdapter, 116 | crab: CrabAdapter, 117 | } as any 118 | const adapter = new adapters[chain]() 119 | await adapter.init(api) 120 | return adapter 121 | } 122 | 123 | async function chainBalance(sdk: any, fromData: any, address: string) { 124 | const fromChainBalance = (await sdk.findAdapter(from).getTokenBalance(token, alice.address)).free.toNumber() 125 | let tokenDecimals = fromData.decimals 126 | let toChainBalance 127 | if (to == 'moonriver') { 128 | const assetBalance = ( 129 | (await tochain.api.query.assets.account('10810581592933651521121702237638664357', address)) as any 130 | ).value.balance 131 | 132 | toChainBalance = 133 | (String(assetBalance) as any) !== 'undefined' ? assetBalance.toNumber() / 10 ** fromData.decimals : 0 134 | tokenDecimals = 18 135 | } else if (to == 'moonbeam') { 136 | const assetBalance = ( 137 | (await tochain.api.query.assets.account('110021739665376159354538090254163045594', address)) as any 138 | ).value.balance 139 | toChainBalance = 140 | (String(assetBalance) as any) !== 'undefined' ? assetBalance.toNumber() / 10 ** fromData.decimals : 0 141 | tokenDecimals = 18 142 | } else { 143 | toChainBalance = (await sdk.findAdapter(to).getTokenBalance(token, address)).free.toNumber() 144 | } 145 | 146 | return { address: address, fromChain: fromChainBalance, toChain: toChainBalance, decimals: tokenDecimals } 147 | } 148 | 149 | it('Cross-chain using BridgeSDK works', async () => { 150 | const fromChain = await chooseAdapter(from, fromchain.api) 151 | const toChain = await chooseAdapter(to, tochain.api) 152 | const sdk = new Bridge({ adapters: [fromChain as any, toChain as any] }) 153 | const fromAdapter = sdk.findAdapter(from as any) 154 | const fromData = fromAdapter.getToken(token, fromAdapter.chain.id) 155 | 156 | const amount = new FixedPointNumber(2, fromData.decimals) 157 | const address = 158 | to === 'moonriver' || to == 'moonbeam' ? '0x4E7440dB498561A46AAa82b9Bc7d2D5162b5c27B' : alice.address 159 | 160 | const chainBalanceInitial = await chainBalance(sdk, fromData, address) 161 | await check(chainBalanceInitial).toMatchSnapshot('initial') 162 | const tx = fromAdapter 163 | .createTx({ 164 | address: address, 165 | amount: amount, 166 | to: to as any, 167 | token: token, 168 | }) 169 | .signAsync(alice) 170 | 171 | await sendTransaction(tx as any) 172 | 173 | await fromchain.chain.newBlock() 174 | await tochain.chain.newBlock() 175 | 176 | await sleep(100) 177 | const chainBalanceNow = await chainBalance(sdk, fromData, address) 178 | await check(chainBalanceNow) 179 | .redact({ number: precision ?? 3 }) 180 | .toMatchSnapshot('after') 181 | 182 | //Verify if Destination Chain Transfer Fee matches the app 183 | expect(chainBalanceNow.fromChain).not.toEqual(chainBalanceInitial.fromChain) 184 | expect(chainBalanceNow.toChain).not.toEqual(chainBalanceInitial.toChain) 185 | 186 | if (!ignoreFee) { 187 | const fee = amount.toNumber() - (chainBalanceNow.toChain - chainBalanceInitial.toChain) 188 | await check(fee).redact({ number: 1 }).toMatchSnapshot('fee') 189 | } 190 | }, 300000) 191 | }) 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /tests/xcm-transfer/__snapshots__/kusama-para.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`'assetHubKusama' -> 'karura' xcm transfer 'USDT' > xcmPallet transfer > balance on from chain 1`] = ` 4 | { 5 | "balance": 999000000, 6 | "extra": null, 7 | "reason": { 8 | "consumer": null, 9 | }, 10 | "status": "Liquid", 11 | } 12 | `; 13 | 14 | exports[`'assetHubKusama' -> 'karura' xcm transfer 'USDT' > xcmPallet transfer > balance on to chain 1`] = ` 15 | { 16 | "free": "(rounded 999000)", 17 | "frozen": 0, 18 | "reserved": 0, 19 | } 20 | `; 21 | 22 | exports[`'assetHubKusama' -> 'karura' xcm transfer 'USDT' > xcmPallet transfer > from chain hrmp messages 1`] = ` 23 | [ 24 | { 25 | "data": [ 26 | "ConcatenatedVersionedXcm", 27 | { 28 | "v4": [ 29 | { 30 | "reserveAssetDeposited": [ 31 | { 32 | "fun": { 33 | "fungible": 1000000, 34 | }, 35 | "id": { 36 | "interior": { 37 | "x3": [ 38 | { 39 | "parachain": 1000, 40 | }, 41 | { 42 | "palletInstance": 50, 43 | }, 44 | { 45 | "generalIndex": 1984, 46 | }, 47 | ], 48 | }, 49 | "parents": 1, 50 | }, 51 | }, 52 | ], 53 | }, 54 | { 55 | "clearOrigin": null, 56 | }, 57 | { 58 | "buyExecution": { 59 | "fees": { 60 | "fun": { 61 | "fungible": 1000000, 62 | }, 63 | "id": { 64 | "interior": { 65 | "x3": [ 66 | { 67 | "parachain": 1000, 68 | }, 69 | { 70 | "palletInstance": 50, 71 | }, 72 | { 73 | "generalIndex": 1984, 74 | }, 75 | ], 76 | }, 77 | "parents": 1, 78 | }, 79 | }, 80 | "weightLimit": { 81 | "unlimited": null, 82 | }, 83 | }, 84 | }, 85 | { 86 | "depositAsset": { 87 | "assets": { 88 | "wild": { 89 | "allCounted": 1, 90 | }, 91 | }, 92 | "beneficiary": { 93 | "interior": { 94 | "x1": [ 95 | { 96 | "accountId32": { 97 | "id": "0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee", 98 | "network": null, 99 | }, 100 | }, 101 | ], 102 | }, 103 | "parents": 0, 104 | }, 105 | }, 106 | }, 107 | { 108 | "setTopic": "(redacted)", 109 | }, 110 | ], 111 | }, 112 | ], 113 | "recipient": 2000, 114 | }, 115 | ] 116 | `; 117 | 118 | exports[`'assetHubKusama' -> 'karura' xcm transfer 'USDT' > xcmPallet transfer > to chain xcm events 1`] = ` 119 | [ 120 | { 121 | "data": { 122 | "id": "(hash)", 123 | "origin": { 124 | "Sibling": 1000, 125 | }, 126 | "success": true, 127 | "weightUsed": { 128 | "proofSize": 0, 129 | "refTime": 1000000000, 130 | }, 131 | }, 132 | "method": "Processed", 133 | "section": "messageQueue", 134 | }, 135 | ] 136 | `; 137 | 138 | exports[`'assetHubKusama' -> 'karura' xcm transfer 'USDT' > xcmPallet transfer > tx events 1`] = ` 139 | [ 140 | { 141 | "data": { 142 | "outcome": { 143 | "Complete": { 144 | "used": { 145 | "proofSize": "(rounded 6200)", 146 | "refTime": "(rounded 300000000)", 147 | }, 148 | }, 149 | }, 150 | }, 151 | "method": "Attempted", 152 | "section": "polkadotXcm", 153 | }, 154 | { 155 | "data": { 156 | "fees": [ 157 | { 158 | "fun": { 159 | "Fungible": "(rounded 1040000000)", 160 | }, 161 | "id": { 162 | "interior": "Here", 163 | "parents": 1, 164 | }, 165 | }, 166 | ], 167 | "paying": { 168 | "interior": { 169 | "X1": [ 170 | { 171 | "AccountId32": { 172 | "id": "(hash)", 173 | "network": "Kusama", 174 | }, 175 | }, 176 | ], 177 | }, 178 | "parents": 0, 179 | }, 180 | }, 181 | "method": "FeesPaid", 182 | "section": "polkadotXcm", 183 | }, 184 | { 185 | "data": { 186 | "destination": { 187 | "interior": { 188 | "X1": [ 189 | { 190 | "Parachain": 2000, 191 | }, 192 | ], 193 | }, 194 | "parents": 1, 195 | }, 196 | "message": [ 197 | { 198 | "ReserveAssetDeposited": [ 199 | { 200 | "fun": { 201 | "Fungible": 1000000, 202 | }, 203 | "id": { 204 | "interior": { 205 | "X3": [ 206 | { 207 | "Parachain": 1000, 208 | }, 209 | { 210 | "PalletInstance": 50, 211 | }, 212 | { 213 | "GeneralIndex": "(rounded 1980)", 214 | }, 215 | ], 216 | }, 217 | "parents": 1, 218 | }, 219 | }, 220 | ], 221 | }, 222 | "ClearOrigin", 223 | { 224 | "BuyExecution": { 225 | "fees": { 226 | "fun": { 227 | "Fungible": 1000000, 228 | }, 229 | "id": { 230 | "interior": { 231 | "X3": [ 232 | { 233 | "Parachain": 1000, 234 | }, 235 | { 236 | "PalletInstance": 50, 237 | }, 238 | { 239 | "GeneralIndex": "(rounded 1980)", 240 | }, 241 | ], 242 | }, 243 | "parents": 1, 244 | }, 245 | }, 246 | "weightLimit": "Unlimited", 247 | }, 248 | }, 249 | { 250 | "DepositAsset": { 251 | "assets": { 252 | "Wild": { 253 | "AllCounted": 1, 254 | }, 255 | }, 256 | "beneficiary": { 257 | "interior": { 258 | "X1": [ 259 | { 260 | "AccountId32": { 261 | "id": "(hash)", 262 | "network": null, 263 | }, 264 | }, 265 | ], 266 | }, 267 | "parents": 0, 268 | }, 269 | }, 270 | }, 271 | ], 272 | "messageId": "(hash)", 273 | "origin": { 274 | "interior": { 275 | "X1": [ 276 | { 277 | "AccountId32": { 278 | "id": "(hash)", 279 | "network": "Kusama", 280 | }, 281 | }, 282 | ], 283 | }, 284 | "parents": 0, 285 | }, 286 | }, 287 | "method": "Sent", 288 | "section": "polkadotXcm", 289 | }, 290 | ] 291 | `; 292 | 293 | exports[`'karura' -> 'assetHubKusama' xcm transfer 'USDT' > xtokens transfer > balance on from chain 1`] = ` 294 | { 295 | "free": 9000000, 296 | "frozen": 0, 297 | "reserved": 0, 298 | } 299 | `; 300 | 301 | exports[`'karura' -> 'assetHubKusama' xcm transfer 'USDT' > xtokens transfer > balance on to chain 1`] = ` 302 | { 303 | "balance": "(rounded 1000000000)", 304 | "extra": null, 305 | "reason": { 306 | "consumer": null, 307 | }, 308 | "status": "Liquid", 309 | } 310 | `; 311 | 312 | exports[`'karura' -> 'assetHubKusama' xcm transfer 'USDT' > xtokens transfer > from chain hrmp messages 1`] = ` 313 | [ 314 | { 315 | "data": [ 316 | "ConcatenatedVersionedXcm", 317 | { 318 | "v4": [ 319 | { 320 | "withdrawAsset": [ 321 | { 322 | "fun": { 323 | "fungible": 1000000, 324 | }, 325 | "id": { 326 | "interior": { 327 | "x2": [ 328 | { 329 | "palletInstance": 50, 330 | }, 331 | { 332 | "generalIndex": 1984, 333 | }, 334 | ], 335 | }, 336 | "parents": 0, 337 | }, 338 | }, 339 | ], 340 | }, 341 | { 342 | "clearOrigin": null, 343 | }, 344 | { 345 | "buyExecution": { 346 | "fees": { 347 | "fun": { 348 | "fungible": 1000000, 349 | }, 350 | "id": { 351 | "interior": { 352 | "x2": [ 353 | { 354 | "palletInstance": 50, 355 | }, 356 | { 357 | "generalIndex": 1984, 358 | }, 359 | ], 360 | }, 361 | "parents": 0, 362 | }, 363 | }, 364 | "weightLimit": { 365 | "unlimited": null, 366 | }, 367 | }, 368 | }, 369 | { 370 | "depositAsset": { 371 | "assets": { 372 | "wild": { 373 | "allCounted": 1, 374 | }, 375 | }, 376 | "beneficiary": { 377 | "interior": { 378 | "x1": [ 379 | { 380 | "accountId32": { 381 | "id": "0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee", 382 | "network": null, 383 | }, 384 | }, 385 | ], 386 | }, 387 | "parents": 0, 388 | }, 389 | }, 390 | }, 391 | ], 392 | }, 393 | ], 394 | "recipient": 1000, 395 | }, 396 | ] 397 | `; 398 | 399 | exports[`'karura' -> 'assetHubKusama' xcm transfer 'USDT' > xtokens transfer > to chain xcm events 1`] = ` 400 | [ 401 | { 402 | "data": { 403 | "id": "(hash)", 404 | "origin": { 405 | "Sibling": 2000, 406 | }, 407 | "success": true, 408 | "weightUsed": { 409 | "proofSize": "(rounded 7200)", 410 | "refTime": "(rounded 320000000)", 411 | }, 412 | }, 413 | "method": "Processed", 414 | "section": "messageQueue", 415 | }, 416 | ] 417 | `; 418 | 419 | exports[`'karura' -> 'assetHubKusama' xcm transfer 'USDT' > xtokens transfer > tx events 1`] = ` 420 | [ 421 | { 422 | "data": { 423 | "assets": [ 424 | { 425 | "fun": { 426 | "Fungible": 1000000, 427 | }, 428 | "id": { 429 | "interior": { 430 | "X3": [ 431 | { 432 | "Parachain": 1000, 433 | }, 434 | { 435 | "PalletInstance": 50, 436 | }, 437 | { 438 | "GeneralIndex": "(rounded 2000)", 439 | }, 440 | ], 441 | }, 442 | "parents": 1, 443 | }, 444 | }, 445 | ], 446 | "dest": { 447 | "interior": { 448 | "X2": [ 449 | { 450 | "Parachain": 1000, 451 | }, 452 | { 453 | "AccountId32": { 454 | "id": "(hash)", 455 | "network": null, 456 | }, 457 | }, 458 | ], 459 | }, 460 | "parents": 1, 461 | }, 462 | "fee": { 463 | "fun": { 464 | "Fungible": 1000000, 465 | }, 466 | "id": { 467 | "interior": { 468 | "X3": [ 469 | { 470 | "Parachain": 1000, 471 | }, 472 | { 473 | "PalletInstance": 50, 474 | }, 475 | { 476 | "GeneralIndex": "(rounded 2000)", 477 | }, 478 | ], 479 | }, 480 | "parents": 1, 481 | }, 482 | }, 483 | "sender": "rPizfonc8MPuEsMxufAytHjpRW7a2YrXWHKibaJXe9ZtjKx", 484 | }, 485 | "method": "TransferredAssets", 486 | "section": "xTokens", 487 | }, 488 | ] 489 | `; 490 | 491 | exports[`'karura' -> 'basilisk' xcm transfer 'DAI' > xtokens transfer > balance on from chain 1`] = `99000000000000000000`; 492 | 493 | exports[`'karura' -> 'basilisk' xcm transfer 'DAI' > xtokens transfer > balance on to chain 1`] = ` 494 | { 495 | "free": "(rounded 101000000000000000000)", 496 | "frozen": 0, 497 | "reserved": 0, 498 | } 499 | `; 500 | 501 | exports[`'karura' -> 'basilisk' xcm transfer 'DAI' > xtokens transfer > from chain hrmp messages 1`] = ` 502 | [ 503 | { 504 | "data": [ 505 | "ConcatenatedVersionedXcm", 506 | { 507 | "v4": [ 508 | { 509 | "reserveAssetDeposited": [ 510 | { 511 | "fun": { 512 | "fungible": "0x00000000000000000de0b6b3a7640000", 513 | }, 514 | "id": { 515 | "interior": { 516 | "x2": [ 517 | { 518 | "parachain": 2000, 519 | }, 520 | { 521 | "generalKey": { 522 | "data": "0x024bb6afb5fa2b07a5d1c499e1c3ddb5a15e709a710000000000000000000000", 523 | "length": 21, 524 | }, 525 | }, 526 | ], 527 | }, 528 | "parents": 1, 529 | }, 530 | }, 531 | ], 532 | }, 533 | { 534 | "clearOrigin": null, 535 | }, 536 | { 537 | "buyExecution": { 538 | "fees": { 539 | "fun": { 540 | "fungible": "0x00000000000000000de0b6b3a7640000", 541 | }, 542 | "id": { 543 | "interior": { 544 | "x2": [ 545 | { 546 | "parachain": 2000, 547 | }, 548 | { 549 | "generalKey": { 550 | "data": "0x024bb6afb5fa2b07a5d1c499e1c3ddb5a15e709a710000000000000000000000", 551 | "length": 21, 552 | }, 553 | }, 554 | ], 555 | }, 556 | "parents": 1, 557 | }, 558 | }, 559 | "weightLimit": { 560 | "unlimited": null, 561 | }, 562 | }, 563 | }, 564 | { 565 | "depositAsset": { 566 | "assets": { 567 | "wild": { 568 | "allCounted": 1, 569 | }, 570 | }, 571 | "beneficiary": { 572 | "interior": { 573 | "x1": [ 574 | { 575 | "accountId32": { 576 | "id": "0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee", 577 | "network": null, 578 | }, 579 | }, 580 | ], 581 | }, 582 | "parents": 0, 583 | }, 584 | }, 585 | }, 586 | ], 587 | }, 588 | ], 589 | "recipient": 2090, 590 | }, 591 | ] 592 | `; 593 | 594 | exports[`'karura' -> 'basilisk' xcm transfer 'DAI' > xtokens transfer > to chain xcm events 1`] = ` 595 | [ 596 | { 597 | "data": { 598 | "id": "(hash)", 599 | "origin": { 600 | "Sibling": 2000, 601 | }, 602 | "success": true, 603 | "weightUsed": { 604 | "proofSize": 0, 605 | "refTime": 400000000, 606 | }, 607 | }, 608 | "method": "Processed", 609 | "section": "messageQueue", 610 | }, 611 | ] 612 | `; 613 | 614 | exports[`'karura' -> 'basilisk' xcm transfer 'DAI' > xtokens transfer > tx events 1`] = ` 615 | [ 616 | { 617 | "data": { 618 | "assets": [ 619 | { 620 | "fun": { 621 | "Fungible": 1000000000000000000, 622 | }, 623 | "id": { 624 | "interior": { 625 | "X2": [ 626 | { 627 | "Parachain": 2000, 628 | }, 629 | { 630 | "GeneralKey": { 631 | "data": "(hash)", 632 | "length": 21, 633 | }, 634 | }, 635 | ], 636 | }, 637 | "parents": 1, 638 | }, 639 | }, 640 | ], 641 | "dest": { 642 | "interior": { 643 | "X2": [ 644 | { 645 | "Parachain": "(rounded 2100)", 646 | }, 647 | { 648 | "AccountId32": { 649 | "id": "(hash)", 650 | "network": null, 651 | }, 652 | }, 653 | ], 654 | }, 655 | "parents": 1, 656 | }, 657 | "fee": { 658 | "fun": { 659 | "Fungible": 1000000000000000000, 660 | }, 661 | "id": { 662 | "interior": { 663 | "X2": [ 664 | { 665 | "Parachain": 2000, 666 | }, 667 | { 668 | "GeneralKey": { 669 | "data": "(hash)", 670 | "length": 21, 671 | }, 672 | }, 673 | ], 674 | }, 675 | "parents": 1, 676 | }, 677 | }, 678 | "sender": "rPizfonc8MPuEsMxufAytHjpRW7a2YrXWHKibaJXe9ZtjKx", 679 | }, 680 | "method": "TransferredAssets", 681 | "section": "xTokens", 682 | }, 683 | ] 684 | `; 685 | -------------------------------------------------------------------------------- /tests/xcm-transfer/__snapshots__/kusama-relay.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`'karura' -> 'kusama' xcm transfer 'KSM wiht limited weight' > xtokens transfer > balance on from chain 1`] = ` 4 | { 5 | "free": 9000000000000, 6 | "frozen": 0, 7 | "reserved": 0, 8 | } 9 | `; 10 | 11 | exports[`'karura' -> 'kusama' xcm transfer 'KSM wiht limited weight' > xtokens transfer > balance on to chain 1`] = ` 12 | { 13 | "consumers": 0, 14 | "data": { 15 | "flags": 0, 16 | "free": 10000000000000, 17 | "frozen": 0, 18 | "reserved": 0, 19 | }, 20 | "nonce": 0, 21 | "providers": 1, 22 | "sufficients": 0, 23 | } 24 | `; 25 | 26 | exports[`'karura' -> 'kusama' xcm transfer 'KSM wiht limited weight' > xtokens transfer > from chain ump messages 1`] = ` 27 | [ 28 | { 29 | "v4": [ 30 | { 31 | "withdrawAsset": [ 32 | { 33 | "fun": { 34 | "fungible": 1000000000000, 35 | }, 36 | "id": { 37 | "interior": { 38 | "here": null, 39 | }, 40 | "parents": 0, 41 | }, 42 | }, 43 | ], 44 | }, 45 | { 46 | "clearOrigin": null, 47 | }, 48 | { 49 | "buyExecution": { 50 | "fees": { 51 | "fun": { 52 | "fungible": 1000000000000, 53 | }, 54 | "id": { 55 | "interior": { 56 | "here": null, 57 | }, 58 | "parents": 0, 59 | }, 60 | }, 61 | "weightLimit": { 62 | "limited": { 63 | "proofSize": 0, 64 | "refTime": 5000000000, 65 | }, 66 | }, 67 | }, 68 | }, 69 | { 70 | "depositAsset": { 71 | "assets": { 72 | "wild": { 73 | "allCounted": 1, 74 | }, 75 | }, 76 | "beneficiary": { 77 | "interior": { 78 | "x1": [ 79 | { 80 | "accountId32": { 81 | "id": "0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee", 82 | "network": null, 83 | }, 84 | }, 85 | ], 86 | }, 87 | "parents": 0, 88 | }, 89 | }, 90 | }, 91 | ], 92 | }, 93 | ] 94 | `; 95 | 96 | exports[`'karura' -> 'kusama' xcm transfer 'KSM wiht limited weight' > xtokens transfer > to chain ump events 1`] = ` 97 | [ 98 | { 99 | "data": { 100 | "id": "(hash)", 101 | "origin": { 102 | "Ump": { 103 | "Para": 2000, 104 | }, 105 | }, 106 | "success": false, 107 | "weightUsed": { 108 | "proofSize": "(rounded 7200)", 109 | "refTime": "(rounded 320000000)", 110 | }, 111 | }, 112 | "method": "Processed", 113 | "section": "messageQueue", 114 | }, 115 | ] 116 | `; 117 | 118 | exports[`'karura' -> 'kusama' xcm transfer 'KSM wiht limited weight' > xtokens transfer > tx events 1`] = ` 119 | [ 120 | { 121 | "data": { 122 | "assets": [ 123 | { 124 | "fun": { 125 | "Fungible": 1000000000000, 126 | }, 127 | "id": { 128 | "interior": "Here", 129 | "parents": 1, 130 | }, 131 | }, 132 | ], 133 | "dest": { 134 | "interior": { 135 | "X1": [ 136 | { 137 | "AccountId32": { 138 | "id": "(hash)", 139 | "network": null, 140 | }, 141 | }, 142 | ], 143 | }, 144 | "parents": 1, 145 | }, 146 | "fee": { 147 | "fun": { 148 | "Fungible": 1000000000000, 149 | }, 150 | "id": { 151 | "interior": "Here", 152 | "parents": 1, 153 | }, 154 | }, 155 | "sender": "rPizfonc8MPuEsMxufAytHjpRW7a2YrXWHKibaJXe9ZtjKx", 156 | }, 157 | "method": "TransferredAssets", 158 | "section": "xTokens", 159 | }, 160 | ] 161 | `; 162 | 163 | exports[`'karura' -> 'kusama' xcm transfer 'KSM' > xtokens transfer > balance on from chain 1`] = ` 164 | { 165 | "free": 9000000000000, 166 | "frozen": 0, 167 | "reserved": 0, 168 | } 169 | `; 170 | 171 | exports[`'karura' -> 'kusama' xcm transfer 'KSM' > xtokens transfer > balance on to chain 1`] = ` 172 | { 173 | "consumers": 0, 174 | "data": { 175 | "flags": "0x80000000000000000000000000000000", 176 | "free": "(rounded 11000000000000)", 177 | "frozen": 0, 178 | "reserved": 0, 179 | }, 180 | "nonce": 0, 181 | "providers": 1, 182 | "sufficients": 0, 183 | } 184 | `; 185 | 186 | exports[`'karura' -> 'kusama' xcm transfer 'KSM' > xtokens transfer > from chain ump messages 1`] = ` 187 | [ 188 | { 189 | "v4": [ 190 | { 191 | "withdrawAsset": [ 192 | { 193 | "fun": { 194 | "fungible": 1000000000000, 195 | }, 196 | "id": { 197 | "interior": { 198 | "here": null, 199 | }, 200 | "parents": 0, 201 | }, 202 | }, 203 | ], 204 | }, 205 | { 206 | "clearOrigin": null, 207 | }, 208 | { 209 | "buyExecution": { 210 | "fees": { 211 | "fun": { 212 | "fungible": 1000000000000, 213 | }, 214 | "id": { 215 | "interior": { 216 | "here": null, 217 | }, 218 | "parents": 0, 219 | }, 220 | }, 221 | "weightLimit": { 222 | "unlimited": null, 223 | }, 224 | }, 225 | }, 226 | { 227 | "depositAsset": { 228 | "assets": { 229 | "wild": { 230 | "allCounted": 1, 231 | }, 232 | }, 233 | "beneficiary": { 234 | "interior": { 235 | "x1": [ 236 | { 237 | "accountId32": { 238 | "id": "0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee", 239 | "network": null, 240 | }, 241 | }, 242 | ], 243 | }, 244 | "parents": 0, 245 | }, 246 | }, 247 | }, 248 | ], 249 | }, 250 | ] 251 | `; 252 | 253 | exports[`'karura' -> 'kusama' xcm transfer 'KSM' > xtokens transfer > to chain ump events 1`] = ` 254 | [ 255 | { 256 | "data": { 257 | "id": "(hash)", 258 | "origin": { 259 | "Ump": { 260 | "Para": 2000, 261 | }, 262 | }, 263 | "success": true, 264 | "weightUsed": { 265 | "proofSize": "(rounded 7200)", 266 | "refTime": "(rounded 320000000)", 267 | }, 268 | }, 269 | "method": "Processed", 270 | "section": "messageQueue", 271 | }, 272 | ] 273 | `; 274 | 275 | exports[`'karura' -> 'kusama' xcm transfer 'KSM' > xtokens transfer > tx events 1`] = ` 276 | [ 277 | { 278 | "data": { 279 | "assets": [ 280 | { 281 | "fun": { 282 | "Fungible": 1000000000000, 283 | }, 284 | "id": { 285 | "interior": "Here", 286 | "parents": 1, 287 | }, 288 | }, 289 | ], 290 | "dest": { 291 | "interior": { 292 | "X1": [ 293 | { 294 | "AccountId32": { 295 | "id": "(hash)", 296 | "network": null, 297 | }, 298 | }, 299 | ], 300 | }, 301 | "parents": 1, 302 | }, 303 | "fee": { 304 | "fun": { 305 | "Fungible": 1000000000000, 306 | }, 307 | "id": { 308 | "interior": "Here", 309 | "parents": 1, 310 | }, 311 | }, 312 | "sender": "rPizfonc8MPuEsMxufAytHjpRW7a2YrXWHKibaJXe9ZtjKx", 313 | }, 314 | "method": "TransferredAssets", 315 | "section": "xTokens", 316 | }, 317 | ] 318 | `; 319 | 320 | exports[`'kusama' -> 'karura' xcm transfer 'KSM' > xcmPallet transfer > balance on from chain 1`] = ` 321 | { 322 | "consumers": 0, 323 | "data": { 324 | "flags": "0x80000000000000000000000000000000", 325 | "free": "(rounded 9000000000000)", 326 | "frozen": 0, 327 | "reserved": 0, 328 | }, 329 | "nonce": 1, 330 | "providers": 1, 331 | "sufficients": 0, 332 | } 333 | `; 334 | 335 | exports[`'kusama' -> 'karura' xcm transfer 'KSM' > xcmPallet transfer > balance on to chain 1`] = ` 336 | { 337 | "free": "(rounded 11000000000000)", 338 | "frozen": 0, 339 | "reserved": 0, 340 | } 341 | `; 342 | 343 | exports[`'kusama' -> 'karura' xcm transfer 'KSM' > xcmPallet transfer > to chain dmp events 1`] = ` 344 | [ 345 | { 346 | "data": { 347 | "count": 1, 348 | }, 349 | "method": "DownwardMessagesReceived", 350 | "section": "parachainSystem", 351 | }, 352 | { 353 | "data": { 354 | "dmqHead": "(hash)", 355 | "weightUsed": { 356 | "proofSize": "(rounded 8000)", 357 | "refTime": "(rounded 530000000)", 358 | }, 359 | }, 360 | "method": "DownwardMessagesProcessed", 361 | "section": "parachainSystem", 362 | }, 363 | { 364 | "data": { 365 | "id": "(hash)", 366 | "origin": "Parent", 367 | "success": true, 368 | "weightUsed": { 369 | "proofSize": 0, 370 | "refTime": 1000000000, 371 | }, 372 | }, 373 | "method": "Processed", 374 | "section": "messageQueue", 375 | }, 376 | ] 377 | `; 378 | 379 | exports[`'kusama' -> 'karura' xcm transfer 'KSM' > xcmPallet transfer > tx events 1`] = ` 380 | [ 381 | { 382 | "data": { 383 | "outcome": { 384 | "Complete": { 385 | "used": { 386 | "proofSize": "(rounded 6200)", 387 | "refTime": "(rounded 304000000)", 388 | }, 389 | }, 390 | }, 391 | }, 392 | "method": "Attempted", 393 | "section": "xcmPallet", 394 | }, 395 | { 396 | "data": { 397 | "fees": [ 398 | { 399 | "fun": { 400 | "Fungible": "(rounded 1320000000)", 401 | }, 402 | "id": { 403 | "interior": "Here", 404 | "parents": 0, 405 | }, 406 | }, 407 | ], 408 | "paying": { 409 | "interior": { 410 | "X1": [ 411 | { 412 | "AccountId32": { 413 | "id": "(hash)", 414 | "network": "Kusama", 415 | }, 416 | }, 417 | ], 418 | }, 419 | "parents": 0, 420 | }, 421 | }, 422 | "method": "FeesPaid", 423 | "section": "xcmPallet", 424 | }, 425 | { 426 | "data": { 427 | "destination": { 428 | "interior": { 429 | "X1": [ 430 | { 431 | "Parachain": 2000, 432 | }, 433 | ], 434 | }, 435 | "parents": 0, 436 | }, 437 | "message": [ 438 | { 439 | "ReserveAssetDeposited": [ 440 | { 441 | "fun": { 442 | "Fungible": 1000000000000, 443 | }, 444 | "id": { 445 | "interior": "Here", 446 | "parents": 1, 447 | }, 448 | }, 449 | ], 450 | }, 451 | "ClearOrigin", 452 | { 453 | "BuyExecution": { 454 | "fees": { 455 | "fun": { 456 | "Fungible": 1000000000000, 457 | }, 458 | "id": { 459 | "interior": "Here", 460 | "parents": 1, 461 | }, 462 | }, 463 | "weightLimit": "Unlimited", 464 | }, 465 | }, 466 | { 467 | "DepositAsset": { 468 | "assets": { 469 | "Wild": { 470 | "AllCounted": 1, 471 | }, 472 | }, 473 | "beneficiary": { 474 | "interior": { 475 | "X1": [ 476 | { 477 | "AccountId32": { 478 | "id": "(hash)", 479 | "network": null, 480 | }, 481 | }, 482 | ], 483 | }, 484 | "parents": 0, 485 | }, 486 | }, 487 | }, 488 | ], 489 | "messageId": "(hash)", 490 | "origin": { 491 | "interior": { 492 | "X1": [ 493 | { 494 | "AccountId32": { 495 | "id": "(hash)", 496 | "network": "Kusama", 497 | }, 498 | }, 499 | ], 500 | }, 501 | "parents": 0, 502 | }, 503 | }, 504 | "method": "Sent", 505 | "section": "xcmPallet", 506 | }, 507 | ] 508 | `; 509 | 510 | exports[`'kusama' -> 'shiden' xcm transfer 'KSM' > xcmPallet transfer > balance on from chain 1`] = ` 511 | { 512 | "consumers": 0, 513 | "data": { 514 | "flags": "0x80000000000000000000000000000000", 515 | "free": "(rounded 9000000000000)", 516 | "frozen": 0, 517 | "reserved": 0, 518 | }, 519 | "nonce": 1, 520 | "providers": 1, 521 | "sufficients": 0, 522 | } 523 | `; 524 | 525 | exports[`'kusama' -> 'shiden' xcm transfer 'KSM' > xcmPallet transfer > balance on to chain 1`] = ` 526 | { 527 | "balance": "(rounded 11000000000000)", 528 | "extra": null, 529 | "reason": { 530 | "consumer": null, 531 | }, 532 | "status": "Liquid", 533 | } 534 | `; 535 | 536 | exports[`'kusama' -> 'shiden' xcm transfer 'KSM' > xcmPallet transfer > to chain dmp events 1`] = ` 537 | [ 538 | { 539 | "data": { 540 | "count": 1, 541 | }, 542 | "method": "DownwardMessagesReceived", 543 | "section": "parachainSystem", 544 | }, 545 | { 546 | "data": { 547 | "dmqHead": "(hash)", 548 | "weightUsed": { 549 | "proofSize": "(rounded 8000)", 550 | "refTime": "(rounded 530000000)", 551 | }, 552 | }, 553 | "method": "DownwardMessagesProcessed", 554 | "section": "parachainSystem", 555 | }, 556 | { 557 | "data": { 558 | "id": "(hash)", 559 | "origin": "Parent", 560 | "success": true, 561 | "weightUsed": { 562 | "proofSize": "(rounded 9300)", 563 | "refTime": "(rounded 900000000)", 564 | }, 565 | }, 566 | "method": "Processed", 567 | "section": "messageQueue", 568 | }, 569 | ] 570 | `; 571 | 572 | exports[`'kusama' -> 'shiden' xcm transfer 'KSM' > xcmPallet transfer > tx events 1`] = ` 573 | [ 574 | { 575 | "data": { 576 | "outcome": { 577 | "Complete": { 578 | "used": { 579 | "proofSize": "(rounded 6200)", 580 | "refTime": "(rounded 304000000)", 581 | }, 582 | }, 583 | }, 584 | }, 585 | "method": "Attempted", 586 | "section": "xcmPallet", 587 | }, 588 | { 589 | "data": { 590 | "fees": [ 591 | { 592 | "fun": { 593 | "Fungible": "(rounded 1320000000)", 594 | }, 595 | "id": { 596 | "interior": "Here", 597 | "parents": 0, 598 | }, 599 | }, 600 | ], 601 | "paying": { 602 | "interior": { 603 | "X1": [ 604 | { 605 | "AccountId32": { 606 | "id": "(hash)", 607 | "network": "Kusama", 608 | }, 609 | }, 610 | ], 611 | }, 612 | "parents": 0, 613 | }, 614 | }, 615 | "method": "FeesPaid", 616 | "section": "xcmPallet", 617 | }, 618 | { 619 | "data": { 620 | "destination": { 621 | "interior": { 622 | "X1": [ 623 | { 624 | "Parachain": "(rounded 2010)", 625 | }, 626 | ], 627 | }, 628 | "parents": 0, 629 | }, 630 | "message": [ 631 | { 632 | "ReserveAssetDeposited": [ 633 | { 634 | "fun": { 635 | "Fungible": 1000000000000, 636 | }, 637 | "id": { 638 | "interior": "Here", 639 | "parents": 1, 640 | }, 641 | }, 642 | ], 643 | }, 644 | "ClearOrigin", 645 | { 646 | "BuyExecution": { 647 | "fees": { 648 | "fun": { 649 | "Fungible": 1000000000000, 650 | }, 651 | "id": { 652 | "interior": "Here", 653 | "parents": 1, 654 | }, 655 | }, 656 | "weightLimit": "Unlimited", 657 | }, 658 | }, 659 | { 660 | "DepositAsset": { 661 | "assets": { 662 | "Wild": { 663 | "AllCounted": 1, 664 | }, 665 | }, 666 | "beneficiary": { 667 | "interior": { 668 | "X1": [ 669 | { 670 | "AccountId32": { 671 | "id": "(hash)", 672 | "network": null, 673 | }, 674 | }, 675 | ], 676 | }, 677 | "parents": 0, 678 | }, 679 | }, 680 | }, 681 | ], 682 | "messageId": "(hash)", 683 | "origin": { 684 | "interior": { 685 | "X1": [ 686 | { 687 | "AccountId32": { 688 | "id": "(hash)", 689 | "network": "Kusama", 690 | }, 691 | }, 692 | ], 693 | }, 694 | "parents": 0, 695 | }, 696 | }, 697 | "method": "Sent", 698 | "section": "xcmPallet", 699 | }, 700 | ] 701 | `; 702 | -------------------------------------------------------------------------------- /tests/xcm-transfer/__snapshots__/polkadot-para.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`'acala' -> 'assetHubPolkadot' xcm transfer 'WBTC' > xtokens transfer > balance on from chain 1`] = ` 4 | { 5 | "free": 90000000, 6 | "frozen": 0, 7 | "reserved": 0, 8 | } 9 | `; 10 | 11 | exports[`'acala' -> 'assetHubPolkadot' xcm transfer 'WBTC' > xtokens transfer > balance on to chain 1`] = ` 12 | { 13 | "balance": 1000000000, 14 | "extra": null, 15 | "reason": { 16 | "consumer": null, 17 | }, 18 | "status": "Liquid", 19 | } 20 | `; 21 | 22 | exports[`'acala' -> 'assetHubPolkadot' xcm transfer 'WBTC' > xtokens transfer > from chain hrmp messages 1`] = ` 23 | [ 24 | { 25 | "data": [ 26 | "ConcatenatedVersionedXcm", 27 | { 28 | "v4": [ 29 | { 30 | "withdrawAsset": [ 31 | { 32 | "fun": { 33 | "fungible": 10000000, 34 | }, 35 | "id": { 36 | "interior": { 37 | "x2": [ 38 | { 39 | "palletInstance": 50, 40 | }, 41 | { 42 | "generalIndex": 21, 43 | }, 44 | ], 45 | }, 46 | "parents": 0, 47 | }, 48 | }, 49 | { 50 | "fun": { 51 | "fungible": 150000000, 52 | }, 53 | "id": { 54 | "interior": { 55 | "here": null, 56 | }, 57 | "parents": 1, 58 | }, 59 | }, 60 | ], 61 | }, 62 | { 63 | "clearOrigin": null, 64 | }, 65 | { 66 | "buyExecution": { 67 | "fees": { 68 | "fun": { 69 | "fungible": 150000000, 70 | }, 71 | "id": { 72 | "interior": { 73 | "here": null, 74 | }, 75 | "parents": 1, 76 | }, 77 | }, 78 | "weightLimit": { 79 | "unlimited": null, 80 | }, 81 | }, 82 | }, 83 | { 84 | "depositAsset": { 85 | "assets": { 86 | "wild": { 87 | "allCounted": 2, 88 | }, 89 | }, 90 | "beneficiary": { 91 | "interior": { 92 | "x1": [ 93 | { 94 | "accountId32": { 95 | "id": "0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee", 96 | "network": null, 97 | }, 98 | }, 99 | ], 100 | }, 101 | "parents": 0, 102 | }, 103 | }, 104 | }, 105 | ], 106 | }, 107 | ], 108 | "recipient": 1000, 109 | }, 110 | ] 111 | `; 112 | 113 | exports[`'acala' -> 'assetHubPolkadot' xcm transfer 'WBTC' > xtokens transfer > to chain xcm events 1`] = ` 114 | [ 115 | { 116 | "data": { 117 | "id": "(hash)", 118 | "origin": "Parent", 119 | "success": true, 120 | "weightUsed": { 121 | "proofSize": "(rounded 3600)", 122 | "refTime": "(rounded 160000000)", 123 | }, 124 | }, 125 | "method": "Processed", 126 | "section": "messageQueue", 127 | }, 128 | { 129 | "data": { 130 | "id": "(hash)", 131 | "origin": { 132 | "Sibling": 2000, 133 | }, 134 | "success": false, 135 | "weightUsed": { 136 | "proofSize": "(rounded 7200)", 137 | "refTime": "(rounded 330000000)", 138 | }, 139 | }, 140 | "method": "Processed", 141 | "section": "messageQueue", 142 | }, 143 | ] 144 | `; 145 | 146 | exports[`'acala' -> 'assetHubPolkadot' xcm transfer 'WBTC' > xtokens transfer > tx events 1`] = ` 147 | [ 148 | { 149 | "data": { 150 | "assets": [ 151 | { 152 | "fun": { 153 | "Fungible": 16000000000, 154 | }, 155 | "id": { 156 | "interior": "Here", 157 | "parents": 1, 158 | }, 159 | }, 160 | { 161 | "fun": { 162 | "Fungible": 10000000, 163 | }, 164 | "id": { 165 | "interior": { 166 | "X3": [ 167 | { 168 | "Parachain": 1000, 169 | }, 170 | { 171 | "PalletInstance": 50, 172 | }, 173 | { 174 | "GeneralIndex": 21, 175 | }, 176 | ], 177 | }, 178 | "parents": 1, 179 | }, 180 | }, 181 | ], 182 | "dest": { 183 | "interior": { 184 | "X2": [ 185 | { 186 | "Parachain": 1000, 187 | }, 188 | { 189 | "AccountId32": { 190 | "id": "(hash)", 191 | "network": null, 192 | }, 193 | }, 194 | ], 195 | }, 196 | "parents": 1, 197 | }, 198 | "fee": { 199 | "fun": { 200 | "Fungible": 16000000000, 201 | }, 202 | "id": { 203 | "interior": "Here", 204 | "parents": 1, 205 | }, 206 | }, 207 | "sender": "23y3WetbNi6rDMgHmyRDjgpb7PnhgPotuPPawxruTMLYTLzG", 208 | }, 209 | "method": "TransferredAssets", 210 | "section": "xTokens", 211 | }, 212 | ] 213 | `; 214 | 215 | exports[`'assetHubPolkadot' -> 'acala' xcm transfer 'WBTC' > xcmPallet transfer > balance on from chain 1`] = ` 216 | { 217 | "balance": 90000000, 218 | "extra": null, 219 | "reason": { 220 | "consumer": null, 221 | }, 222 | "status": "Liquid", 223 | } 224 | `; 225 | 226 | exports[`'assetHubPolkadot' -> 'acala' xcm transfer 'WBTC' > xcmPallet transfer > balance on to chain 1`] = ` 227 | { 228 | "free": "(rounded 10000000)", 229 | "frozen": 0, 230 | "reserved": 0, 231 | } 232 | `; 233 | 234 | exports[`'assetHubPolkadot' -> 'acala' xcm transfer 'WBTC' > xcmPallet transfer > from chain hrmp messages 1`] = ` 235 | [ 236 | { 237 | "data": [ 238 | "ConcatenatedVersionedXcm", 239 | { 240 | "v4": [ 241 | { 242 | "reserveAssetDeposited": [ 243 | { 244 | "fun": { 245 | "fungible": 10000000, 246 | }, 247 | "id": { 248 | "interior": { 249 | "x3": [ 250 | { 251 | "parachain": 1000, 252 | }, 253 | { 254 | "palletInstance": 50, 255 | }, 256 | { 257 | "generalIndex": 21, 258 | }, 259 | ], 260 | }, 261 | "parents": 1, 262 | }, 263 | }, 264 | ], 265 | }, 266 | { 267 | "clearOrigin": null, 268 | }, 269 | { 270 | "buyExecution": { 271 | "fees": { 272 | "fun": { 273 | "fungible": 10000000, 274 | }, 275 | "id": { 276 | "interior": { 277 | "x3": [ 278 | { 279 | "parachain": 1000, 280 | }, 281 | { 282 | "palletInstance": 50, 283 | }, 284 | { 285 | "generalIndex": 21, 286 | }, 287 | ], 288 | }, 289 | "parents": 1, 290 | }, 291 | }, 292 | "weightLimit": { 293 | "unlimited": null, 294 | }, 295 | }, 296 | }, 297 | { 298 | "depositAsset": { 299 | "assets": { 300 | "wild": { 301 | "allCounted": 1, 302 | }, 303 | }, 304 | "beneficiary": { 305 | "interior": { 306 | "x1": [ 307 | { 308 | "accountId32": { 309 | "id": "0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee", 310 | "network": null, 311 | }, 312 | }, 313 | ], 314 | }, 315 | "parents": 0, 316 | }, 317 | }, 318 | }, 319 | { 320 | "setTopic": "(redacted)", 321 | }, 322 | ], 323 | }, 324 | ], 325 | "recipient": 2000, 326 | }, 327 | ] 328 | `; 329 | 330 | exports[`'assetHubPolkadot' -> 'acala' xcm transfer 'WBTC' > xcmPallet transfer > to chain xcm events 1`] = ` 331 | [ 332 | { 333 | "data": { 334 | "id": "(hash)", 335 | "origin": { 336 | "Sibling": 1000, 337 | }, 338 | "success": true, 339 | "weightUsed": { 340 | "proofSize": 0, 341 | "refTime": 1000000000, 342 | }, 343 | }, 344 | "method": "Processed", 345 | "section": "messageQueue", 346 | }, 347 | ] 348 | `; 349 | 350 | exports[`'assetHubPolkadot' -> 'acala' xcm transfer 'WBTC' > xcmPallet transfer > tx events 1`] = ` 351 | [ 352 | { 353 | "data": { 354 | "outcome": { 355 | "Complete": { 356 | "used": { 357 | "proofSize": "(rounded 6200)", 358 | "refTime": "(rounded 305000000)", 359 | }, 360 | }, 361 | }, 362 | }, 363 | "method": "Attempted", 364 | "section": "polkadotXcm", 365 | }, 366 | { 367 | "data": { 368 | "fees": [ 369 | { 370 | "fun": { 371 | "Fungible": "(rounded 305000000)", 372 | }, 373 | "id": { 374 | "interior": "Here", 375 | "parents": 1, 376 | }, 377 | }, 378 | ], 379 | "paying": { 380 | "interior": { 381 | "X1": [ 382 | { 383 | "AccountId32": { 384 | "id": "(hash)", 385 | "network": "Polkadot", 386 | }, 387 | }, 388 | ], 389 | }, 390 | "parents": 0, 391 | }, 392 | }, 393 | "method": "FeesPaid", 394 | "section": "polkadotXcm", 395 | }, 396 | { 397 | "data": { 398 | "destination": { 399 | "interior": { 400 | "X1": [ 401 | { 402 | "Parachain": 2000, 403 | }, 404 | ], 405 | }, 406 | "parents": 1, 407 | }, 408 | "message": [ 409 | { 410 | "ReserveAssetDeposited": [ 411 | { 412 | "fun": { 413 | "Fungible": 10000000, 414 | }, 415 | "id": { 416 | "interior": { 417 | "X3": [ 418 | { 419 | "Parachain": 1000, 420 | }, 421 | { 422 | "PalletInstance": 50, 423 | }, 424 | { 425 | "GeneralIndex": 21, 426 | }, 427 | ], 428 | }, 429 | "parents": 1, 430 | }, 431 | }, 432 | ], 433 | }, 434 | "ClearOrigin", 435 | { 436 | "BuyExecution": { 437 | "fees": { 438 | "fun": { 439 | "Fungible": 10000000, 440 | }, 441 | "id": { 442 | "interior": { 443 | "X3": [ 444 | { 445 | "Parachain": 1000, 446 | }, 447 | { 448 | "PalletInstance": 50, 449 | }, 450 | { 451 | "GeneralIndex": 21, 452 | }, 453 | ], 454 | }, 455 | "parents": 1, 456 | }, 457 | }, 458 | "weightLimit": "Unlimited", 459 | }, 460 | }, 461 | { 462 | "DepositAsset": { 463 | "assets": { 464 | "Wild": { 465 | "AllCounted": 1, 466 | }, 467 | }, 468 | "beneficiary": { 469 | "interior": { 470 | "X1": [ 471 | { 472 | "AccountId32": { 473 | "id": "(hash)", 474 | "network": null, 475 | }, 476 | }, 477 | ], 478 | }, 479 | "parents": 0, 480 | }, 481 | }, 482 | }, 483 | ], 484 | "messageId": "(hash)", 485 | "origin": { 486 | "interior": { 487 | "X1": [ 488 | { 489 | "AccountId32": { 490 | "id": "(hash)", 491 | "network": "Polkadot", 492 | }, 493 | }, 494 | ], 495 | }, 496 | "parents": 0, 497 | }, 498 | }, 499 | "method": "Sent", 500 | "section": "polkadotXcm", 501 | }, 502 | ] 503 | `; 504 | -------------------------------------------------------------------------------- /tests/xcm-transfer/__snapshots__/polkadot-relay.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`'acala' -> 'polkadot' xcm transfer 'DOT wiht limited weight' > xtokens transfer > balance on from chain 1`] = ` 4 | { 5 | "free": 9000000000000, 6 | "frozen": 0, 7 | "reserved": 0, 8 | } 9 | `; 10 | 11 | exports[`'acala' -> 'polkadot' xcm transfer 'DOT wiht limited weight' > xtokens transfer > balance on to chain 1`] = ` 12 | { 13 | "consumers": 0, 14 | "data": { 15 | "flags": 0, 16 | "free": 10000000000000, 17 | "frozen": 0, 18 | "reserved": 0, 19 | }, 20 | "nonce": 0, 21 | "providers": 1, 22 | "sufficients": 0, 23 | } 24 | `; 25 | 26 | exports[`'acala' -> 'polkadot' xcm transfer 'DOT wiht limited weight' > xtokens transfer > from chain ump messages 1`] = ` 27 | [ 28 | { 29 | "v4": [ 30 | { 31 | "withdrawAsset": [ 32 | { 33 | "fun": { 34 | "fungible": 1000000000000, 35 | }, 36 | "id": { 37 | "interior": { 38 | "here": null, 39 | }, 40 | "parents": 0, 41 | }, 42 | }, 43 | ], 44 | }, 45 | { 46 | "clearOrigin": null, 47 | }, 48 | { 49 | "buyExecution": { 50 | "fees": { 51 | "fun": { 52 | "fungible": 1000000000000, 53 | }, 54 | "id": { 55 | "interior": { 56 | "here": null, 57 | }, 58 | "parents": 0, 59 | }, 60 | }, 61 | "weightLimit": { 62 | "limited": { 63 | "proofSize": 0, 64 | "refTime": 5000000000, 65 | }, 66 | }, 67 | }, 68 | }, 69 | { 70 | "depositAsset": { 71 | "assets": { 72 | "wild": { 73 | "allCounted": 1, 74 | }, 75 | }, 76 | "beneficiary": { 77 | "interior": { 78 | "x1": [ 79 | { 80 | "accountId32": { 81 | "id": "0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee", 82 | "network": null, 83 | }, 84 | }, 85 | ], 86 | }, 87 | "parents": 0, 88 | }, 89 | }, 90 | }, 91 | ], 92 | }, 93 | ] 94 | `; 95 | 96 | exports[`'acala' -> 'polkadot' xcm transfer 'DOT wiht limited weight' > xtokens transfer > to chain ump events 1`] = ` 97 | [ 98 | { 99 | "data": { 100 | "id": "(hash)", 101 | "origin": { 102 | "Ump": { 103 | "Para": 2000, 104 | }, 105 | }, 106 | "success": false, 107 | "weightUsed": { 108 | "proofSize": "(rounded 7200)", 109 | "refTime": "(rounded 280000000)", 110 | }, 111 | }, 112 | "method": "Processed", 113 | "section": "messageQueue", 114 | }, 115 | ] 116 | `; 117 | 118 | exports[`'acala' -> 'polkadot' xcm transfer 'DOT wiht limited weight' > xtokens transfer > tx events 1`] = ` 119 | [ 120 | { 121 | "data": { 122 | "assets": [ 123 | { 124 | "fun": { 125 | "Fungible": 1000000000000, 126 | }, 127 | "id": { 128 | "interior": "Here", 129 | "parents": 1, 130 | }, 131 | }, 132 | ], 133 | "dest": { 134 | "interior": { 135 | "X1": [ 136 | { 137 | "AccountId32": { 138 | "id": "(hash)", 139 | "network": null, 140 | }, 141 | }, 142 | ], 143 | }, 144 | "parents": 1, 145 | }, 146 | "fee": { 147 | "fun": { 148 | "Fungible": 1000000000000, 149 | }, 150 | "id": { 151 | "interior": "Here", 152 | "parents": 1, 153 | }, 154 | }, 155 | "sender": "23y3WetbNi6rDMgHmyRDjgpb7PnhgPotuPPawxruTMLYTLzG", 156 | }, 157 | "method": "TransferredAssets", 158 | "section": "xTokens", 159 | }, 160 | ] 161 | `; 162 | 163 | exports[`'acala' -> 'polkadot' xcm transfer 'DOT' > xtokens transfer > balance on from chain 1`] = ` 164 | { 165 | "free": 9000000000000, 166 | "frozen": 0, 167 | "reserved": 0, 168 | } 169 | `; 170 | 171 | exports[`'acala' -> 'polkadot' xcm transfer 'DOT' > xtokens transfer > balance on to chain 1`] = ` 172 | { 173 | "consumers": 0, 174 | "data": { 175 | "flags": "0x80000000000000000000000000000000", 176 | "free": "(rounded 11000000000000)", 177 | "frozen": 0, 178 | "reserved": 0, 179 | }, 180 | "nonce": 0, 181 | "providers": 1, 182 | "sufficients": 0, 183 | } 184 | `; 185 | 186 | exports[`'acala' -> 'polkadot' xcm transfer 'DOT' > xtokens transfer > from chain ump messages 1`] = ` 187 | [ 188 | { 189 | "v4": [ 190 | { 191 | "withdrawAsset": [ 192 | { 193 | "fun": { 194 | "fungible": 1000000000000, 195 | }, 196 | "id": { 197 | "interior": { 198 | "here": null, 199 | }, 200 | "parents": 0, 201 | }, 202 | }, 203 | ], 204 | }, 205 | { 206 | "clearOrigin": null, 207 | }, 208 | { 209 | "buyExecution": { 210 | "fees": { 211 | "fun": { 212 | "fungible": 1000000000000, 213 | }, 214 | "id": { 215 | "interior": { 216 | "here": null, 217 | }, 218 | "parents": 0, 219 | }, 220 | }, 221 | "weightLimit": { 222 | "unlimited": null, 223 | }, 224 | }, 225 | }, 226 | { 227 | "depositAsset": { 228 | "assets": { 229 | "wild": { 230 | "allCounted": 1, 231 | }, 232 | }, 233 | "beneficiary": { 234 | "interior": { 235 | "x1": [ 236 | { 237 | "accountId32": { 238 | "id": "0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee", 239 | "network": null, 240 | }, 241 | }, 242 | ], 243 | }, 244 | "parents": 0, 245 | }, 246 | }, 247 | }, 248 | ], 249 | }, 250 | ] 251 | `; 252 | 253 | exports[`'acala' -> 'polkadot' xcm transfer 'DOT' > xtokens transfer > to chain ump events 1`] = ` 254 | [ 255 | { 256 | "data": { 257 | "id": "(hash)", 258 | "origin": { 259 | "Ump": { 260 | "Para": 2000, 261 | }, 262 | }, 263 | "success": true, 264 | "weightUsed": { 265 | "proofSize": "(rounded 7200)", 266 | "refTime": "(rounded 280000000)", 267 | }, 268 | }, 269 | "method": "Processed", 270 | "section": "messageQueue", 271 | }, 272 | ] 273 | `; 274 | 275 | exports[`'acala' -> 'polkadot' xcm transfer 'DOT' > xtokens transfer > tx events 1`] = ` 276 | [ 277 | { 278 | "data": { 279 | "assets": [ 280 | { 281 | "fun": { 282 | "Fungible": 1000000000000, 283 | }, 284 | "id": { 285 | "interior": "Here", 286 | "parents": 1, 287 | }, 288 | }, 289 | ], 290 | "dest": { 291 | "interior": { 292 | "X1": [ 293 | { 294 | "AccountId32": { 295 | "id": "(hash)", 296 | "network": null, 297 | }, 298 | }, 299 | ], 300 | }, 301 | "parents": 1, 302 | }, 303 | "fee": { 304 | "fun": { 305 | "Fungible": 1000000000000, 306 | }, 307 | "id": { 308 | "interior": "Here", 309 | "parents": 1, 310 | }, 311 | }, 312 | "sender": "23y3WetbNi6rDMgHmyRDjgpb7PnhgPotuPPawxruTMLYTLzG", 313 | }, 314 | "method": "TransferredAssets", 315 | "section": "xTokens", 316 | }, 317 | ] 318 | `; 319 | 320 | exports[`'polkadot' -> 'acala' xcm transfer 'DOT' > xcmPallet transfer > balance on from chain 1`] = ` 321 | { 322 | "consumers": 0, 323 | "data": { 324 | "flags": "0x80000000000000000000000000000000", 325 | "free": "(rounded 9000000000000)", 326 | "frozen": 0, 327 | "reserved": 0, 328 | }, 329 | "nonce": 1, 330 | "providers": 1, 331 | "sufficients": 0, 332 | } 333 | `; 334 | 335 | exports[`'polkadot' -> 'acala' xcm transfer 'DOT' > xcmPallet transfer > balance on to chain 1`] = ` 336 | { 337 | "free": "(rounded 11000000000000)", 338 | "frozen": 0, 339 | "reserved": 0, 340 | } 341 | `; 342 | 343 | exports[`'polkadot' -> 'acala' xcm transfer 'DOT' > xcmPallet transfer > to chain dmp events 1`] = ` 344 | [ 345 | { 346 | "data": { 347 | "count": 1, 348 | }, 349 | "method": "DownwardMessagesReceived", 350 | "section": "parachainSystem", 351 | }, 352 | { 353 | "data": { 354 | "dmqHead": "(hash)", 355 | "weightUsed": { 356 | "proofSize": "(rounded 8000)", 357 | "refTime": "(rounded 530000000)", 358 | }, 359 | }, 360 | "method": "DownwardMessagesProcessed", 361 | "section": "parachainSystem", 362 | }, 363 | { 364 | "data": { 365 | "id": "(hash)", 366 | "origin": "Parent", 367 | "success": true, 368 | "weightUsed": { 369 | "proofSize": 0, 370 | "refTime": 1000000000, 371 | }, 372 | }, 373 | "method": "Processed", 374 | "section": "messageQueue", 375 | }, 376 | ] 377 | `; 378 | 379 | exports[`'polkadot' -> 'acala' xcm transfer 'DOT' > xcmPallet transfer > tx events 1`] = ` 380 | [ 381 | { 382 | "data": { 383 | "outcome": { 384 | "Complete": { 385 | "used": { 386 | "proofSize": "(rounded 6200)", 387 | "refTime": "(rounded 265000000)", 388 | }, 389 | }, 390 | }, 391 | }, 392 | "method": "Attempted", 393 | "section": "xcmPallet", 394 | }, 395 | { 396 | "data": { 397 | "fees": [ 398 | { 399 | "fun": { 400 | "Fungible": 397000000, 401 | }, 402 | "id": { 403 | "interior": "Here", 404 | "parents": 0, 405 | }, 406 | }, 407 | ], 408 | "paying": { 409 | "interior": { 410 | "X1": [ 411 | { 412 | "AccountId32": { 413 | "id": "(hash)", 414 | "network": "Polkadot", 415 | }, 416 | }, 417 | ], 418 | }, 419 | "parents": 0, 420 | }, 421 | }, 422 | "method": "FeesPaid", 423 | "section": "xcmPallet", 424 | }, 425 | { 426 | "data": { 427 | "destination": { 428 | "interior": { 429 | "X1": [ 430 | { 431 | "Parachain": 2000, 432 | }, 433 | ], 434 | }, 435 | "parents": 0, 436 | }, 437 | "message": [ 438 | { 439 | "ReserveAssetDeposited": [ 440 | { 441 | "fun": { 442 | "Fungible": 1000000000000, 443 | }, 444 | "id": { 445 | "interior": "Here", 446 | "parents": 1, 447 | }, 448 | }, 449 | ], 450 | }, 451 | "ClearOrigin", 452 | { 453 | "BuyExecution": { 454 | "fees": { 455 | "fun": { 456 | "Fungible": 1000000000000, 457 | }, 458 | "id": { 459 | "interior": "Here", 460 | "parents": 1, 461 | }, 462 | }, 463 | "weightLimit": "Unlimited", 464 | }, 465 | }, 466 | { 467 | "DepositAsset": { 468 | "assets": { 469 | "Wild": { 470 | "AllCounted": 1, 471 | }, 472 | }, 473 | "beneficiary": { 474 | "interior": { 475 | "X1": [ 476 | { 477 | "AccountId32": { 478 | "id": "(hash)", 479 | "network": null, 480 | }, 481 | }, 482 | ], 483 | }, 484 | "parents": 0, 485 | }, 486 | }, 487 | }, 488 | ], 489 | "messageId": "(hash)", 490 | "origin": { 491 | "interior": { 492 | "X1": [ 493 | { 494 | "AccountId32": { 495 | "id": "(hash)", 496 | "network": "Polkadot", 497 | }, 498 | }, 499 | ], 500 | }, 501 | "parents": 0, 502 | }, 503 | }, 504 | "method": "Sent", 505 | "section": "xcmPallet", 506 | }, 507 | ] 508 | `; 509 | 510 | exports[`'polkadot' -> 'astar' xcm transfer 'DOT' > xcmPallet transfer > balance on from chain 1`] = ` 511 | { 512 | "consumers": 0, 513 | "data": { 514 | "flags": "0x80000000000000000000000000000000", 515 | "free": "(rounded 9000000000000)", 516 | "frozen": 0, 517 | "reserved": 0, 518 | }, 519 | "nonce": 1, 520 | "providers": 1, 521 | "sufficients": 0, 522 | } 523 | `; 524 | 525 | exports[`'polkadot' -> 'astar' xcm transfer 'DOT' > xcmPallet transfer > balance on to chain 1`] = ` 526 | { 527 | "balance": "(rounded 11000000000000)", 528 | "extra": null, 529 | "reason": { 530 | "consumer": null, 531 | }, 532 | "status": "Liquid", 533 | } 534 | `; 535 | 536 | exports[`'polkadot' -> 'astar' xcm transfer 'DOT' > xcmPallet transfer > to chain dmp events 1`] = ` 537 | [ 538 | { 539 | "data": { 540 | "count": 1, 541 | }, 542 | "method": "DownwardMessagesReceived", 543 | "section": "parachainSystem", 544 | }, 545 | { 546 | "data": { 547 | "dmqHead": "(hash)", 548 | "weightUsed": { 549 | "proofSize": "(rounded 8000)", 550 | "refTime": "(rounded 530000000)", 551 | }, 552 | }, 553 | "method": "DownwardMessagesProcessed", 554 | "section": "parachainSystem", 555 | }, 556 | { 557 | "data": { 558 | "id": "(hash)", 559 | "origin": "Parent", 560 | "success": true, 561 | "weightUsed": { 562 | "proofSize": "(rounded 9400)", 563 | "refTime": "(rounded 900000000)", 564 | }, 565 | }, 566 | "method": "Processed", 567 | "section": "messageQueue", 568 | }, 569 | ] 570 | `; 571 | 572 | exports[`'polkadot' -> 'astar' xcm transfer 'DOT' > xcmPallet transfer > tx events 1`] = ` 573 | [ 574 | { 575 | "data": { 576 | "outcome": { 577 | "Complete": { 578 | "used": { 579 | "proofSize": "(rounded 6200)", 580 | "refTime": "(rounded 265000000)", 581 | }, 582 | }, 583 | }, 584 | }, 585 | "method": "Attempted", 586 | "section": "xcmPallet", 587 | }, 588 | { 589 | "data": { 590 | "fees": [ 591 | { 592 | "fun": { 593 | "Fungible": 397000000, 594 | }, 595 | "id": { 596 | "interior": "Here", 597 | "parents": 0, 598 | }, 599 | }, 600 | ], 601 | "paying": { 602 | "interior": { 603 | "X1": [ 604 | { 605 | "AccountId32": { 606 | "id": "(hash)", 607 | "network": "Polkadot", 608 | }, 609 | }, 610 | ], 611 | }, 612 | "parents": 0, 613 | }, 614 | }, 615 | "method": "FeesPaid", 616 | "section": "xcmPallet", 617 | }, 618 | { 619 | "data": { 620 | "destination": { 621 | "interior": { 622 | "X1": [ 623 | { 624 | "Parachain": "(rounded 2010)", 625 | }, 626 | ], 627 | }, 628 | "parents": 0, 629 | }, 630 | "message": [ 631 | { 632 | "ReserveAssetDeposited": [ 633 | { 634 | "fun": { 635 | "Fungible": 1000000000000, 636 | }, 637 | "id": { 638 | "interior": "Here", 639 | "parents": 1, 640 | }, 641 | }, 642 | ], 643 | }, 644 | "ClearOrigin", 645 | { 646 | "BuyExecution": { 647 | "fees": { 648 | "fun": { 649 | "Fungible": 1000000000000, 650 | }, 651 | "id": { 652 | "interior": "Here", 653 | "parents": 1, 654 | }, 655 | }, 656 | "weightLimit": "Unlimited", 657 | }, 658 | }, 659 | { 660 | "DepositAsset": { 661 | "assets": { 662 | "Wild": { 663 | "AllCounted": 1, 664 | }, 665 | }, 666 | "beneficiary": { 667 | "interior": { 668 | "X1": [ 669 | { 670 | "AccountId32": { 671 | "id": "(hash)", 672 | "network": null, 673 | }, 674 | }, 675 | ], 676 | }, 677 | "parents": 0, 678 | }, 679 | }, 680 | }, 681 | ], 682 | "messageId": "(hash)", 683 | "origin": { 684 | "interior": { 685 | "X1": [ 686 | { 687 | "AccountId32": { 688 | "id": "(hash)", 689 | "network": "Polkadot", 690 | }, 691 | }, 692 | ], 693 | }, 694 | "parents": 0, 695 | }, 696 | }, 697 | "method": "Sent", 698 | "section": "xcmPallet", 699 | }, 700 | ] 701 | `; 702 | -------------------------------------------------------------------------------- /tests/xcm-transfer/kusama-para.test.ts: -------------------------------------------------------------------------------- 1 | import { Context } from '../../networks/types' 2 | import { query, tx } from '../../helpers/api' 3 | 4 | import { assetHubKusama } from '../../networks/assethub' 5 | import { basilisk } from '../../networks/hydraDX' 6 | import { karura } from '../../networks/acala' 7 | 8 | import buildTest from './shared' 9 | 10 | const tests = [ 11 | // assetHubKusama <-> karura 12 | { 13 | from: 'assetHubKusama', 14 | to: 'karura', 15 | name: 'USDT', 16 | test: { 17 | xcmPalletHorizontal: { 18 | tx: tx.xcmPallet.limitedReserveTransferAssetsV3( 19 | assetHubKusama.usdt, 20 | 1e6, 21 | tx.xcmPallet.parachainV3(1, karura.paraId), 22 | ), 23 | fromBalance: query.assets(assetHubKusama.usdtIndex), 24 | toBalance: query.tokens(karura.usdt), 25 | }, 26 | }, 27 | }, 28 | { 29 | from: 'karura', 30 | to: 'assetHubKusama', 31 | name: 'USDT', 32 | fromStorage: ({ alice }: Context) => ({ 33 | Tokens: { 34 | Accounts: [[[alice.address, karura.usdt], { free: 10e6 }]], 35 | }, 36 | }), 37 | test: { 38 | xtokenstHorizontal: { 39 | tx: tx.xtokens.transfer(karura.usdt, 1e6, tx.xtokens.parachainV3(assetHubKusama.paraId)), 40 | fromBalance: query.tokens(karura.usdt), 41 | toBalance: query.assets(assetHubKusama.usdtIndex), 42 | }, 43 | }, 44 | }, 45 | // karura <-> basilisk 46 | { 47 | from: 'karura', 48 | to: 'basilisk', 49 | name: 'DAI', 50 | fromStorage: { 51 | Evm: { 52 | accountStorages: [ 53 | [ 54 | [ 55 | karura.dai.Erc20, 56 | '0x2aef47e62c966f0695d5af370ddc1bc7c56902063eee60853e2872fc0ff4f88c', // balanceOf(Alice) 57 | ], 58 | '0x0000000000000000000000000000000000000000000000056bc75e2d63100000', // 1e20 59 | ], 60 | ], 61 | }, 62 | }, 63 | test: { 64 | xtokenstHorizontal: { 65 | tx: tx.xtokens.transfer(karura.dai, 10n ** 18n, tx.xtokens.parachainV3(basilisk.paraId)), 66 | fromBalance: query.evm(karura.dai.Erc20, '0x2aef47e62c966f0695d5af370ddc1bc7c56902063eee60853e2872fc0ff4f88c'), 67 | toBalance: query.tokens(basilisk.dai), 68 | }, 69 | }, 70 | }, 71 | // TODO: restore this once Basilisk fixed the asset mapping issue 72 | // { 73 | // from: 'basilisk', 74 | // to: 'karura', 75 | // name: 'DAI', 76 | // fromStorage: ({ alice }: Context) => ({ 77 | // Tokens: { 78 | // accounts: [[[alice.address, basilisk.dai], { free: 10n * 10n ** 18n }]], 79 | // }, 80 | // }), 81 | // test: { 82 | // xtokenstHorizontal: { 83 | // tx: tx.xtokens.transfer(basilisk.dai, 10n ** 18n, tx.xtokens.parachainV3(karura.paraId)), 84 | // fromBalance: query.tokens(basilisk.dai), 85 | // toBalance: query.evm(karura.dai.Erc20, '0x2aef47e62c966f0695d5af370ddc1bc7c56902063eee60853e2872fc0ff4f88c'), 86 | // }, 87 | // }, 88 | // }, 89 | ] as const 90 | 91 | export type TestType = (typeof tests)[number] 92 | 93 | buildTest(tests) 94 | -------------------------------------------------------------------------------- /tests/xcm-transfer/kusama-relay.test.ts: -------------------------------------------------------------------------------- 1 | import { query, tx } from '../../helpers/api' 2 | 3 | import { karura } from '../../networks/acala' 4 | import { kusama } from '../../networks/polkadot' 5 | import { shiden } from '../../networks/astar' 6 | 7 | import buildTest from './shared' 8 | 9 | const tests = [ 10 | // karura <-> kusama 11 | { 12 | from: 'karura', 13 | to: 'kusama', 14 | name: 'KSM', 15 | test: { 16 | xtokensUp: { 17 | tx: tx.xtokens.transfer(karura.ksm, 1e12, tx.xtokens.relaychainV3), 18 | balance: query.tokens(karura.ksm), 19 | }, 20 | }, 21 | }, 22 | { 23 | from: 'karura', 24 | to: 'kusama', 25 | name: 'KSM wiht limited weight', 26 | test: { 27 | xtokensUp: { 28 | tx: tx.xtokens.transfer(karura.ksm, 1e12, tx.xtokens.relaychainV3, { Limited: { refTime: 5000000000 } }), 29 | balance: query.tokens(karura.ksm), 30 | }, 31 | }, 32 | }, 33 | { 34 | from: 'kusama', 35 | to: 'karura', 36 | name: 'KSM', 37 | test: { 38 | xcmPalletDown: { 39 | tx: tx.xcmPallet.limitedReserveTransferAssetsV3(kusama.ksm, 1e12, tx.xcmPallet.parachainV3(0, karura.paraId)), 40 | balance: query.tokens(karura.ksm), 41 | }, 42 | }, 43 | }, 44 | // kusama <-> shiden 45 | { 46 | from: 'kusama', 47 | to: 'shiden', 48 | name: 'KSM', 49 | test: { 50 | xcmPalletDown: { 51 | tx: tx.xcmPallet.limitedReserveTransferAssetsV3(kusama.ksm, 1e12, tx.xcmPallet.parachainV3(0, shiden.paraId)), 52 | balance: query.assets(shiden.ksm), 53 | }, 54 | }, 55 | }, 56 | ] as const 57 | 58 | export type TestType = (typeof tests)[number] 59 | 60 | buildTest(tests) 61 | -------------------------------------------------------------------------------- /tests/xcm-transfer/playground.test.ts: -------------------------------------------------------------------------------- 1 | // import { Context } from '../../networks/types' 2 | // import { query, tx } from '../../helpers/api' 3 | 4 | // import { acala , karura } from '../../networks/acala' 5 | // import { basilisk , hydraDX } from '../../networks/hydraDX' 6 | // import { kusama, polkadot } from '../../networks/polkadot' 7 | // import { moonbeam } from '../../networks/moonbeam' 8 | // import { statemine , statemint } from '../../networks/statemint' 9 | 10 | import buildTest from './shared' 11 | 12 | // Use this file to write new tests so you can run it without running all other tests 13 | // Move the tests to approapriate file when you are done 14 | 15 | const tests = [] as const 16 | 17 | export type TestType = (typeof tests)[number] 18 | 19 | buildTest(tests) 20 | -------------------------------------------------------------------------------- /tests/xcm-transfer/polkadot-para.test.ts: -------------------------------------------------------------------------------- 1 | import { Context } from '../../networks/types' 2 | import { query, tx } from '../../helpers/api' 3 | 4 | import { acala } from '../../networks/acala' 5 | import { assetHubPolkadot } from '../../networks/assethub' 6 | 7 | import buildTest from './shared' 8 | 9 | const tests = [ 10 | // assetHubPolkadot <-> acala 11 | { 12 | from: 'assetHubPolkadot', 13 | to: 'acala', 14 | name: 'WBTC', 15 | fromStorage: ({ alice }: Context) => ({ 16 | System: { 17 | account: [[[acala.paraAccount], { providers: 1, data: { free: 10e10 } }]], 18 | }, 19 | Assets: { 20 | account: [[[assetHubPolkadot.wbtcIndex, alice.address], { balance: 1e8 }]], 21 | asset: [[[assetHubPolkadot.wbtcIndex], { supply: 1e8 }]], 22 | }, 23 | }), 24 | test: { 25 | xcmPalletHorizontal: { 26 | tx: tx.xcmPallet.limitedReserveTransferAssetsV3( 27 | assetHubPolkadot.wbtc, 28 | 1e7, 29 | tx.xcmPallet.parachainV3(1, acala.paraId), 30 | ), 31 | fromBalance: query.assets(assetHubPolkadot.wbtcIndex), 32 | toBalance: query.tokens(acala.wbtc), 33 | }, 34 | }, 35 | }, 36 | { 37 | // TODO: this failed with FailedToTransactAsset on assetHubPolkadot somehow 38 | from: 'acala', 39 | to: 'assetHubPolkadot', 40 | route: 'polkadot', // for sending DOT for fee 41 | name: 'WBTC', 42 | fromStorage: ({ alice }: Context) => ({ 43 | Tokens: { 44 | Accounts: [[[alice.address, acala.wbtc], { free: 1e8 }]], 45 | }, 46 | }), 47 | toStorage: ({ alice }: Context) => ({ 48 | System: { 49 | account: [[[acala.paraAccount], { providers: 1, data: { free: 10e10 } }]], 50 | }, 51 | Assets: { 52 | account: [ 53 | [[assetHubPolkadot.wbtcIndex, acala.paraAccount], { balance: 10e8 }], 54 | [[assetHubPolkadot.wbtcIndex, alice.address], { balance: 10e8 }], 55 | ], 56 | asset: [[[assetHubPolkadot.wbtcIndex], { supply: 10e8 }]], 57 | }, 58 | }), 59 | test: { 60 | xtokenstHorizontal: { 61 | tx: tx.xtokens.transferMulticurrencies( 62 | acala.wbtc, 63 | 1e7, 64 | acala.dot, // fee 65 | 16e9, 66 | tx.xtokens.parachainV3(assetHubPolkadot.paraId), 67 | ), 68 | fromBalance: query.tokens(acala.wbtc), 69 | toBalance: query.assets(assetHubPolkadot.wbtcIndex), 70 | }, 71 | }, 72 | }, 73 | ] as const 74 | 75 | export type TestType = (typeof tests)[number] 76 | 77 | buildTest(tests) 78 | -------------------------------------------------------------------------------- /tests/xcm-transfer/polkadot-relay.test.ts: -------------------------------------------------------------------------------- 1 | import { query, tx } from '../../helpers/api' 2 | 3 | import { acala } from '../../networks/acala' 4 | import { astar } from '../../networks/astar' 5 | import { polkadot } from '../../networks/polkadot' 6 | 7 | import buildTest from './shared' 8 | 9 | const tests = [ 10 | // acala <-> polkadot 11 | { 12 | from: 'acala', 13 | to: 'polkadot', 14 | name: 'DOT', 15 | test: { 16 | xtokensUp: { 17 | tx: tx.xtokens.transfer(acala.dot, 1e12, tx.xtokens.relaychainV3), 18 | balance: query.tokens(acala.dot), 19 | }, 20 | }, 21 | }, 22 | { 23 | from: 'acala', 24 | to: 'polkadot', 25 | name: 'DOT wiht limited weight', 26 | test: { 27 | xtokensUp: { 28 | tx: tx.xtokens.transfer(acala.dot, 1e12, tx.xtokens.relaychainV3, { Limited: { refTime: 5000000000 } }), 29 | balance: query.tokens(acala.dot), 30 | }, 31 | }, 32 | }, 33 | { 34 | from: 'polkadot', 35 | to: 'acala', 36 | name: 'DOT', 37 | test: { 38 | xcmPalletDown: { 39 | tx: tx.xcmPallet.limitedReserveTransferAssetsV3(polkadot.dot, 1e12, tx.xcmPallet.parachainV3(0, acala.paraId)), 40 | balance: query.tokens(acala.dot), 41 | }, 42 | }, 43 | }, 44 | // polkadot <-> astar 45 | { 46 | from: 'polkadot', 47 | to: 'astar', 48 | name: 'DOT', 49 | test: { 50 | xcmPalletDown: { 51 | tx: tx.xcmPallet.limitedReserveTransferAssetsV3(polkadot.dot, 1e12, tx.xcmPallet.parachainV3(0, astar.paraId)), 52 | balance: query.assets(astar.dot), 53 | }, 54 | }, 55 | }, 56 | ] as const 57 | 58 | export type TestType = (typeof tests)[number] 59 | 60 | buildTest(tests) 61 | -------------------------------------------------------------------------------- /tests/xcm-transfer/shared.ts: -------------------------------------------------------------------------------- 1 | import { afterEach, beforeEach, describe, it } from 'vitest' 2 | import { sendTransaction } from '@acala-network/chopsticks-testing' 3 | import _ from 'lodash' 4 | 5 | import { Network, NetworkNames, createContext, createNetworks } from '../../networks' 6 | import { check, checkEvents, checkHrmp, checkSystemEvents, checkUmp } from '../../helpers' 7 | 8 | import type { TestType as KusamaParaTestType } from './kusama-para.test' 9 | import type { TestType as KusamaRelayTestType } from './kusama-relay.test' 10 | import type { TestType as PlaygroundTestType } from './playground.test' 11 | import type { TestType as PolkadotParaTestType } from './polkadot-para.test' 12 | import type { TestType as PolkadotRelayTestType } from './polkadot-relay.test' 13 | 14 | type TestType = 15 | | KusamaRelayTestType 16 | | KusamaParaTestType 17 | | PolkadotRelayTestType 18 | | PolkadotParaTestType 19 | | PlaygroundTestType 20 | 21 | export default function buildTest(tests: ReadonlyArray) { 22 | for (const { from, to, test, name, ...opt } of tests) { 23 | describe(`'${from}' -> '${to}' xcm transfer '${name}'`, async () => { 24 | let fromChain: Network 25 | let toChain: Network 26 | let routeChain: Network 27 | 28 | const ctx = createContext() 29 | const { alice } = ctx 30 | 31 | let fromAccount = alice 32 | if ('fromAccount' in opt) { 33 | fromAccount = (opt.fromAccount as any)(ctx) 34 | } 35 | 36 | let toAccount = alice 37 | if ('toAccount' in opt) { 38 | toAccount = (opt.toAccount as any)(ctx) 39 | } 40 | 41 | const precision = 3 42 | // if ('precision' in opt) { 43 | // precision = opt.precision 44 | // } 45 | 46 | beforeEach(async () => { 47 | const networkOptions = { 48 | [from]: undefined, 49 | [to]: undefined, 50 | } as Record 51 | if ('route' in opt) { 52 | networkOptions[opt.route] = undefined 53 | } 54 | const chains = await createNetworks(networkOptions, ctx) 55 | 56 | fromChain = chains[from] 57 | toChain = chains[to] 58 | if ('route' in opt) { 59 | routeChain = chains[opt.route] 60 | } 61 | 62 | if ('fromStorage' in opt) { 63 | const override = typeof opt.fromStorage === 'function' ? opt.fromStorage(ctx) : opt.fromStorage 64 | await fromChain.dev.setStorage(override) 65 | } 66 | 67 | if ('toStorage' in opt) { 68 | const override = typeof opt.toStorage === 'function' ? opt.toStorage(ctx) : opt.toStorage 69 | await toChain.dev.setStorage(override) 70 | } 71 | }) 72 | 73 | afterEach(async () => { 74 | await toChain.teardown() 75 | await fromChain.teardown() 76 | if (routeChain) { 77 | await routeChain.teardown() 78 | } 79 | }) 80 | 81 | if ('xtokensUp' in test) { 82 | const { balance, tx } = test.xtokensUp 83 | 84 | it('xtokens transfer', async () => { 85 | const tx0 = await sendTransaction(tx(fromChain, toAccount.addressRaw).signAsync(fromAccount)) 86 | 87 | await fromChain.chain.newBlock() 88 | 89 | await check(balance(fromChain, fromAccount.address)) 90 | .redact({ number: precision }) 91 | .toMatchSnapshot('balance on from chain') 92 | await checkEvents(tx0, 'xTokens').redact({ number: precision }).toMatchSnapshot('tx events') 93 | await checkUmp(fromChain).toMatchSnapshot('from chain ump messages') 94 | 95 | await toChain.chain.newBlock() 96 | 97 | await check(toChain.api.query.system.account(toAccount.address)) 98 | .redact({ number: precision }) 99 | .toMatchSnapshot('balance on to chain') 100 | await checkSystemEvents(toChain, 'ump', 'messageQueue').toMatchSnapshot('to chain ump events') 101 | }, 240000) 102 | } 103 | 104 | if ('xcmPalletDown' in test) { 105 | const { balance, tx } = test.xcmPalletDown 106 | 107 | it('xcmPallet transfer', async () => { 108 | const tx0 = await sendTransaction(tx(fromChain, toAccount.addressRaw).signAsync(fromAccount)) 109 | 110 | await fromChain.chain.newBlock() 111 | 112 | await check(fromChain.api.query.system.account(fromAccount.address)) 113 | .redact({ number: precision }) 114 | .toMatchSnapshot('balance on from chain') 115 | await checkEvents(tx0, 'xcmPallet').redact({ number: precision }).toMatchSnapshot('tx events') 116 | 117 | await toChain.chain.newBlock() 118 | 119 | await check(balance(toChain, toAccount.address)) 120 | .redact({ number: precision }) 121 | .toMatchSnapshot('balance on to chain') 122 | await checkSystemEvents(toChain, 'parachainSystem', 'dmpQueue', 'messageQueue').toMatchSnapshot( 123 | 'to chain dmp events', 124 | ) 125 | }, 240000) 126 | } 127 | 128 | if ('xcmPalletHorizontal' in test) { 129 | const { fromBalance, toBalance, tx, ...testOpt } = test.xcmPalletHorizontal 130 | 131 | it('xcmPallet transfer', async () => { 132 | const tx0 = await sendTransaction(tx(fromChain, toAccount.addressRaw).signAsync(fromAccount)) 133 | 134 | await fromChain.chain.newBlock() 135 | 136 | await check(fromBalance(fromChain, fromAccount.address)) 137 | .redact({ number: precision }) 138 | .toMatchSnapshot('balance on from chain') 139 | await checkEvents(tx0, 'polkadotXcm').redact({ number: precision }).toMatchSnapshot('tx events') 140 | 141 | if ('checkUmp' in testOpt) { 142 | await checkUmp(fromChain).toMatchSnapshot('from chain ump messages') 143 | } else { 144 | await checkHrmp(fromChain) 145 | .redact({ redactKeys: /setTopic/ }) 146 | .toMatchSnapshot('from chain hrmp messages') 147 | } 148 | 149 | if (routeChain) { 150 | await routeChain.chain.newBlock() 151 | } 152 | await toChain.chain.newBlock() 153 | 154 | await check(toBalance(toChain, toAccount.address)) 155 | .redact({ number: precision }) 156 | .toMatchSnapshot('balance on to chain') 157 | await checkSystemEvents(toChain, 'xcmpQueue', 'dmpQueue', 'messageQueue').toMatchSnapshot( 158 | 'to chain xcm events', 159 | ) 160 | }, 240000) 161 | } 162 | 163 | if ('xtokenstHorizontal' in test) { 164 | const { fromBalance, toBalance, tx, ...testOpt } = test.xtokenstHorizontal 165 | 166 | it('xtokens transfer', async () => { 167 | const txx = tx(fromChain, toAccount.addressRaw) 168 | const tx0 = await sendTransaction(txx.signAsync(fromAccount)) 169 | 170 | await fromChain.chain.newBlock() 171 | 172 | await check(fromBalance(fromChain, fromAccount.address)) 173 | .redact({ number: precision }) 174 | .toMatchSnapshot('balance on from chain') 175 | await checkEvents(tx0, 'xTokens').toMatchSnapshot('tx events') 176 | 177 | if ('checkUmp' in testOpt) { 178 | await checkUmp(fromChain).toMatchSnapshot('from chain ump messages') 179 | } else { 180 | await checkHrmp(fromChain).toMatchSnapshot('from chain hrmp messages') 181 | } 182 | 183 | if (routeChain) { 184 | await routeChain.chain.newBlock() 185 | } 186 | await toChain.chain.newBlock() 187 | 188 | await check(toBalance(toChain, toAccount.address)) 189 | .redact({ number: precision }) 190 | .toMatchSnapshot('balance on to chain') 191 | await checkSystemEvents(toChain, 'xcmpQueue', 'dmpQueue', 'messageQueue').toMatchSnapshot( 192 | 'to chain xcm events', 193 | ) 194 | }, 240000) 195 | } 196 | }) 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["ESNext"], 4 | "module": "esnext", 5 | "target": "esnext", 6 | "moduleResolution": "bundler", 7 | "moduleDetection": "force", 8 | "allowImportingTsExtensions": true, 9 | "noEmit": true, 10 | "composite": true, 11 | "strict": true, 12 | "downlevelIteration": true, 13 | "skipLibCheck": true, 14 | "jsx": "react-jsx", 15 | "allowSyntheticDefaultImports": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "allowJs": true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /vitest.config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config' 2 | import swc from 'unplugin-swc' 3 | 4 | export default defineConfig({ 5 | test: { 6 | hookTimeout: 240_000, 7 | testTimeout: 240_000, 8 | pool: 'forks', 9 | passWithNoTests: true, 10 | retry: process.env.CI ? 3 : 2, 11 | reporters: process.env.GITHUB_ACTIONS ? ['basic', 'github-actions'] : ['basic'], 12 | }, 13 | plugins: [swc.vite()], 14 | }) 15 | -------------------------------------------------------------------------------- /wasm/acala-2240.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AcalaNetwork/e2e-tests/18ea104b765362a8a5660e663bc64bbe342b7e2b/wasm/acala-2240.wasm -------------------------------------------------------------------------------- /wasm/acala_runtime.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AcalaNetwork/e2e-tests/18ea104b765362a8a5660e663bc64bbe342b7e2b/wasm/acala_runtime.wasm -------------------------------------------------------------------------------- /wasm/karura-2240.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AcalaNetwork/e2e-tests/18ea104b765362a8a5660e663bc64bbe342b7e2b/wasm/karura-2240.wasm -------------------------------------------------------------------------------- /wasm/karura_runtime.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AcalaNetwork/e2e-tests/18ea104b765362a8a5660e663bc64bbe342b7e2b/wasm/karura_runtime.wasm --------------------------------------------------------------------------------