├── .editorconfig ├── .env.example ├── .github ├── command-runner │ ├── command-runner-config.json │ ├── comment.cjs │ ├── merge.cjs │ ├── postBump.cjs │ ├── runOrBump.cjs │ └── utils.cjs ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── command-runner.yml │ ├── notifications.json │ ├── update-known-good.yml │ └── update-snapshot.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .npmrc ├── .prettierignore ├── .vscode └── settings.json ├── .yarn └── releases │ └── yarn-4.9.1.cjs ├── .yarnrc.yml ├── KNOWN_GOOD_BLOCK_NUMBERS.env ├── README.md ├── biome.json ├── eslint.config.mjs ├── package.json ├── packages ├── kusama │ ├── package.json │ ├── src │ │ ├── __snapshots__ │ │ │ ├── assetHubKusama.bridgeHubKusama.test.ts.snap │ │ │ ├── assetHubKusama.coretimeKusama.test.ts.snap │ │ │ ├── assetHubKusama.karura.test.ts.snap │ │ │ ├── assetHubKusama.kusama.test.ts.snap │ │ │ ├── assetHubKusama.peopleKusama.test.ts.snap │ │ │ ├── assetHubKusama.proxy.e2e.test.ts.snap │ │ │ ├── assetHubKusama.scheduler.e2e.test.ts.snap │ │ │ ├── assetHubKusama.vesting.e2e.test.ts.snap │ │ │ ├── basilisk.karura.test.ts.snap │ │ │ ├── bridgeHubKusama.kusama.test.ts.snap │ │ │ ├── coretimeKusama.kusama.test.ts.snap │ │ │ ├── coretimeKusama.proxy.e2e.test.ts.snap │ │ │ ├── karura.kusama.test.ts.snap │ │ │ ├── karura.shiden.test.ts.snap │ │ │ ├── kusama.governance.e2e.test.ts.snap │ │ │ ├── kusama.nominationPools.e2e.test.ts.snap │ │ │ ├── kusama.proxy.e2e.test.ts.snap │ │ │ ├── kusama.scheduler.e2e.test.ts.snap │ │ │ ├── kusama.shiden.test.ts.snap │ │ │ ├── kusama.staking.e2e.test.ts.snap │ │ │ ├── kusama.vesting.e2e.test.ts.snap │ │ │ ├── peopleKusama.e2e.test.ts.snap │ │ │ ├── peopleKusama.kusama.test.ts.snap │ │ │ └── peopleKusama.proxy.e2e.test.ts.snap │ │ ├── assetHubKusama.bridgeHubKusama.test.ts │ │ ├── assetHubKusama.coretimeKusama.test.ts │ │ ├── assetHubKusama.karura.test.ts │ │ ├── assetHubKusama.kusama.test.ts │ │ ├── assetHubKusama.peopleKusama.test.ts │ │ ├── assetHubKusama.proxy.e2e.test.ts │ │ ├── assetHubKusama.scheduler.e2e.test.ts │ │ ├── assetHubKusama.vesting.e2e.test.ts │ │ ├── basilisk.karura.test.ts │ │ ├── bridgeHubKusama.kusama.test.ts │ │ ├── coretimeKusama.kusama.test.ts │ │ ├── coretimeKusama.proxy.e2e.test.ts │ │ ├── karura.kusama.test.ts │ │ ├── karura.shiden.test.ts │ │ ├── kusama.governance.e2e.test.ts │ │ ├── kusama.nominationPools.e2e.test.ts │ │ ├── kusama.proxy.e2e.test.ts │ │ ├── kusama.scheduler.e2e.test.ts │ │ ├── kusama.shiden.test.ts │ │ ├── kusama.staking.e2e.test.ts │ │ ├── kusama.vesting.e2e.test.ts │ │ ├── peopleKusama.e2e.test.ts │ │ ├── peopleKusama.kusama.test.ts │ │ └── peopleKusama.proxy.e2e.test.ts │ └── tsconfig.json ├── networks │ ├── package.json │ ├── src │ │ ├── captureSnapshot.ts │ │ ├── chains │ │ │ ├── acala.ts │ │ │ ├── assethub.ts │ │ │ ├── astar.ts │ │ │ ├── bridgehub.ts │ │ │ ├── collectives.ts │ │ │ ├── coretime.ts │ │ │ ├── hydration.ts │ │ │ ├── index.ts │ │ │ ├── moonbeam.ts │ │ │ ├── people.ts │ │ │ └── polkadot.ts │ │ ├── createNetwork.ts │ │ ├── defaultAccounts.ts │ │ ├── defineChain.ts │ │ ├── index.ts │ │ └── types.ts │ └── tsconfig.json ├── polkadot │ ├── package.json │ ├── src │ │ ├── __snapshots__ │ │ │ ├── acala.assetHubPolkadot.test.ts.snap │ │ │ ├── acala.astar.test.ts.snap │ │ │ ├── acala.moonbeam.test.ts.snap │ │ │ ├── acala.polkadot.test.ts.snap │ │ │ ├── assetHubPolkadot.bridgeHubPolkadot.test.ts.snap │ │ │ ├── assetHubPolkadot.collectivesPolkadot.test.ts.snap │ │ │ ├── assetHubPolkadot.coretimePolkadot.test.ts.snap │ │ │ ├── assetHubPolkadot.peoplePolkadot.test.ts.snap │ │ │ ├── assetHubPolkadot.polkadot.test.ts.snap │ │ │ ├── assetHubPolkadot.proxy.e2e.test.ts.snap │ │ │ ├── assetHubPolkadot.scheduler.e2e.test.ts.snap │ │ │ ├── assetHubPolkadot.vesting.e2e.test.ts.snap │ │ │ ├── astar.polkadot.test.ts.snap │ │ │ ├── bridgeHubPolkadot.polkadot.test.ts.snap │ │ │ ├── collectivesPolkadot.polkadot.test.ts.snap │ │ │ ├── collectivesPolkadot.proxy.e2e.test.ts.snap │ │ │ ├── collectivesPolkadot.scheduler.e2e.test.ts.snap │ │ │ ├── coretimePolkadot.polkadot.test.ts.snap │ │ │ ├── coretimePolkadot.proxy.e2e.test.ts.snap │ │ │ ├── hydration.moonbeam.test.ts.snap │ │ │ ├── peoplePolkadot.e2e.test.ts.snap │ │ │ ├── peoplePolkadot.polkadot.test.ts.snap │ │ │ ├── peoplePolkadot.proxy.e2e.test.ts.snap │ │ │ ├── polkadot.assetHubPolkadot.collectivesPolkadot.test.ts.snap │ │ │ ├── polkadot.bridgeHubPolkadot.collectivesPolkadot.test.ts.snap │ │ │ ├── polkadot.coretimePolkadot.collectivesPolkadot.test.ts.snap │ │ │ ├── polkadot.governance.e2e.test.ts.snap │ │ │ ├── polkadot.nominationPools.e2e.test.ts.snap │ │ │ ├── polkadot.peoplePolkadot.collectivesPolkadot.test.ts.snap │ │ │ ├── polkadot.proxy.e2e.test.ts.snap │ │ │ ├── polkadot.scheduler.e2e.test.ts.snap │ │ │ ├── polkadot.staking.e2e.test.ts.snap │ │ │ └── polkadot.vesting.e2e.test.ts.snap │ │ ├── acala.assetHubPolkadot.test.ts │ │ ├── acala.astar.test.ts │ │ ├── acala.moonbeam.test.ts │ │ ├── acala.polkadot.test.ts │ │ ├── assetHubPolkadot.bridgeHubPolkadot.test.ts │ │ ├── assetHubPolkadot.collectivesPolkadot.test.ts │ │ ├── assetHubPolkadot.coretimePolkadot.test.ts │ │ ├── assetHubPolkadot.peoplePolkadot.test.ts │ │ ├── assetHubPolkadot.polkadot.test.ts │ │ ├── assetHubPolkadot.proxy.e2e.test.ts │ │ ├── assetHubPolkadot.scheduler.e2e.test.ts │ │ ├── assetHubPolkadot.vesting.e2e.test.ts │ │ ├── astar.polkadot.test.ts │ │ ├── bridgeHubPolkadot.polkadot.test.ts │ │ ├── collectivesPolkadot.polkadot.test.ts │ │ ├── collectivesPolkadot.proxy.e2e.test.ts │ │ ├── collectivesPolkadot.scheduler.e2e.test.ts │ │ ├── coretimePolkadot.polkadot.test.ts │ │ ├── coretimePolkadot.proxy.e2e.test.ts │ │ ├── hydration.moonbeam.test.ts │ │ ├── peoplePolkadot.e2e.test.ts │ │ ├── peoplePolkadot.polkadot.test.ts │ │ ├── peoplePolkadot.proxy.e2e.test.ts │ │ ├── polkadot.assetHubPolkadot.collectivesPolkadot.test.ts │ │ ├── polkadot.bridgeHubPolkadot.collectivesPolkadot.test.ts │ │ ├── polkadot.coretimePolkadot.collectivesPolkadot.test.ts │ │ ├── polkadot.governance.e2e.test.ts │ │ ├── polkadot.nominationPools.e2e.test.ts │ │ ├── polkadot.peoplePolkadot.collectivesPolkadot.test.ts │ │ ├── polkadot.proxy.e2e.test.ts │ │ ├── polkadot.scheduler.e2e.test.ts │ │ ├── polkadot.staking.e2e.test.ts │ │ └── polkadot.vesting.e2e.test.ts │ └── tsconfig.json └── shared │ ├── package.json │ ├── src │ ├── api │ │ ├── index.ts │ │ └── query.ts │ ├── collectives.ts │ ├── governance.ts │ ├── helpers │ │ ├── index.ts │ │ └── proxyTypes.ts │ ├── index.ts │ ├── nomination-pools.ts │ ├── people.ts │ ├── proxy.ts │ ├── scheduler.ts │ ├── setup.ts │ ├── staking.ts │ ├── types.ts │ ├── upgrade.ts │ ├── vesting.ts │ └── xcm │ │ ├── index.ts │ │ ├── runXcmPalletDown.ts │ │ ├── runXcmPalletHorizontal.ts │ │ ├── runXcmPalletUp.ts │ │ ├── runXtokensUp.ts │ │ ├── runXtokenstHorizontal.ts │ │ └── types.ts │ └── tsconfig.json ├── scripts ├── check-proxy-coverage.ts └── update-env.ts ├── tsconfig.base.json ├── tsconfig.json ├── tsconfig.lint.json ├── vitest.config.mts └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | indent_style=tab 4 | indent_size=2 5 | tab_width=2 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,cjs}] 19 | indent_style=space 20 | tab_width=2 21 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | DB_PATH=./db.sqlite 2 | RUNTIME_LOG_LEVEL=5 3 | -------------------------------------------------------------------------------- /.github/command-runner/command-runner-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "run": { 3 | "allowed_issues": [45] 4 | }, 5 | "merge": { 6 | "allowed_users": ["xlc", "ntduan"] 7 | }, 8 | "cancel-merge": { 9 | "allowed_users": ["xlc", "ntduan"] 10 | }, 11 | "bump": { 12 | "allowed_issues": [45] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.github/command-runner/comment.cjs: -------------------------------------------------------------------------------- 1 | module.exports = class Comment { 2 | constructor({ github, context, commentId }) { 3 | this.github = github 4 | this.context = context 5 | this.commentId = commentId || null 6 | } 7 | 8 | async createOrUpdateComment(body) { 9 | const actionUrl = `https://github.com/${this.context.payload.repository.full_name}/actions/runs/${this.context.runId}` 10 | if (!this.commentId) { 11 | const result = await this.github.rest.issues.createComment({ 12 | issue_number: this.context.issue.number, 13 | owner: this.context.repo.owner, 14 | repo: this.context.repo.repo, 15 | body: `${body}` + `\n[view details](${actionUrl})`, 16 | }) 17 | this.commentId = result.data.id 18 | } 19 | await this.github.rest.issues.updateComment({ 20 | comment_id: this.commentId, 21 | issue_number: this.context.issue.number, 22 | owner: this.context.repo.owner, 23 | repo: this.context.repo.repo, 24 | body: `${body}` + `\n[view details](${actionUrl})`, 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.github/command-runner/merge.cjs: -------------------------------------------------------------------------------- 1 | module.exports = async ({ github, context, command, core, commentId }) => { 2 | const Comment = require('./comment.cjs') 3 | const comment = new Comment({ github, context, commentId }) 4 | 5 | if (command === 'merge') { 6 | console.log('Run merge') 7 | 8 | const { repository } = await github.graphql( 9 | ` 10 | query($owner: String!, $repo: String!, $pullNumber: Int!) { 11 | repository(owner: $owner, name: $repo) { 12 | pullRequest(number: $pullNumber) { 13 | id 14 | } 15 | } 16 | } 17 | `, 18 | { 19 | ...context.repo, 20 | pullNumber: context.issue.number, 21 | }, 22 | ) 23 | 24 | const pullRequestId = repository.pullRequest.id 25 | 26 | await github.graphql( 27 | ` 28 | mutation($pullRequestId: ID!) { 29 | enablePullRequestAutoMerge(input: { pullRequestId: $pullRequestId, mergeMethod: SQUASH }) { 30 | pullRequest { 31 | autoMergeRequest { 32 | enabledAt 33 | } 34 | } 35 | } 36 | } 37 | `, 38 | { 39 | pullRequestId: pullRequestId, 40 | }, 41 | ) 42 | 43 | const pendingReview = await github.rest.pulls.createReview({ 44 | ...context.repo, 45 | pull_number: context.issue.number, 46 | }) 47 | 48 | await github.rest.pulls.submitReview({ 49 | ...context.repo, 50 | pull_number: context.issue.number, 51 | event: 'APPROVE', 52 | review_id: pendingReview.data.id, 53 | }) 54 | 55 | await comment.createOrUpdateComment(` Auto-merge enabled`) 56 | core.info('Auto-merge enabled') 57 | return 58 | } 59 | 60 | if (command === 'cancel-merge') { 61 | console.log('Run cancel-merge') 62 | await github.rest.pulls.submitReview({ 63 | ...context.repo, 64 | pull_number: context.issue.number, 65 | event: 'REQUEST_CHANGES', 66 | body: 'Dismissed', 67 | }) 68 | 69 | const { repository } = await github.graphql( 70 | ` 71 | query($owner: String!, $repo: String!, $pullNumber: Int!) { 72 | repository(owner: $owner, name: $repo) { 73 | pullRequest(number: $pullNumber) { 74 | id 75 | } 76 | } 77 | } 78 | `, 79 | { 80 | ...context.repo, 81 | pullNumber: context.issue.number, 82 | }, 83 | ) 84 | 85 | const pullRequestId = repository.pullRequest.id 86 | 87 | await github.graphql( 88 | ` 89 | mutation($pullRequestId: ID!) { 90 | disablePullRequestAutoMerge(input: { pullRequestId: $pullRequestId }) { 91 | pullRequest { 92 | autoMergeRequest { 93 | disabledAt 94 | } 95 | } 96 | } 97 | `, 98 | { 99 | pullRequestId: pullRequestId, 100 | }, 101 | ) 102 | await comment.createOrUpdateComment(` Auto-merge disabled`) 103 | 104 | core.info('Auto-merge disabled') 105 | return 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /.github/command-runner/postBump.cjs: -------------------------------------------------------------------------------- 1 | module.exports = async ({ github, context, exec, commentId, core, testResult }) => { 2 | const Comment = require('./comment.cjs') 3 | const comment = new Comment({ github, context, commentId }) 4 | 5 | if (testResult !== 'success') { 6 | return comment.createOrUpdateComment(` Test failed`) 7 | } 8 | 9 | const diffResult = await exec.exec('git diff --exit-code', null, { ignoreReturnCode: true }) 10 | 11 | if (!diffResult) { 12 | core.info('KNOWN_GOOD_BLOCK_NUMBERS.env not updated') 13 | return comment.createOrUpdateComment(` KNOWN_GOOD_BLOCK_NUMBERS.env not updated`) 14 | } 15 | 16 | await exec.exec(`git config --global user.name 'github-actions[bot]'`) 17 | await exec.exec(`git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'`) 18 | await exec.exec(`git add KNOWN_GOOD_BLOCK_NUMBERS.env`) 19 | await exec.exec(`git`, ['commit', '-am', '[ci skip] Update KNOWN_GOOD_BLOCK_NUMBERS']) 20 | await exec.exec('git push') 21 | 22 | let commitId = '' 23 | await exec.exec('git', ['rev-parse', 'HEAD'], { 24 | listeners: { 25 | stdout: (data) => { 26 | commitId += data.toString() 27 | }, 28 | }, 29 | }) 30 | 31 | return comment.createOrUpdateComment(`**KNOWN_GOOD_BLOCK_NUMBERS.env has been updated**
**Commit**: ${commitId}`) 32 | } 33 | -------------------------------------------------------------------------------- /.github/command-runner/runOrBump.cjs: -------------------------------------------------------------------------------- 1 | module.exports = async ({ github, core, context, commentId, exec, env, command, args }) => { 2 | const Comment = require('./comment.cjs') 3 | const comment = new Comment({ github, context, commentId }) 4 | const { runCommand, createResult, writeNewEnv } = require('./utils.cjs') 5 | 6 | const excuteUpdateKnownGood = async () => { 7 | const execCommand = `yarn update-known-good` 8 | const result = await runCommand({ cmd: execCommand, comment, exec }) 9 | 10 | if (result.exitCode) { 11 | core.setFailed('Failed to update known good blocks') 12 | await comment.createOrUpdateComment( 13 | createResult({ 14 | context, 15 | command: execCommand, 16 | result: `${result.errorOutput}\n${result.output}`, 17 | extra: `**Test Result**: \`Failed to update known good blocks\``, 18 | }), 19 | ) 20 | 21 | process.exit(1) 22 | } 23 | 24 | return result 25 | } 26 | 27 | const excuteTest = async ({ update, env }) => { 28 | const execCommand = update 29 | ? `yarn test --reporter default ${update ? '-u' : ''}` 30 | : `yarn test --reporter default ${args.trim()}` 31 | 32 | const result = await runCommand({ cmd: execCommand, comment, exec }) 33 | 34 | if (result.exitCode) { 35 | core.setFailed('Tests failed') 36 | await comment.createOrUpdateComment( 37 | createResult({ 38 | context, 39 | command: execCommand, 40 | result: `${env ? `${env}\n` : ''}${result.errorOutput}\n${result.output}`, 41 | extra: `**Test Result**: \`Failed\``, 42 | }), 43 | ) 44 | process.exit(1) 45 | } 46 | 47 | return result 48 | } 49 | 50 | if (command === 'run') { 51 | const updateKnownGoodResult = await excuteUpdateKnownGood() 52 | 53 | let newEnv = updateKnownGoodResult.output 54 | 55 | if (env) { 56 | newEnv = writeNewEnv({ env }) 57 | } 58 | 59 | const testResult = await excuteTest({ update: false, env: newEnv }) 60 | core.info('Tests Passed') 61 | const output = `${newEnv}\n${testResult.output}` 62 | return comment.createOrUpdateComment( 63 | createResult({ 64 | context, 65 | command: testResult.cmd, 66 | result: output, 67 | extra: `**Test Result**: \`Passed\``, 68 | }), 69 | ) 70 | } 71 | 72 | if (command === 'bump') { 73 | if (env.trim().length) { 74 | core.setFailed('env is not supported in bump command') 75 | return comment.createOrUpdateComment(` ENV is not supported in bump command`) 76 | } 77 | 78 | const updateKnownGoodResult = await excuteUpdateKnownGood() 79 | 80 | await exec.exec(`git config --global user.name 'github-actions[bot]'`) 81 | await exec.exec(`git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'`) 82 | await exec.exec(`git add KNOWN_GOOD_BLOCK_NUMBERS.env`) 83 | const diffCachedResult = await exec.exec('git diff --cached --exit-code', null, { ignoreReturnCode: true }) 84 | 85 | if (!diffCachedResult) { 86 | core.setFailed('KNOWN_GOOD_BLOCK_NUMBERS.env not updated') 87 | await comment.createOrUpdateComment(` **KNOWN_GOOD_BLOCK_NUMBERS.env not updated**`) 88 | process.exit(1) 89 | } 90 | 91 | const testResult = await excuteTest({ update: true, env: updateKnownGoodResult.output }) 92 | const output = `${updateKnownGoodResult.output}\n${testResult.output}` 93 | 94 | const diffResult = await exec.exec('git diff --exit-code', null, { ignoreReturnCode: true }) 95 | 96 | if (!diffResult) { 97 | core.info('snapshot not updated') 98 | // dispatch update-known-good workflow to having it to update the snapshot 99 | await github.rest.actions.createWorkflowDispatch({ 100 | owner: context.repo.owner, 101 | repo: context.repo.repo, 102 | workflow_id: 'update-known-good.yml', 103 | ref: 'master', 104 | }) 105 | 106 | return comment.createOrUpdateComment( 107 | createResult({ 108 | context, 109 | command: testResult.cmd, 110 | result: output, 111 | extra: `
Triggered update-known-good workflow to update the snapshot`, 112 | }), 113 | ) 114 | } 115 | const branchName = `Update-SnapShot-${commentId}` 116 | await exec.exec(`git checkout -b ${branchName}`) 117 | await exec.exec(`git`, ['commit', '-am', '[ci skip] Update snapshots']) 118 | 119 | const commentUrl = `https://github.com/${context.payload.repository.full_name}/issues/${context.issue.number}#issuecomment-${commentId}` 120 | await exec.exec(`git push origin HEAD:${branchName}`) 121 | const result = await github.rest.pulls.create({ 122 | owner: context.repo.owner, 123 | repo: context.repo.repo, 124 | title: branchName, 125 | head: branchName, 126 | base: 'master', 127 | body: `Update Snapshots (${commentUrl})`, 128 | }) 129 | core.info(`The Pull request #${result.data.number} has been created to update the snapshot`) 130 | return comment.createOrUpdateComment( 131 | createResult({ 132 | context, 133 | command: testResult.cmd, 134 | result: output, 135 | extra: `
**The Pull request #${result.data.number} has been created to update the snapshot**`, 136 | }), 137 | ) 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /.github/command-runner/utils.cjs: -------------------------------------------------------------------------------- 1 | function createResult({ command, context, result, extra }) { 2 | return `**Request**: \`${context.payload.comment.body.trim()}\` 3 | **Command**: \`${command}\` 4 | ${extra} 5 | 6 |
7 | Results 8 | 9 | \`\`\` 10 | ${result} 11 | \`\`\` 12 |
13 | ` 14 | } 15 | 16 | // biome-ignore lint/suspicious/noControlCharactersInRegex: 17 | const ansiEscapeRegex = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g 18 | 19 | async function runCommand({ cmd, comment, exec }) { 20 | let output = '' 21 | let errorOutput = '' 22 | await comment.createOrUpdateComment(`Running: \`${cmd}\``) 23 | 24 | const exitCode = await exec.exec(cmd, null, { 25 | ignoreReturnCode: true, 26 | listeners: { 27 | stdline: (data) => { 28 | output += `${data}\n` 29 | }, 30 | errline: (data) => { 31 | errorOutput += `${data}\n` 32 | }, 33 | }, 34 | }) 35 | 36 | return { 37 | output: output.replace(ansiEscapeRegex, ''), 38 | errorOutput: errorOutput.replace(ansiEscapeRegex, ''), 39 | exitCode, 40 | cmd, 41 | } 42 | } 43 | 44 | function writeNewEnv({ env }) { 45 | const fs = require('node:fs') 46 | 47 | const envContent = fs.readFileSync('KNOWN_GOOD_BLOCK_NUMBERS.env', 'utf8').toString() 48 | 49 | fs.writeFileSync('.env', env) 50 | return `# .env 51 | ${env} 52 | 53 | # KNOWN_GOOD_BLOCK_NUMBERS.env 54 | ${envContent} 55 | ` 56 | } 57 | 58 | module.exports = { 59 | createResult, 60 | runCommand, 61 | writeNewEnv, 62 | } 63 | -------------------------------------------------------------------------------- /.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/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | lint: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Use Node.js 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: 18.x 22 | cache: 'yarn' 23 | - run: yarn --immutable 24 | - run: yarn lint 25 | define-matrix: 26 | runs-on: ubuntu-latest 27 | outputs: 28 | tests: ${{ steps.tests.outputs.tests }} 29 | steps: 30 | - uses: actions/checkout@v4 31 | - name: Define Tests 32 | id: tests 33 | run: | 34 | echo tests=$(cd packages && ls */src/*.test.ts | jq -R -s -c 'split("\n")[:-1]') >> "$GITHUB_OUTPUT" 35 | tests: 36 | needs: define-matrix 37 | timeout-minutes: 30 38 | strategy: 39 | fail-fast: false 40 | matrix: 41 | tests: ${{ fromJSON(needs.define-matrix.outputs.tests) }} 42 | runs-on: ubuntu-latest 43 | steps: 44 | - uses: actions/checkout@v4 45 | - name: setup node env 46 | uses: actions/setup-node@v4 47 | with: 48 | node-version: 18.x 49 | cache: 'yarn' 50 | - run: yarn --immutable 51 | - run: yarn test packages/${{ matrix.tests }} 52 | all-passed: 53 | runs-on: ubuntu-latest 54 | needs: tests 55 | if: always() 56 | steps: 57 | - name: All tests ok 58 | if: ${{ !(contains(needs.*.result, 'failure')) }} 59 | run: exit 0 60 | - name: Some tests failed 61 | if: ${{ contains(needs.*.result, 'failure') }} 62 | run: exit 1 63 | -------------------------------------------------------------------------------- /.github/workflows/command-runner.yml: -------------------------------------------------------------------------------- 1 | name: Command Runner Bot 2 | 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | jobs: 8 | check: 9 | outputs: 10 | result: ${{ steps.check_permission.outputs.result }} 11 | command: ${{ fromJson(steps.check_permission.outputs.result).command }} 12 | runs-on: ubuntu-latest 13 | if: ${{ startsWith(github.event.comment.body, '/bot') }} 14 | 15 | steps: 16 | - name: Check Permission 17 | id: check_permission 18 | uses: actions/github-script@v7 19 | with: 20 | script: | 21 | const payload = context.payload 22 | const content = payload.comment ? payload.comment.body : '' 23 | console.log(`content: ${content}`) 24 | const lines = content.split('\n').map(line => line.trim()).filter(line => line.length > 0); 25 | const [params, ...env] = lines; 26 | const [, command, ...args] = params.split(/\s+/) 27 | const actionUrl = `https://github.com/${ context.payload.repository.full_name }/actions/runs/${ context.runId }` 28 | const { data: file } = await github.rest.repos.getContent({ 29 | owner: context.repo.owner, 30 | repo: context.repo.repo, 31 | path: '.github/command-runner/command-runner-config.json', 32 | ref: 'master' 33 | }); 34 | 35 | const config = JSON.parse(Buffer.from(file.content, 'base64').toString('utf8')); 36 | 37 | let errorMsg = '' 38 | if (!Object.keys(config).includes(command)) { 39 | errorMsg = `Invalid command` 40 | } else if (['merge', 'cancel-merge'].includes(command) && !payload.issue.pull_request) { 41 | errorMsg = `This command is only supported in pull requests` 42 | } else if (config[command].allowed_users) { 43 | const user = payload.comment.user.login 44 | if (!config[command].allowed_users.includes(user)) { 45 | errorMsg = `No permission to run this command` 46 | } 47 | } else if (config[command].allowed_issues) { 48 | const issueNumber = payload.issue.number 49 | if (!config[command].allowed_issues.includes(issueNumber)) { 50 | errorMsg = `Need to run this command in the specified issue` 51 | } 52 | } 53 | 54 | if (errorMsg) { 55 | core.error(`errorMsg: ${errorMsg}`) 56 | await github.rest.issues.createComment({ 57 | issue_number: context.issue.number, 58 | owner: context.repo.owner, 59 | repo: context.repo.repo, 60 | body: ` ${errorMsg}` 61 | }) 62 | return { error: errorMsg } 63 | } 64 | 65 | console.log(`command: ${command}, args: ${args.join(' ')}, env: ${env.join('\n')}`) 66 | 67 | const result = await github.rest.issues.createComment({ 68 | issue_number: context.issue.number, 69 | owner: context.repo.owner, 70 | repo: context.repo.repo, 71 | body: ` Running...` + `\n[view details](${actionUrl})` 72 | }) 73 | 74 | return { command, args: args.join(' '), env: env.join('\n'), commentId: result.data.id }; 75 | 76 | merge: 77 | needs: check 78 | if: ${{ needs.check.outputs.command == 'merge' || needs.check.outputs.command == 'cancel-merge' }} 79 | runs-on: ubuntu-latest 80 | steps: 81 | - uses: actions/checkout@v4 82 | - uses: actions/github-script@v7 83 | with: 84 | script: | 85 | const script = require('.github/command-runner/merge.cjs') 86 | const { command, commentId } = ${{ needs.check.outputs.result }} 87 | await script({ github, context, core, command, commentId }) 88 | run-or-bump: 89 | needs: check 90 | if: ${{ needs.check.outputs.command == 'run' || needs.check.outputs.command == 'bump' }} 91 | runs-on: ubuntu-latest 92 | steps: 93 | - id: ref 94 | uses: actions/github-script@v7 95 | with: 96 | script: | 97 | return !context.payload.issue.pull_request ? 98 | 'master' : 99 | (await github.rest.pulls.get({ 100 | ...context.repo, 101 | pull_number: context.payload.issue.number 102 | })).data.head.ref 103 | result-encoding: string 104 | - uses: actions/checkout@v4 105 | with: 106 | ref: ${{ steps.ref.outputs.result }} 107 | - name: setup node env 108 | uses: actions/setup-node@v4 109 | with: 110 | node-version: 18.x 111 | cache: 'yarn' 112 | - run: yarn --immutable 113 | - uses: actions/create-github-app-token@v1 114 | id: app-token 115 | with: 116 | app-id: ${{ secrets.GH_APP_ID }} 117 | private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} 118 | - uses: actions/github-script@v7 119 | with: 120 | github-token: ${{ steps.app-token.outputs.token }} 121 | script: | 122 | const script = require('.github/command-runner/runOrBump.cjs') 123 | const { command, args, env, commentId } = ${{ needs.check.outputs.result }} 124 | await script({ github, core, context, io, exec, command, args, env, commentId }) 125 | -------------------------------------------------------------------------------- /.github/workflows/notifications.json: -------------------------------------------------------------------------------- 1 | { 2 | "assetHubKusama": 129, 3 | "karura": 130, 4 | "basilisk": 131, 5 | "coretimeKusama": 132, 6 | "kusama": 133, 7 | "shiden": 134, 8 | "people": 135, 9 | "acala": 136, 10 | "assetHubPolkadot": 137, 11 | "astar": 138, 12 | "moonbeam": 139, 13 | "polkadot": 140, 14 | "coretimePolkadot": 141, 15 | "hydration": 142, 16 | "collectivesPolkadot": 192, 17 | "bridgeHubPolkadot": 207, 18 | "bridgeHubKusama": 208, 19 | "unknown": 143 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/update-known-good.yml: -------------------------------------------------------------------------------- 1 | name: Update Known Good Block Numbers 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | retry: 7 | description: 'If this is a retry run' 8 | required: false 9 | type: boolean 10 | failed_tests: 11 | description: 'Failed tests to retry (JSON array)' 12 | required: false 13 | type: string 14 | schedule: 15 | - cron: '0 */6 * * *' 16 | 17 | env: 18 | GH_TOKEN: ${{ github.token }} 19 | 20 | permissions: 21 | contents: write 22 | pull-requests: write 23 | actions: write 24 | issues: write 25 | 26 | jobs: 27 | define-matrix: 28 | runs-on: ubuntu-latest 29 | outputs: 30 | tests: ${{ steps.tests.outputs.tests }} 31 | steps: 32 | - uses: actions/checkout@v4 33 | - name: setup node env 34 | uses: actions/setup-node@v4 35 | with: 36 | node-version: 18.x 37 | cache: 'yarn' 38 | - run: yarn --immutable 39 | - name: Define Tests 40 | id: tests 41 | run: | 42 | if [ "${{ github.event.inputs.retry }}" == "true" ]; then 43 | echo "tests=$(echo '${{ github.event.inputs.failed_tests }}' | sed 's/^"\(.*\)"$/\1/')" >> "$GITHUB_OUTPUT" 44 | else 45 | echo tests=$(cd packages && ls */src/*.test.ts | jq -R -s -c 'split("\n")[:-1]') >> "$GITHUB_OUTPUT" 46 | fi 47 | - name: Update Known Good Block Numbers 48 | run: | 49 | yarn update-known-good 50 | - name: Upload Artifact 51 | uses: actions/upload-artifact@v4 52 | with: 53 | name: KNOWN_GOOD_BLOCK_NUMBERS.env 54 | path: KNOWN_GOOD_BLOCK_NUMBERS.env 55 | retention-days: 1 56 | tests: 57 | needs: define-matrix 58 | timeout-minutes: 30 59 | strategy: 60 | fail-fast: false 61 | matrix: 62 | tests: ${{ fromJSON(needs.define-matrix.outputs.tests) }} 63 | runs-on: ubuntu-latest 64 | steps: 65 | - uses: actions/checkout@v4 66 | - name: setup node env 67 | uses: actions/setup-node@v4 68 | with: 69 | node-version: 18.x 70 | cache: 'yarn' 71 | - run: yarn --immutable 72 | - name: Download a single artifact 73 | uses: actions/download-artifact@v4 74 | with: 75 | name: KNOWN_GOOD_BLOCK_NUMBERS.env 76 | - run: yarn test packages/${{ matrix.tests }} 77 | save: 78 | needs: tests 79 | runs-on: ubuntu-latest 80 | if: success() && github.event.inputs.retry != 'true' 81 | steps: 82 | - uses: actions/create-github-app-token@v1 83 | id: app-token 84 | with: 85 | app-id: ${{ secrets.GH_APP_ID }} 86 | private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} 87 | - uses: actions/checkout@v4 88 | with: 89 | token: ${{ steps.app-token.outputs.token }} 90 | - name: Download a single artifact 91 | uses: actions/download-artifact@v4 92 | with: 93 | name: KNOWN_GOOD_BLOCK_NUMBERS.env 94 | - name: Commit and push changes 95 | run: | 96 | git config --global user.name 'github-actions[bot]' 97 | git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com' 98 | git add KNOWN_GOOD_BLOCK_NUMBERS.env 99 | if ! git diff --cached --quiet; then 100 | git commit -m "[ci skip] Update KNOWN_GOOD_BLOCK_NUMBERS" 101 | git push 102 | else 103 | echo "No changes to commit" 104 | fi 105 | schedule-retry: 106 | needs: tests 107 | if: failure() && github.event.inputs.retry != 'true' 108 | runs-on: ubuntu-latest 109 | steps: 110 | - name: Get failed jobs 111 | id: get-failed 112 | uses: actions/github-script@v7 113 | with: 114 | script: | 115 | const response = await github.paginate( 116 | github.rest.actions.listJobsForWorkflowRun, 117 | { 118 | owner: context.repo.owner, 119 | repo: context.repo.repo, 120 | run_id: context.runId 121 | } 122 | ); 123 | 124 | const failedTests = response 125 | .filter(job => job.name.startsWith('tests (') && job.conclusion === 'failure') 126 | .map(job => { 127 | const match = job.name.match(/tests \((.*)\)/); 128 | return match ? match[1] : null; 129 | }) 130 | .filter(Boolean); 131 | 132 | return JSON.stringify(failedTests); 133 | - name: sleep 134 | run: sleep 300 135 | - name: Dispatch retry workflow 136 | uses: actions/github-script@v7 137 | with: 138 | script: | 139 | await github.rest.actions.createWorkflowDispatch({ 140 | owner: context.repo.owner, 141 | repo: context.repo.repo, 142 | workflow_id: 'update-known-good.yml', 143 | ref: 'master', 144 | inputs: { 145 | retry: 'true', 146 | failed_tests: '${{ steps.get-failed.outputs.result }}' 147 | } 148 | }) 149 | notify: 150 | needs: tests 151 | if: failure() && github.event.inputs.retry == 'true' 152 | runs-on: ubuntu-latest 153 | steps: 154 | - name: Create Comment 155 | uses: actions/github-script@v7 156 | with: 157 | script: | 158 | const response = await github.paginate( 159 | github.rest.actions.listJobsForWorkflowRun, 160 | { 161 | owner: context.repo.owner, 162 | repo: context.repo.repo, 163 | run_id: context.runId 164 | }, 165 | ); 166 | 167 | const failedTests = response 168 | .filter(job => job.name.startsWith('tests (') && job.conclusion === 'failure') 169 | .map(job => { 170 | const match = job.name.match(/tests \((.*)\)/); 171 | return match ? match[1] : null; 172 | }) 173 | .filter(Boolean); 174 | 175 | const impactedNetworks = new Set() 176 | const regex = /(\w+)\.(\w+)?(\.\w+)?\.test/ 177 | for (const test of failedTests) { 178 | const match = test.match(regex) 179 | if (match) { 180 | impactedNetworks.add(match[1]) 181 | if (match[2] && match[2] !== "e2e" && match[3] !== ".e2e") { 182 | impactedNetworks.add(match[2]) 183 | } 184 | } else { 185 | impactedNetworks.add("unknown") 186 | } 187 | } 188 | 189 | const { data: config } = await github.rest.repos.getContent({ 190 | owner: context.repo.owner, 191 | repo: context.repo.repo, 192 | path: '.github/workflows/notifications.json', 193 | ref: 'master' 194 | }) 195 | 196 | const notifications = JSON.parse(Buffer.from(config.content, 'base64').toString('utf8')) 197 | 198 | const issuesToNotify = new Set() 199 | for (const network of impactedNetworks) { 200 | issuesToNotify.add(notifications[network] ?? notifications['unknown']) 201 | } 202 | 203 | for (const issueNumber of issuesToNotify) { 204 | // add a comment to the issue 205 | await github.rest.issues.createComment({ 206 | issue_number: issueNumber, 207 | owner: context.repo.owner, 208 | repo: context.repo.repo, 209 | body: `Workflow failed: https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` 210 | }) 211 | } 212 | -------------------------------------------------------------------------------- /.github/workflows/update-snapshot.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 | GH_TOKEN: ${{ github.token }} 12 | 13 | jobs: 14 | update: 15 | runs-on: ubuntu-latest 16 | timeout-minutes: 90 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: setup node env 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: 18.x 23 | cache: 'yarn' 24 | - run: yarn --immutable 25 | - run: yarn update-known-good 26 | - run: yarn test -u 27 | - name: Commit and Create PR 28 | uses: actions/github-script@v6 29 | with: 30 | script: | 31 | const branchName = `update-snapshots-${context.sha.slice(0, 7)}` 32 | await exec.exec(`git config --global user.name 'github-actions[bot]'`) 33 | await exec.exec(`git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'"`) 34 | await exec.exec(`git checkout -b ${branchName}`) 35 | await exec.exec(`git`, ['commit', '-am', 'update snapshots']) 36 | await exec.exec(`git push origin HEAD:${branchName}`) 37 | await github.rest.pulls.create({ 38 | owner: context.repo.owner, 39 | repo: context.repo.repo, 40 | title: 'Update Snapshots', 41 | head: branchName, 42 | base: 'master', 43 | body: 'Update Snapshots\n\nClose and reopen this PR to trigger CI.', 44 | }) 45 | -------------------------------------------------------------------------------- /.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 | 3 | npx lint-staged 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # registry=https://registry.npmmirror.com 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .yarn 2 | *.yml 3 | *.md 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "[typescript]": { 4 | "editor.defaultFormatter": "esbenp.prettier-vscode" 5 | }, 6 | "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"] 7 | } 8 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | yarnPath: .yarn/releases/yarn-4.9.1.cjs 4 | -------------------------------------------------------------------------------- /KNOWN_GOOD_BLOCK_NUMBERS.env: -------------------------------------------------------------------------------- 1 | ACALA_BLOCK_NUMBER=8771351 2 | ASSETHUBKUSAMA_BLOCK_NUMBER=9608884 3 | ASSETHUBPOLKADOT_BLOCK_NUMBER=9023064 4 | ASTAR_BLOCK_NUMBER=8912270 5 | BASILISK_BLOCK_NUMBER=9795062 6 | BRIDGEHUBKUSAMA_BLOCK_NUMBER=5884081 7 | BRIDGEHUBPOLKADOT_BLOCK_NUMBER=5338577 8 | COLLECTIVESPOLKADOT_BLOCK_NUMBER=6526666 9 | CORETIMEKUSAMA_BLOCK_NUMBER=2878950 10 | CORETIMEPOLKADOT_BLOCK_NUMBER=1958340 11 | HYDRATION_BLOCK_NUMBER=7836822 12 | KARURA_BLOCK_NUMBER=9320795 13 | KUSAMA_BLOCK_NUMBER=28711636 14 | MOONBEAM_BLOCK_NUMBER=11222747 15 | MOONRIVER_BLOCK_NUMBER=11905654 16 | PEOPLEKUSAMA_BLOCK_NUMBER=4451184 17 | PEOPLEPOLKADOT_BLOCK_NUMBER=2284886 18 | POLKADOT_BLOCK_NUMBER=26367190 19 | SHIDEN_BLOCK_NUMBER=10576460 20 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", 3 | "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true }, 4 | "files": { 5 | "ignoreUnknown": false, 6 | "ignore": [ 7 | "*.json", 8 | "*.txt", 9 | "*.snap", 10 | "*.wasm", 11 | "*.html", 12 | "*.md", 13 | "*.gitignore", 14 | "*.yml", 15 | "*.tsbuildinfo", 16 | "**/node_modules/**" 17 | ] 18 | }, 19 | "formatter": { 20 | "enabled": true, 21 | "useEditorconfig": true, 22 | "formatWithErrors": false, 23 | "indentStyle": "tab", 24 | "indentWidth": 2, 25 | "lineEnding": "lf", 26 | "lineWidth": 120, 27 | "attributePosition": "auto", 28 | "bracketSpacing": true, 29 | "ignore": ["**/tsconfig.tsbuildinfo", "**/.gitignore", "**/.yarn", "**/*.yml", "**/*.md", "**/node_modules/**"] 30 | }, 31 | "organizeImports": { "enabled": true }, 32 | "linter": { 33 | "enabled": true, 34 | "rules": { 35 | "recommended": true, 36 | "suspicious": { 37 | "noExplicitAny": "off", 38 | "noAssignInExpressions": "off" 39 | }, 40 | "style": { 41 | "noUnusedTemplateLiteral": "off", 42 | "noNonNullAssertion": "off", 43 | "noParameterAssign": "off" 44 | }, 45 | "complexity": { 46 | "noForEach": "off", 47 | "useLiteralKeys": "off" 48 | } 49 | }, 50 | "ignore": ["**/node_modules/"] 51 | }, 52 | "javascript": { 53 | "formatter": { 54 | "jsxQuoteStyle": "double", 55 | "quoteProperties": "asNeeded", 56 | "trailingCommas": "all", 57 | "semicolons": "asNeeded", 58 | "arrowParentheses": "always", 59 | "bracketSameLine": false, 60 | "quoteStyle": "single", 61 | "attributePosition": "auto", 62 | "bracketSpacing": true 63 | } 64 | }, 65 | "overrides": [ 66 | { 67 | "include": ["**/*.test.ts", "packages/web-test"], 68 | "linter": { 69 | "rules": { 70 | "style": { 71 | "noNonNullAssertion": "off" 72 | } 73 | } 74 | } 75 | } 76 | ] 77 | } 78 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js' 2 | import tsParser from '@typescript-eslint/parser' 3 | import eslintConfigPrettier from 'eslint-config-prettier' 4 | import eslintPluginImportX from 'eslint-plugin-import-x' 5 | import tseslint from 'typescript-eslint' 6 | 7 | export default tseslint.config( 8 | js.configs.recommended, 9 | tseslint.configs.strict, 10 | tseslint.configs.stylistic, 11 | eslintPluginImportX.flatConfigs.recommended, 12 | eslintPluginImportX.flatConfigs.typescript, 13 | eslintConfigPrettier, 14 | { 15 | languageOptions: { 16 | parser: tsParser, 17 | ecmaVersion: 'latest', 18 | sourceType: 'module', 19 | parserOptions: { 20 | projectService: true, 21 | tsconfigRootDir: import.meta.dirname, 22 | }, 23 | }, 24 | rules: { 25 | '@typescript-eslint/no-empty-function': 'off', 26 | '@typescript-eslint/explicit-module-boundary-types': 'off', 27 | '@typescript-eslint/no-explicit-any': 'off', 28 | '@typescript-eslint/ban-ts-comment': 'off', 29 | '@typescript-eslint/no-non-null-assertion': 'off', 30 | 31 | '@typescript-eslint/no-unused-vars': [ 32 | 'warn', 33 | { 34 | argsIgnorePattern: '^_', 35 | varsIgnorePattern: '^_', 36 | caughtErrorsIgnorePattern: '^_', 37 | }, 38 | ], 39 | }, 40 | }, 41 | { 42 | ignores: [ 43 | 'eslint.config.mjs', 44 | '**/node_modules/', 45 | '**/vitest.config.mts', 46 | '.yarn/', 47 | '.github/command-runner/', // TODO: enable lint for those files 48 | ], 49 | }, 50 | ) 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e2e-tests", 3 | "private": true, 4 | "scripts": { 5 | "lint": "tsc --noEmit && biome check .", 6 | "fix": "biome check --write .", 7 | "test": "vitest", 8 | "test:ui": "vitest --ui", 9 | "update-env": "tsx scripts/update-env.ts", 10 | "update-known-good": "tsx scripts/update-env.ts --update-known-good", 11 | "postinstall": "husky install", 12 | "check-proxy-coverage": "tsx scripts/check-proxy-coverage.ts" 13 | }, 14 | "type": "module", 15 | "workspaces": [ 16 | "packages/*" 17 | ], 18 | "resolutions": { 19 | "@polkadot/api": "^15.0", 20 | "@polkadot/api-augment": "^15.0", 21 | "@polkadot/api-derive": "^15.0", 22 | "@polkadot/rpc-augment": "^15.0", 23 | "@polkadot/rpc-core": "^15.0", 24 | "@polkadot/rpc-provider": "^15.0", 25 | "@polkadot/types": "^15.0", 26 | "@polkadot/types-augment": "^15.0", 27 | "@polkadot/types-codec": "^15.0", 28 | "@polkadot/types-create": "^15.0", 29 | "@polkadot/types-known": "^15.0" 30 | }, 31 | "packageManager": "yarn@4.9.1", 32 | "dependencies": { 33 | "@e2e-test/networks": "workspace:*", 34 | "@swc/core": "^1.11.24", 35 | "lodash": "^4.17.21", 36 | "ts-pattern": "^5.7.0", 37 | "typescript": "^5.8.3", 38 | "vitest": "^3.1.4" 39 | }, 40 | "devDependencies": { 41 | "@biomejs/biome": "1.9.4", 42 | "@types/lodash": "^4.17.17", 43 | "@types/node": "^22.15.29", 44 | "@vitest/ui": "^3.1.3", 45 | "dotenv": "^16.5.0", 46 | "husky": "^9.1.7", 47 | "lint-staged": "^16.1.0", 48 | "tsx": "^4.19.4", 49 | "unplugin-swc": "^1.5.4", 50 | "vite-tsconfig-paths": "^5.1.4" 51 | }, 52 | "lint-staged": { 53 | "*.{js,ts}": "biome check --write --no-errors-on-unmatched" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/kusama/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@e2e-test/kusama", 3 | "type": "module", 4 | "dependencies": { 5 | "@acala-network/chopsticks-testing": "^1.0.6", 6 | "@e2e-test/shared": "workspace:*" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/kusama/src/__snapshots__/assetHubKusama.vesting.e2e.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`Kusama Asset Hub Vesting > signed-origin force-vested transfer fails > force vest events 1`] = ` 4 | [ 5 | { 6 | "data": { 7 | "dispatchError": "BadOrigin", 8 | "dispatchInfo": { 9 | "class": "Normal", 10 | "paysFee": "Yes", 11 | "weight": { 12 | "proofSize": "(rounded 18000)", 13 | "refTime": "(rounded 1200000000)", 14 | }, 15 | }, 16 | }, 17 | "method": "ExtrinsicFailed", 18 | "section": "system", 19 | }, 20 | ] 21 | `; 22 | -------------------------------------------------------------------------------- /packages/kusama/src/__snapshots__/kusama.vesting.e2e.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`Kusama Vesting > forced vested transfer and forced removal of vesting schedule work > forced vested transfer event 1`] = ` 4 | [ 5 | "DfnTB4z7eUvYRqcGtTpFsLC69o6tvBSC1pEv8vWPZFtCkaK", 6 | 16666666650, 7 | ] 8 | `; 9 | 10 | exports[`Kusama Vesting > forced vested transfer and forced removal of vesting schedule work > forced vesting removal event 1`] = ` 11 | [ 12 | "DfnTB4z7eUvYRqcGtTpFsLC69o6tvBSC1pEv8vWPZFtCkaK", 13 | ] 14 | `; 15 | 16 | exports[`Kusama Vesting > signed-origin force-vested transfer fails > force vest events 1`] = ` 17 | [ 18 | { 19 | "data": { 20 | "dispatchError": "BadOrigin", 21 | "dispatchInfo": { 22 | "class": "Normal", 23 | "paysFee": "Yes", 24 | "weight": { 25 | "proofSize": "(rounded 13000)", 26 | "refTime": "(rounded 1100000000)", 27 | }, 28 | }, 29 | }, 30 | "method": "ExtrinsicFailed", 31 | "section": "system", 32 | }, 33 | ] 34 | `; 35 | 36 | exports[`Kusama Vesting > test merger of two vesting schedules > vesting events 1 1`] = ` 37 | [ 38 | { 39 | "data": { 40 | "account": "HnMAUz7r2G8G3hB27SYNyit5aJmh2a5P4eMdDtACtMFDbam", 41 | "unvested": "(rounded 85000000000)", 42 | }, 43 | "method": "VestingUpdated", 44 | "section": "vesting", 45 | }, 46 | ] 47 | `; 48 | 49 | exports[`Kusama Vesting > test merger of two vesting schedules > vesting events 2 1`] = ` 50 | [ 51 | { 52 | "data": { 53 | "account": "HnMAUz7r2G8G3hB27SYNyit5aJmh2a5P4eMdDtACtMFDbam", 54 | "unvested": "(rounded 250000000000)", 55 | }, 56 | "method": "VestingUpdated", 57 | "section": "vesting", 58 | }, 59 | ] 60 | `; 61 | 62 | exports[`Kusama Vesting > test merger of two vesting schedules > vesting schedules merger events 1`] = ` 63 | [ 64 | { 65 | "data": { 66 | "account": "HnMAUz7r2G8G3hB27SYNyit5aJmh2a5P4eMdDtACtMFDbam", 67 | "unvested": "(rounded 230000000000)", 68 | }, 69 | "method": "VestingUpdated", 70 | "section": "vesting", 71 | }, 72 | ] 73 | `; 74 | 75 | exports[`Kusama Vesting > vesting schedule lifecycle > vest events 1`] = ` 76 | [ 77 | { 78 | "data": { 79 | "account": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", 80 | "unvested": "(rounded 17000000000)", 81 | }, 82 | "method": "VestingUpdated", 83 | "section": "vesting", 84 | }, 85 | ] 86 | `; 87 | 88 | exports[`Kusama Vesting > vesting schedule lifecycle > vest events 2`] = ` 89 | [ 90 | { 91 | "data": { 92 | "account": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", 93 | }, 94 | "method": "VestingCompleted", 95 | "section": "vesting", 96 | }, 97 | ] 98 | `; 99 | 100 | exports[`Kusama Vesting > vesting schedule lifecycle > vest other events 1`] = ` 101 | [ 102 | { 103 | "data": { 104 | "account": "FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP", 105 | "unvested": "(rounded 8300000000)", 106 | }, 107 | "method": "VestingUpdated", 108 | "section": "vesting", 109 | }, 110 | ] 111 | `; 112 | -------------------------------------------------------------------------------- /packages/kusama/src/assetHubKusama.bridgeHubKusama.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { assetHubKusama, bridgeHubKusama } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 8 | 9 | describe('assetHubKusama & bridgeHubKusama', async () => { 10 | const [assetHubKusamaClient, bridgeHubKusamaClient] = await setupNetworks(assetHubKusama, bridgeHubKusama) 11 | 12 | const bridgeHubKSM = bridgeHubKusama.custom.ksm 13 | const assetHubKSM = assetHubKusama.custom.ksm 14 | 15 | runXcmPalletDown('assetHubKusama transfer KSM to bridgeHubKusama', async () => { 16 | return { 17 | fromChain: assetHubKusamaClient, 18 | toChain: bridgeHubKusamaClient, 19 | balance: query.balances, 20 | toAccount: defaultAccounts.dave, 21 | tx: tx.xcmPallet.limitedTeleportAssets(assetHubKSM, 1e12, tx.xcmPallet.parachainV3(1, bridgeHubKusama.paraId!)), 22 | } 23 | }) 24 | 25 | runXcmPalletUp('bridgeHubKusama transfer KSM to assetHubKusama', async () => { 26 | return { 27 | fromChain: bridgeHubKusamaClient, 28 | toChain: assetHubKusamaClient, 29 | balance: query.balances, 30 | toAccount: defaultAccounts.dave, 31 | tx: tx.xcmPallet.limitedTeleportAssets( 32 | bridgeHubKSM, 33 | 1e12, 34 | tx.xcmPallet.parachainV3(1, assetHubKusamaClient.config.paraId!), 35 | ), 36 | } 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /packages/kusama/src/assetHubKusama.coretimeKusama.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { assetHubKusama, coretimeKusama } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 8 | 9 | describe('assetHubKusama & coretimeKusama', async () => { 10 | const [assetHubKusamaClient, coretimeKusamaClient] = await setupNetworks(assetHubKusama, coretimeKusama) 11 | 12 | const coretimeKSM = coretimeKusama.custom.ksm 13 | const assetHubKSM = assetHubKusama.custom.ksm 14 | 15 | runXcmPalletDown('assetHubKusama transfer KSM to coretimeKusama', async () => { 16 | return { 17 | fromChain: assetHubKusamaClient, 18 | toChain: coretimeKusamaClient, 19 | balance: query.balances, 20 | toAccount: defaultAccounts.dave, 21 | tx: tx.xcmPallet.limitedTeleportAssets(assetHubKSM, 1e12, tx.xcmPallet.parachainV3(1, coretimeKusama.paraId!)), 22 | } 23 | }) 24 | 25 | runXcmPalletUp('coretimeKusama transfer KSM to assetHubKusama', async () => { 26 | return { 27 | fromChain: coretimeKusamaClient, 28 | toChain: assetHubKusamaClient, 29 | balance: query.balances, 30 | toAccount: defaultAccounts.dave, 31 | tx: tx.xcmPallet.limitedTeleportAssets( 32 | coretimeKSM, 33 | 1e12, 34 | tx.xcmPallet.parachainV3(1, assetHubKusamaClient.config.paraId!), 35 | ), 36 | } 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /packages/kusama/src/assetHubKusama.karura.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { assetHubKusama, karura } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletHorizontal, runXtokenstHorizontal } from '@e2e-test/shared/xcm' 8 | 9 | describe('assetHubKusama & karura', async () => { 10 | const [assetHubKusamaClient, karuraClient] = await setupNetworks(assetHubKusama, karura) 11 | 12 | const assetHubKusamaUsdt = assetHubKusama.custom.usdtIndex 13 | const karuraUsdt = karura.custom.usdt 14 | 15 | runXcmPalletHorizontal('assetHubKusama transfer USDT to karura', async () => { 16 | return { 17 | fromChain: assetHubKusamaClient, 18 | toChain: karuraClient, 19 | fromBalance: query.assets(assetHubKusamaUsdt), 20 | toBalance: query.tokens(karuraUsdt), 21 | tx: tx.xcmPallet.limitedReserveTransferAssetsV3( 22 | assetHubKusama.custom.usdt, 23 | 1e6, 24 | tx.xcmPallet.parachainV3(1, karura.paraId!), 25 | ), 26 | } 27 | }) 28 | 29 | runXtokenstHorizontal('karura transfer USDT to assetHubKusama', async () => { 30 | await karuraClient.dev.setStorage({ 31 | Tokens: { 32 | Accounts: [[[defaultAccounts.alice.address, karuraUsdt], { free: 10e6 }]], 33 | }, 34 | }) 35 | 36 | return { 37 | fromChain: karuraClient, 38 | toChain: assetHubKusamaClient, 39 | fromBalance: query.tokens(karuraUsdt), 40 | toBalance: query.assets(assetHubKusamaUsdt), 41 | tx: tx.xtokens.transfer(karuraUsdt, 1e6, tx.xtokens.parachainV4(assetHubKusama.paraId!)), 42 | precision: 1, 43 | } 44 | }) 45 | }) 46 | -------------------------------------------------------------------------------- /packages/kusama/src/assetHubKusama.kusama.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { assetHubKusama, kusama } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 8 | 9 | describe('kusama & assetHubKusama', async () => { 10 | const [kusamaClient, assetHubClient] = await setupNetworks(kusama, assetHubKusama) 11 | 12 | const assetHubKSM = assetHubKusama.custom.ksm 13 | const kusamaKSM = kusama.custom.ksm 14 | 15 | runXcmPalletDown('kusama transfer KSM to assetHubKusama', async () => { 16 | return { 17 | fromChain: kusamaClient, 18 | toChain: assetHubClient, 19 | balance: query.balances, 20 | toAccount: defaultAccounts.dave, 21 | tx: tx.xcmPallet.teleportAssetsV3(kusamaKSM, 1e12, tx.xcmPallet.parachainV3(0, assetHubKusama.paraId!)), 22 | totalIssuanceProvider: () => query.totalIssuance(kusamaClient), 23 | } 24 | }) 25 | 26 | runXcmPalletUp('assetHubKusama transfer KSM to kusama', async () => { 27 | return { 28 | fromChain: assetHubClient, 29 | toChain: kusamaClient, 30 | balance: query.balances, 31 | toAccount: defaultAccounts.dave, 32 | tx: tx.xcmPallet.teleportAssetsV3(assetHubKSM, 1e12, tx.xcmPallet.relaychainV4), 33 | totalIssuanceProvider: () => query.totalIssuance(kusamaClient), 34 | } 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /packages/kusama/src/assetHubKusama.peopleKusama.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { assetHubKusama, peopleKusama } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 8 | 9 | describe('assetHubKusama & peopleKusama', async () => { 10 | const [assetHubKusamaClient, peopleClient] = await setupNetworks(assetHubKusama, peopleKusama) 11 | 12 | const peopleKSM = peopleKusama.custom.ksm 13 | const kusamaKSM = assetHubKusama.custom.ksm 14 | 15 | runXcmPalletDown('assetHubKusama transfer KSM to peopleKusama', async () => { 16 | return { 17 | fromChain: assetHubKusamaClient, 18 | toChain: peopleClient, 19 | balance: query.balances, 20 | toAccount: defaultAccounts.dave, 21 | tx: tx.xcmPallet.limitedTeleportAssets(kusamaKSM, 1e12, tx.xcmPallet.parachainV3(1, peopleKusama.paraId!)), 22 | } 23 | }) 24 | 25 | runXcmPalletUp('peopleKusama transfer KSM to assetHubKusama', async () => { 26 | return { 27 | fromChain: peopleClient, 28 | toChain: assetHubKusamaClient, 29 | balance: query.balances, 30 | toAccount: defaultAccounts.dave, 31 | tx: tx.xcmPallet.limitedTeleportAssets( 32 | peopleKSM, 33 | 1e12, 34 | tx.xcmPallet.parachainV3(1, assetHubKusamaClient.config.paraId!), 35 | ), 36 | } 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /packages/kusama/src/assetHubKusama.proxy.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { assetHubKusama } from '@e2e-test/networks/chains' 2 | 3 | import { proxyE2ETests } from '@e2e-test/shared' 4 | import { AssetHubProxyTypes } from '@e2e-test/shared' 5 | 6 | proxyE2ETests(assetHubKusama, { testSuiteName: 'Kusama AssetHub Proxy', addressEncoding: 2 }, AssetHubProxyTypes) 7 | -------------------------------------------------------------------------------- /packages/kusama/src/assetHubKusama.scheduler.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { kusama } from '@e2e-test/networks/chains' 2 | 3 | import { schedulerE2ETests } from '@e2e-test/shared' 4 | 5 | schedulerE2ETests(kusama, { testSuiteName: 'Asset Hub Kusama Scheduler E2E tests', addressEncoding: 2 }) 6 | -------------------------------------------------------------------------------- /packages/kusama/src/assetHubKusama.vesting.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { assetHubKusama } from '@e2e-test/networks/chains' 2 | 3 | import { vestingE2ETests } from '@e2e-test/shared' 4 | 5 | vestingE2ETests(assetHubKusama, { testSuiteName: 'Kusama Asset Hub Vesting', addressEncoding: 2 }) 6 | -------------------------------------------------------------------------------- /packages/kusama/src/basilisk.karura.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { basilisk, karura, kusama } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXtokenstHorizontal } from '@e2e-test/shared/xcm' 8 | 9 | describe('basilisk & karura', async () => { 10 | const [karuraClient, basiliskClient, kusamaClient] = await setupNetworks(karura, basilisk, kusama) 11 | 12 | runXtokenstHorizontal('karura transfer KSM to basilisk', async () => { 13 | return { 14 | fromChain: karuraClient, 15 | toChain: basiliskClient, 16 | routeChain: kusamaClient, 17 | isCheckUmp: true, 18 | toAccount: defaultAccounts.bob, 19 | fromBalance: query.tokens(karura.custom.ksm), 20 | toBalance: query.tokens(basilisk.custom.relayToken), 21 | tx: tx.xtokens.transfer(karura.custom.ksm, 10n ** 12n, tx.xtokens.parachainV4(basilisk.paraId!)), 22 | } 23 | }) 24 | 25 | runXtokenstHorizontal( 26 | 'basilisk transfer KSM to karura', 27 | async () => { 28 | return { 29 | fromChain: basiliskClient, 30 | toChain: karuraClient, 31 | routeChain: kusamaClient, 32 | isCheckUmp: true, 33 | toAccount: defaultAccounts.bob, 34 | fromBalance: query.tokens(basilisk.custom.relayToken), 35 | toBalance: query.tokens(karura.custom.ksm), 36 | tx: tx.xtokens.transfer(basilisk.custom.relayToken, 10n ** 12n, tx.xtokens.parachainV4(karura.paraId!)), 37 | } 38 | }, 39 | { skip: true }, 40 | ) // TODO: somehow pjs is generate invalid signature 41 | 42 | runXtokenstHorizontal( 43 | 'basilisk transfer BSX to karura', 44 | async () => { 45 | return { 46 | fromChain: basiliskClient, 47 | toChain: karuraClient, 48 | fromBalance: query.balances, 49 | toBalance: query.tokens(karura.custom.bsx), 50 | tx: tx.xtokens.transfer(basilisk.custom.bsx, 10n ** 15n, tx.xtokens.parachainV4(karura.paraId!)), 51 | } 52 | }, 53 | { skip: true }, 54 | ) // TODO: somehow pjs is generate invalid signature 55 | 56 | runXtokenstHorizontal('karura transfer BSX to basilisk', async () => { 57 | await karuraClient.dev.setStorage({ 58 | Tokens: { 59 | Accounts: [[[defaultAccounts.alice.address, karura.custom.bsx], { free: 10n * 10n ** 15n }]], 60 | }, 61 | }) 62 | 63 | return { 64 | fromChain: karuraClient, 65 | toChain: basiliskClient, 66 | fromBalance: query.tokens(karura.custom.bsx), 67 | toBalance: query.balances, 68 | tx: tx.xtokens.transfer(karura.custom.bsx, 10n ** 15n, tx.xtokens.parachainV4(basilisk.paraId!)), 69 | } 70 | }) 71 | }) 72 | -------------------------------------------------------------------------------- /packages/kusama/src/bridgeHubKusama.kusama.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { bridgeHubKusama, kusama } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 8 | 9 | describe('kusama & bridgeHubKusama', async () => { 10 | const [kusamaClient, bridgeHubClient] = await setupNetworks(kusama, bridgeHubKusama) 11 | 12 | const bridgeHubKSM = bridgeHubKusama.custom.ksm 13 | const kusamaKSM = kusama.custom.ksm 14 | 15 | runXcmPalletDown('kusama transfer KSM to bridgeHubKusama', async () => { 16 | return { 17 | fromChain: kusamaClient, 18 | toChain: bridgeHubClient, 19 | balance: query.balances, 20 | toAccount: defaultAccounts.dave, 21 | tx: tx.xcmPallet.teleportAssetsV3(kusamaKSM, 1e12, tx.xcmPallet.parachainV3(0, bridgeHubKusama.paraId!)), 22 | totalIssuanceProvider: () => query.totalIssuance(kusamaClient), 23 | } 24 | }) 25 | 26 | runXcmPalletUp('bridgeHubKusama transfer KSM to kusama', async () => { 27 | return { 28 | fromChain: bridgeHubClient, 29 | toChain: kusamaClient, 30 | balance: query.balances, 31 | toAccount: defaultAccounts.dave, 32 | tx: tx.xcmPallet.teleportAssetsV3(bridgeHubKSM, 1e12, tx.xcmPallet.relaychainV4), 33 | totalIssuanceProvider: () => query.totalIssuance(kusamaClient), 34 | } 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /packages/kusama/src/coretimeKusama.kusama.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { coretimeKusama, kusama } from '@e2e-test/networks/chains' 4 | import { setupNetworks } from '@e2e-test/shared' 5 | import { query, tx } from '@e2e-test/shared/api' 6 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 7 | 8 | describe('kusama & coretimeKusama', async () => { 9 | const [kusamaClient, coretimeClient] = await setupNetworks(kusama, coretimeKusama) 10 | 11 | const coretimeKSM = coretimeKusama.custom.ksm 12 | const kusamaKSM = kusama.custom.ksm 13 | 14 | runXcmPalletDown('kusama transfer KSM to coretimeKusama', async () => { 15 | return { 16 | fromChain: kusamaClient, 17 | toChain: coretimeClient, 18 | balance: query.balances, 19 | tx: tx.xcmPallet.teleportAssetsV3(kusamaKSM, 1e12, tx.xcmPallet.parachainV3(0, coretimeKusama.paraId!)), 20 | totalIssuanceProvider: () => query.totalIssuance(kusamaClient), 21 | } 22 | }) 23 | 24 | runXcmPalletUp('coretimeKusama transfer KSM to kusama', async () => { 25 | return { 26 | fromChain: coretimeClient, 27 | toChain: kusamaClient, 28 | balance: query.balances, 29 | tx: tx.xcmPallet.teleportAssetsV3(coretimeKSM, 1e12, tx.xcmPallet.relaychainV4), 30 | totalIssuanceProvider: () => query.totalIssuance(kusamaClient), 31 | } 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /packages/kusama/src/coretimeKusama.proxy.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { coretimeKusama } from '@e2e-test/networks/chains' 2 | 3 | import { proxyE2ETests } from '@e2e-test/shared' 4 | import { CoretimeProxyTypes } from '@e2e-test/shared' 5 | 6 | proxyE2ETests(coretimeKusama, { testSuiteName: 'Kusama Coretime Proxy', addressEncoding: 2 }, CoretimeProxyTypes) 7 | -------------------------------------------------------------------------------- /packages/kusama/src/karura.kusama.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { karura, kusama } from '@e2e-test/networks/chains' 4 | import { setupNetworks } from '@e2e-test/shared' 5 | import { query, tx } from '@e2e-test/shared/api' 6 | import { runXcmPalletDown, runXtokensUp } from '@e2e-test/shared/xcm' 7 | 8 | describe('karura & kusama', async () => { 9 | const [karuraClient, kusamaClient] = await setupNetworks(karura, kusama) 10 | 11 | const karuraKSM = karura.custom.ksm 12 | const kusamaKSM = kusama.custom.ksm 13 | 14 | runXtokensUp('karura transfer KSM to kusama', async () => { 15 | return { 16 | fromChain: karuraClient, 17 | toChain: kusamaClient, 18 | balance: query.tokens(karuraKSM), 19 | tx: tx.xtokens.transfer(karuraKSM, 1e12, tx.xtokens.relaychainV3), 20 | } 21 | }) 22 | 23 | runXtokensUp('karura transfer KSM to kusama wiht limited weight', async () => { 24 | return { 25 | fromChain: karuraClient, 26 | toChain: kusamaClient, 27 | balance: query.tokens(karuraKSM), 28 | tx: tx.xtokens.transfer(karuraKSM, 1e12, tx.xtokens.relaychainV3, { 29 | Limited: { refTime: 500000000, proofSize: 10000 }, 30 | }), 31 | } 32 | }) 33 | 34 | runXcmPalletDown('kusama transfer KSM to karura', async () => { 35 | return { 36 | fromChain: kusamaClient, 37 | toChain: karuraClient, 38 | balance: query.tokens(karuraKSM), 39 | tx: tx.xcmPallet.limitedReserveTransferAssetsV3(kusamaKSM, 1e12, tx.xcmPallet.parachainV3(0, karura.paraId!)), 40 | } 41 | }) 42 | }) 43 | -------------------------------------------------------------------------------- /packages/kusama/src/karura.shiden.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { karura, shiden } from '@e2e-test/networks/chains' 4 | import { setupNetworks } from '@e2e-test/shared' 5 | import { query, tx } from '@e2e-test/shared/api' 6 | import { runXtokenstHorizontal } from '@e2e-test/shared/xcm' 7 | 8 | describe('karura & shiden', async () => { 9 | const [shidenClient, karuraClient] = await setupNetworks(shiden, karura) 10 | 11 | runXtokenstHorizontal('shiden transfer KAR to karura', async () => { 12 | return { 13 | fromChain: shidenClient, 14 | toChain: karuraClient, 15 | fromBalance: query.assets(shiden.custom.kar), 16 | toBalance: query.balances, 17 | tx: tx.xtokens.transfer(shiden.custom.kar, 1e12, tx.xtokens.parachainV3(karura.paraId!)), 18 | } 19 | }) 20 | 21 | runXtokenstHorizontal('karura transfer KAR to shiden', async () => { 22 | return { 23 | fromChain: karuraClient, 24 | toChain: shidenClient, 25 | fromBalance: query.balances, 26 | toBalance: query.assets(shiden.custom.kar), 27 | tx: tx.xtokens.transfer(karura.custom.kar, 1e12, tx.xtokens.parachainV3(shiden.paraId!)), 28 | } 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /packages/kusama/src/kusama.governance.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { kusama } from '@e2e-test/networks/chains' 2 | 3 | import { governanceE2ETests } from '@e2e-test/shared' 4 | 5 | governanceE2ETests(kusama, { testSuiteName: 'Kusama Governance', addressEncoding: 2 }) 6 | -------------------------------------------------------------------------------- /packages/kusama/src/kusama.nominationPools.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { kusama } from '@e2e-test/networks/chains' 2 | 3 | import { nominationPoolsE2ETests } from '@e2e-test/shared' 4 | 5 | nominationPoolsE2ETests(kusama, { testSuiteName: 'Kusama Nomination Pools', addressEncoding: 2 }) 6 | -------------------------------------------------------------------------------- /packages/kusama/src/kusama.proxy.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { kusama } from '@e2e-test/networks/chains' 2 | 3 | import { proxyE2ETests } from '@e2e-test/shared' 4 | import { KusamaProxyTypes } from '@e2e-test/shared' 5 | 6 | proxyE2ETests(kusama, { testSuiteName: 'Kusama Proxy', addressEncoding: 2 }, KusamaProxyTypes) 7 | -------------------------------------------------------------------------------- /packages/kusama/src/kusama.scheduler.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { kusama } from '@e2e-test/networks/chains' 2 | 3 | import { schedulerE2ETests } from '@e2e-test/shared' 4 | 5 | schedulerE2ETests(kusama, { testSuiteName: 'Kusama Scheduler', addressEncoding: 0 }) 6 | -------------------------------------------------------------------------------- /packages/kusama/src/kusama.shiden.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { kusama, shiden } from '@e2e-test/networks/chains' 4 | import { setupNetworks } from '@e2e-test/shared' 5 | import { query, tx } from '@e2e-test/shared/api' 6 | import { runXcmPalletDown, runXtokensUp } from '@e2e-test/shared/xcm' 7 | 8 | describe('kusama & shiden', async () => { 9 | const [kusamaClient, shidenClient] = await setupNetworks(kusama, shiden) 10 | 11 | const shidenKSM = shiden.custom.ksm 12 | const kusamaKSM = kusama.custom.ksm 13 | 14 | runXtokensUp('shiden transfer KSM to kusama', async () => { 15 | return { 16 | fromChain: shidenClient, 17 | toChain: kusamaClient, 18 | balance: query.assets(shidenKSM), 19 | tx: tx.xtokens.transfer(shidenKSM, 1e12, tx.xtokens.relaychainV3), 20 | } 21 | }) 22 | 23 | runXcmPalletDown('kusama transfer KSM to shiden', async () => { 24 | return { 25 | fromChain: kusamaClient, 26 | toChain: shidenClient, 27 | balance: query.assets(shidenKSM), 28 | tx: tx.xcmPallet.limitedReserveTransferAssetsV3(kusamaKSM, 1e12, tx.xcmPallet.parachainV3(0, shiden.paraId!)), 29 | } 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /packages/kusama/src/kusama.staking.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { kusama } from '@e2e-test/networks/chains' 2 | 3 | import { stakingE2ETests } from '@e2e-test/shared' 4 | 5 | stakingE2ETests(kusama, { testSuiteName: 'Kusama Staking', addressEncoding: 2 }) 6 | -------------------------------------------------------------------------------- /packages/kusama/src/kusama.vesting.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { kusama } from '@e2e-test/networks/chains' 2 | 3 | import { vestingE2ETests } from '@e2e-test/shared' 4 | 5 | vestingE2ETests(kusama, { testSuiteName: 'Kusama Vesting', addressEncoding: 2 }) 6 | -------------------------------------------------------------------------------- /packages/kusama/src/peopleKusama.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { kusama, peopleKusama } from '@e2e-test/networks/chains' 2 | 3 | import { peopleChainE2ETests } from '@e2e-test/shared' 4 | 5 | peopleChainE2ETests(kusama, peopleKusama, { testSuiteName: 'Kusama People', addressEncoding: 2 }) 6 | -------------------------------------------------------------------------------- /packages/kusama/src/peopleKusama.kusama.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { kusama, peopleKusama } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 8 | 9 | describe('kusama & peopleKusama', async () => { 10 | const [kusamaClient, peopleClient] = await setupNetworks(kusama, peopleKusama) 11 | 12 | const peopleKSM = peopleKusama.custom.ksm 13 | const kusamaKSM = kusama.custom.ksm 14 | 15 | runXcmPalletDown('kusama transfer KSM to peopleKusama', async () => { 16 | return { 17 | fromChain: kusamaClient, 18 | toChain: peopleClient, 19 | balance: query.balances, 20 | toAccount: defaultAccounts.dave, 21 | tx: tx.xcmPallet.teleportAssetsV3(kusamaKSM, 1e12, tx.xcmPallet.parachainV3(0, peopleKusama.paraId!)), 22 | totalIssuanceProvider: () => query.totalIssuance(kusamaClient), 23 | } 24 | }) 25 | 26 | runXcmPalletUp('peopleKusama transfer KSM to kusama', async () => { 27 | return { 28 | fromChain: peopleClient, 29 | toChain: kusamaClient, 30 | balance: query.balances, 31 | toAccount: defaultAccounts.dave, 32 | tx: tx.xcmPallet.teleportAssetsV3(peopleKSM, 1e12, tx.xcmPallet.relaychainV4), 33 | totalIssuanceProvider: () => query.totalIssuance(kusamaClient), 34 | } 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /packages/kusama/src/peopleKusama.proxy.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { peopleKusama } from '@e2e-test/networks/chains' 2 | 3 | import { proxyE2ETests } from '@e2e-test/shared' 4 | import { PeopleProxyTypes } from '@e2e-test/shared' 5 | 6 | proxyE2ETests(peopleKusama, { testSuiteName: 'People Kusama Proxy', addressEncoding: 2 }, PeopleProxyTypes) 7 | -------------------------------------------------------------------------------- /packages/kusama/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "emitDeclarationOnly": true, 6 | "declarationDir": "dist/esm" 7 | }, 8 | "include": ["src/**/*"], 9 | "references": [{ "path": "../networks/tsconfig.json" }, { "path": "../shared/tsconfig.json" }] 10 | } 11 | -------------------------------------------------------------------------------- /packages/networks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@e2e-test/networks", 3 | "type": "module", 4 | "dependencies": { 5 | "@acala-network/chopsticks-testing": "^1.0.6" 6 | }, 7 | "main": "./dist/cjs/index.js", 8 | "module": "./dist/esm/index.js", 9 | "files": [ 10 | "*", 11 | "!tsconfig.json", 12 | "!**/*.test.ts" 13 | ], 14 | "exports": { 15 | ".": { 16 | "require": "./dist/cjs/index.js", 17 | "import": "./dist/esm/index.js", 18 | "default": "./dist/esm/index.js" 19 | }, 20 | "./chains": { 21 | "require": "./dist/cjs/chains/index.js", 22 | "import": "./dist/esm/chains/index.js", 23 | "default": "./dist/esm/chains/index.js" 24 | }, 25 | "./*": { 26 | "require": "./dist/cjs/*.js", 27 | "import": "./dist/esm/*.js", 28 | "default": "./dist/esm/*.js" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/networks/src/captureSnapshot.ts: -------------------------------------------------------------------------------- 1 | import type { Client } from './createNetwork.js' 2 | 3 | export function captureSnapshot(...clients: Client[]) { 4 | const heads = clients.map((client) => [client.chain.head, client.chain] as const) 5 | return async () => { 6 | for (const [head, chain] of heads) { 7 | await chain.setHead(head) 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/networks/src/chains/acala.ts: -------------------------------------------------------------------------------- 1 | import { defaultAccounts } from '../defaultAccounts.js' 2 | import { defineChain } from '../defineChain.js' 3 | 4 | const custom = { 5 | acala: { 6 | relayToken: 'DOT', 7 | relayLiquidToken: 'LDOT', 8 | stableToken: 'AUSD', 9 | 10 | paraAccount: '13YMK2eYoAvStnzReuxBjMrAvPXmmdsURwZvc62PrdXimbNy', 11 | dot: { Token: 'DOT' }, 12 | ldot: { Token: 'LDOT' }, 13 | dai: { Erc20: '0x54a37a01cd75b616d63e0ab665bffdb0143c52ae' }, 14 | usdt: { ForeignAsset: 12 }, 15 | ausd: { Token: 'AUSD' }, 16 | aca: { Token: 'ACA' }, 17 | lcdot: { LiquidCrowdloan: 13 }, 18 | eth: { ForeignAsset: 21 }, 19 | }, 20 | karura: { 21 | relayToken: 'KSM', 22 | relayLiquidToken: 'LKSM', 23 | stableToken: 'KUSD', 24 | 25 | paraAccount: '13YMK2eYoAvStnzReuxBjMrAvPXmmdsURwZvc62PrdXimbNy', 26 | ksm: { Token: 'KSM' }, 27 | lksm: { Token: 'LKSM' }, 28 | usdt: { ForeignAsset: 7 }, 29 | rmrk: { ForeignAsset: 0 }, 30 | dai: { Erc20: '0x4bb6afb5fa2b07a5d1c499e1c3ddb5a15e709a71' }, 31 | ausd: { Token: 'KUSD' }, 32 | kar: { Token: 'KAR' }, 33 | bsx: { ForeignAsset: 11 }, 34 | }, 35 | } 36 | 37 | const getInitStorages = (config: typeof custom.acala | typeof custom.karura) => ({ 38 | System: { 39 | account: [[[defaultAccounts.alice.address], { providers: 4, data: { free: 10 * 1e12 } }]], 40 | }, 41 | Tokens: { 42 | accounts: [ 43 | [[defaultAccounts.alice.address, { Token: config.relayToken }], { free: 10 * 1e12 }], 44 | [[defaultAccounts.alice.address, { Token: config.relayLiquidToken }], { free: 100 * 1e12 }], 45 | [[defaultAccounts.alice.address, { Token: config.stableToken }], { free: 1000 * 1e12 }], 46 | ], 47 | }, 48 | Sudo: { 49 | key: defaultAccounts.alice.address, 50 | }, 51 | EvmAccounts: { 52 | accounts: [[['0x82a258cb20e2adb4788153cd5eb5839615ece9a0'], defaultAccounts.alice.address]], 53 | evmAddresses: [[[defaultAccounts.alice.address], '0x82a258cb20e2adb4788153cd5eb5839615ece9a0']], 54 | }, 55 | Homa: { 56 | // avoid impact test outcome 57 | $removePrefix: ['redeemRequests', 'unbondings', 'toBondPool'], 58 | // so that bump era won't trigger unbond 59 | relayChainCurrentEra: 100, 60 | }, 61 | PolkadotXcm: { 62 | // avoid sending xcm version change notifications to makes things faster 63 | $removePrefix: ['versionNotifyTargets', 'versionNotifiers'], 64 | }, 65 | }) 66 | 67 | export const acala = defineChain({ 68 | name: 'acala', 69 | endpoint: 'wss://acala-rpc.dwellir.com', 70 | paraId: 2000, 71 | custom: custom.acala, 72 | initStorages: getInitStorages(custom.acala), 73 | }) 74 | 75 | export const karura = defineChain({ 76 | name: 'karura', 77 | endpoint: 'wss://karura-rpc.dwellir.com', 78 | paraId: 2000, 79 | custom: custom.karura, 80 | initStorages: getInitStorages(custom.karura), 81 | }) 82 | -------------------------------------------------------------------------------- /packages/networks/src/chains/assethub.ts: -------------------------------------------------------------------------------- 1 | import { defaultAccounts, defaultAccountsSr25519 } from '../defaultAccounts.js' 2 | import { defineChain } from '../defineChain.js' 3 | 4 | const custom = { 5 | assetHubPolkadot: { 6 | dot: { Concrete: { parents: 1, interior: 'Here' } }, 7 | usdt: { Concrete: { parents: 0, interior: { X2: [{ PalletInstance: 50 }, { GeneralIndex: 1984 }] } } }, 8 | usdtIndex: 1984, 9 | eth: { 10 | parents: 2, 11 | interior: { 12 | X1: [ 13 | { 14 | GlobalConsensus: { 15 | Ethereum: { 16 | chainId: 1, 17 | }, 18 | }, 19 | }, 20 | ], 21 | }, 22 | }, 23 | }, 24 | assetHubKusama: { 25 | ksm: { Concrete: { parents: 1, interior: 'Here' } }, 26 | usdt: { Concrete: { parents: 0, interior: { X2: [{ PalletInstance: 50 }, { GeneralIndex: 1984 }] } } }, 27 | usdtIndex: 1984, 28 | eth: { 29 | parents: 2, 30 | interior: { 31 | X1: [ 32 | { 33 | GlobalConsensus: { 34 | Ethereum: { 35 | chainId: 1, 36 | }, 37 | }, 38 | }, 39 | ], 40 | }, 41 | }, 42 | }, 43 | } 44 | 45 | const getInitStorages = (config: typeof custom.assetHubPolkadot | typeof custom.assetHubKusama) => ({ 46 | System: { 47 | account: [ 48 | [[defaultAccounts.alice.address], { providers: 1, data: { free: 1000e10 } }], 49 | [[defaultAccountsSr25519.alice.address], { providers: 1, data: { free: 1000e10 } }], 50 | ], 51 | }, 52 | Assets: { 53 | account: [ 54 | [[config.usdtIndex, defaultAccounts.alice.address], { balance: 1000e6 }], // USDT 55 | ], 56 | }, 57 | ForeignAssets: { 58 | account: [ 59 | [[config.eth, defaultAccounts.alice.address], { balance: 10n ** 18n }], // 1 ETH 60 | [[config.eth, '13cKp89Msu7M2PiaCuuGr1BzAsD5V3vaVbDMs3YtjMZHdGwR'], { balance: 10n ** 20n }], // 100 ETH for Sibling 2000 61 | ], 62 | }, 63 | }) 64 | 65 | export const assetHubPolkadot = defineChain({ 66 | name: 'assetHubPolkadot', 67 | endpoint: 'wss://polkadot-asset-hub-rpc.polkadot.io', 68 | paraId: 1000, 69 | custom: custom.assetHubPolkadot, 70 | initStorages: getInitStorages(custom.assetHubPolkadot), 71 | }) 72 | 73 | export const assetHubKusama = defineChain({ 74 | name: 'assetHubKusama', 75 | endpoint: 'wss://kusama-asset-hub-rpc.polkadot.io', 76 | paraId: 1000, 77 | custom: custom.assetHubKusama, 78 | initStorages: getInitStorages(custom.assetHubKusama), 79 | }) 80 | -------------------------------------------------------------------------------- /packages/networks/src/chains/astar.ts: -------------------------------------------------------------------------------- 1 | import { defaultAccounts } from '../defaultAccounts.js' 2 | import { defineChain } from '../defineChain.js' 3 | 4 | const custom = { 5 | astar: { 6 | relayToken: '340282366920938463463374607431768211455', 7 | aUSDToken: '18446744073709551617', 8 | 9 | paraAccount: '13YMK2eZzuFY1WZGagpYtTgbWBWGdoUD2CtrPj1mQPjY8Ldc', 10 | dot: 340282366920938463463374607431768211455n, 11 | astr: { Concrete: { parents: 0, interior: 'Here' } }, 12 | aca: 18446744073709551616n, 13 | usdt: 4294969280n, 14 | }, 15 | shiden: { 16 | relayToken: '340282366920938463463374607431768211455', 17 | aUSDToken: '18446744073709551616', 18 | 19 | paraAccount: 'F7fq1jNy74AqkJ1DP4KqSrWtnTGtXfNVoDwFhTvvPxUvJaq', 20 | ksm: 340282366920938463463374607431768211455n, 21 | sdn: { Concrete: { parents: 0, interior: 'Here' } }, 22 | kar: 18446744073709551618n, 23 | usdt: 4294969280n, 24 | }, 25 | } 26 | 27 | const getInitStorages = (config: typeof custom.astar | typeof custom.shiden) => ({ 28 | System: { 29 | account: [[[defaultAccounts.alice.address], { providers: 1, data: { free: '100000000000000000000' } }]], 30 | }, 31 | Assets: { 32 | account: [ 33 | [[config.relayToken, defaultAccounts.alice.address], { balance: 10 * 1e12 }], 34 | [['aca' in config ? config.aca : config.kar, defaultAccounts.alice.address], { balance: 20 * 1e12 }], 35 | ], 36 | }, 37 | Sudo: { 38 | key: defaultAccounts.alice.address, 39 | }, 40 | PolkadotXcm: { 41 | // avoid sending xcm version change notifications to makes things faster 42 | $removePrefix: ['versionNotifyTargets', 'versionNotifiers', 'supportedVersion'], 43 | }, 44 | }) 45 | 46 | export const astar = defineChain({ 47 | name: 'astar', 48 | paraId: 2006, 49 | endpoint: 'wss://astar-rpc.dwellir.com', 50 | custom: custom.astar, 51 | initStorages: getInitStorages(custom.astar), 52 | }) 53 | 54 | export const shiden = defineChain({ 55 | name: 'shiden', 56 | paraId: 2007, 57 | endpoint: 'wss://shiden-rpc.dwellir.com', 58 | custom: custom.shiden, 59 | initStorages: getInitStorages(custom.shiden), 60 | }) 61 | -------------------------------------------------------------------------------- /packages/networks/src/chains/bridgehub.ts: -------------------------------------------------------------------------------- 1 | import { defaultAccounts } from '../defaultAccounts.js' 2 | import { defineChain } from '../defineChain.js' 3 | 4 | const custom = { 5 | bridgeHubPolkadot: { 6 | dot: { Concrete: { parents: 1, interior: 'Here' } }, 7 | }, 8 | bridgeHubKusama: { 9 | ksm: { Concrete: { parents: 1, interior: 'Here' } }, 10 | }, 11 | } 12 | 13 | const getInitStorages = (_config: typeof custom.bridgeHubPolkadot | typeof custom.bridgeHubKusama) => ({ 14 | System: { 15 | account: [[[defaultAccounts.alice.address], { providers: 1, data: { free: 1000e10 } }]], 16 | }, 17 | }) 18 | 19 | export const bridgeHubPolkadot = defineChain({ 20 | name: 'bridgeHubPolkadot', 21 | endpoint: 'wss://polkadot-bridge-hub-rpc.polkadot.io', 22 | paraId: 1002, 23 | custom: custom.bridgeHubPolkadot, 24 | initStorages: getInitStorages(custom.bridgeHubPolkadot), 25 | }) 26 | 27 | export const bridgeHubKusama = defineChain({ 28 | name: 'bridgeHubKusama', 29 | endpoint: 'wss://kusama-bridge-hub-rpc.polkadot.io', 30 | paraId: 1002, 31 | custom: custom.bridgeHubKusama, 32 | initStorages: getInitStorages(custom.bridgeHubKusama), 33 | }) 34 | -------------------------------------------------------------------------------- /packages/networks/src/chains/collectives.ts: -------------------------------------------------------------------------------- 1 | import { defaultAccounts, defaultAccountsSr25519 } from '../defaultAccounts.js' 2 | import { defineChain } from '../defineChain.js' 3 | 4 | const custom = { 5 | collectivesPolkadot: { 6 | dot: { Concrete: { parents: 1, interior: 'Here' } }, 7 | }, 8 | } 9 | 10 | const getInitStorages = (_config: typeof custom.collectivesPolkadot) => ({ 11 | System: { 12 | account: [ 13 | [[defaultAccountsSr25519.alice.address], { providers: 1, data: { free: 1000e10 } }], 14 | [[defaultAccounts.alice.address], { providers: 1, data: { free: 1000e10 } }], 15 | [[defaultAccounts.bob.address], { providers: 1, data: { free: 1000e10 } }], 16 | ], 17 | }, 18 | }) 19 | 20 | export const collectivesPolkadot = defineChain({ 21 | name: 'collectivesPolkadot', 22 | endpoint: 'wss://polkadot-collectives-rpc.polkadot.io', 23 | paraId: 1001, 24 | custom: custom.collectivesPolkadot, 25 | initStorages: getInitStorages(custom.collectivesPolkadot), 26 | }) 27 | -------------------------------------------------------------------------------- /packages/networks/src/chains/coretime.ts: -------------------------------------------------------------------------------- 1 | import { defaultAccounts, defaultAccountsSr25519 } from '../defaultAccounts.js' 2 | import { defineChain } from '../defineChain.js' 3 | 4 | const custom = { 5 | coretimePolkadot: { 6 | dot: { Concrete: { parents: 1, interior: 'Here' } }, 7 | }, 8 | coretimeKusama: { 9 | ksm: { Concrete: { parents: 1, interior: 'Here' } }, 10 | }, 11 | } 12 | 13 | const getInitStorages = (_config: typeof custom.coretimePolkadot | typeof custom.coretimeKusama) => ({ 14 | System: { 15 | account: [ 16 | [[defaultAccounts.alice.address], { providers: 1, data: { free: 1000e10 } }], 17 | [[defaultAccountsSr25519.alice.address], { providers: 1, data: { free: 1000e10 } }], 18 | ], 19 | }, 20 | }) 21 | 22 | export const coretimePolkadot = defineChain({ 23 | name: 'coretimePolkadot', 24 | endpoint: 'wss://polkadot-coretime-rpc.polkadot.io', 25 | paraId: 1005, 26 | custom: custom.coretimePolkadot, 27 | initStorages: getInitStorages(custom.coretimePolkadot), 28 | }) 29 | 30 | export const coretimeKusama = defineChain({ 31 | name: 'coretimeKusama', 32 | endpoint: 'wss://kusama-coretime-rpc.polkadot.io', 33 | paraId: 1005, 34 | custom: custom.coretimeKusama, 35 | initStorages: getInitStorages(custom.coretimeKusama), 36 | }) 37 | -------------------------------------------------------------------------------- /packages/networks/src/chains/hydration.ts: -------------------------------------------------------------------------------- 1 | import { defaultAccounts } from '../defaultAccounts.js' 2 | import { defineChain } from '../defineChain.js' 3 | 4 | const custom = { 5 | hydration: { 6 | dai: 2, 7 | relayToken: 5, 8 | glmr: 16, 9 | }, 10 | basilisk: { 11 | bsx: 0, 12 | dai: 13, 13 | relayToken: 1, 14 | }, 15 | } 16 | 17 | const getInitStorages = (config: typeof custom.hydration | typeof custom.basilisk) => ({ 18 | System: { 19 | Account: [[[defaultAccounts.alice.address], { providers: 1, data: { free: 10n ** 18n } }]], 20 | }, 21 | Tokens: { 22 | Accounts: [ 23 | [[defaultAccounts.alice.address, config.relayToken], { free: 1000 * 1e12 }], 24 | [[defaultAccounts.alice.address, config.dai], { free: 100n * 10n ** 18n }], 25 | ], 26 | }, 27 | }) 28 | 29 | export const hydration = defineChain({ 30 | name: 'hydration', 31 | paraId: 2034, 32 | endpoint: 'wss://rpc.hydradx.cloud', 33 | custom: custom.hydration, 34 | initStorages: getInitStorages(custom.hydration), 35 | }) 36 | 37 | export const basilisk = defineChain({ 38 | name: 'basilisk', 39 | paraId: 2090, 40 | endpoint: 'wss://basilisk-rpc.dwellir.com', 41 | custom: custom.basilisk, 42 | initStorages: getInitStorages(custom.basilisk), 43 | }) 44 | -------------------------------------------------------------------------------- /packages/networks/src/chains/index.ts: -------------------------------------------------------------------------------- 1 | export * from './acala.js' 2 | export * from './assethub.js' 3 | export * from './astar.js' 4 | export * from './bridgehub.js' 5 | export * from './coretime.js' 6 | export * from './collectives.js' 7 | export * from './hydration.js' 8 | export * from './moonbeam.js' 9 | export * from './people.js' 10 | export * from './polkadot.js' 11 | -------------------------------------------------------------------------------- /packages/networks/src/chains/moonbeam.ts: -------------------------------------------------------------------------------- 1 | import { defaultAccounts } from '../defaultAccounts.js' 2 | import { defineChain } from '../defineChain.js' 3 | 4 | const custom = { 5 | moonbeam: { 6 | dot: 42259045809535163221576417993425387648n, 7 | aca: 224821240862170613278369189818311486111n, 8 | ldot: 225719522181998468294117309041779353812n, 9 | xcmDot: { Concrete: { parents: 1, interior: 'Here' } }, 10 | xcmAca: { 11 | Concrete: { 12 | parents: 1, 13 | interior: { 14 | X2: [ 15 | { Parachain: 2000 }, 16 | { GeneralKey: { data: '0x0000000000000000000000000000000000000000000000000000000000000000', length: 2 } }, 17 | ], 18 | }, 19 | }, 20 | }, 21 | xcmLdot: { 22 | Concrete: { 23 | parents: 1, 24 | interior: { 25 | X2: [ 26 | { Parachain: 2000 }, 27 | { GeneralKey: { data: '0x0003000000000000000000000000000000000000000000000000000000000000', length: 2 } }, 28 | ], 29 | }, 30 | }, 31 | }, 32 | }, 33 | moonriver: {}, 34 | } 35 | 36 | const getInitStorages = () => ({ 37 | System: { 38 | Account: [[[defaultAccounts.alith.address], { providers: 1, data: { free: 1000n * 10n ** 18n } }]], 39 | }, 40 | AuthorFilter: { 41 | EligibleRatio: 100, 42 | EligibleCount: 100, 43 | }, 44 | }) 45 | 46 | export const moonbeam = defineChain({ 47 | name: 'moonbeam', 48 | paraId: 2004, 49 | endpoint: 'wss://moonbeam-rpc.dwellir.com', 50 | custom: custom.moonbeam, 51 | initStorages: getInitStorages(), 52 | }) 53 | 54 | export const moonriver = defineChain({ 55 | name: 'moonriver', 56 | paraId: 2023, 57 | endpoint: 'wss://moonriver-rpc.dwellir.com', 58 | custom: custom.moonriver, 59 | initStorages: getInitStorages(), 60 | }) 61 | -------------------------------------------------------------------------------- /packages/networks/src/chains/people.ts: -------------------------------------------------------------------------------- 1 | import { defaultAccounts, defaultAccountsSr25519 } from '../defaultAccounts.js' 2 | import { defineChain } from '../defineChain.js' 3 | 4 | const custom = { 5 | peoplePolkadot: { 6 | dot: { Concrete: { parents: 1, interior: 'Here' } }, 7 | }, 8 | peopleKusama: { 9 | ksm: { Concrete: { parents: 1, interior: 'Here' } }, 10 | }, 11 | } 12 | 13 | const aliceRegistrar = { 14 | account: defaultAccountsSr25519.alice.address, 15 | fee: 1, 16 | fields: 0, 17 | } 18 | 19 | const bobRegistrar = { 20 | account: defaultAccountsSr25519.bob.address, 21 | fee: 0, 22 | fields: 0, 23 | } 24 | 25 | const getInitStorages = (_config: typeof custom.peoplePolkadot | typeof custom.peopleKusama) => ({ 26 | System: { 27 | account: [ 28 | [[defaultAccounts.alice.address], { providers: 1, data: { free: 1000e10 } }], 29 | [[defaultAccounts.bob.address], { providers: 1, data: { free: 1000e10 } }], 30 | [[defaultAccountsSr25519.alice.address], { providers: 1, data: { free: 1000e10 } }], 31 | [[defaultAccountsSr25519.bob.address], { providers: 1, data: { free: 1000e10 } }], 32 | ], 33 | }, 34 | // Registrars to be used in E2E tests - required to test `RegistrarOrigin`-locked extrinsics. 35 | Identity: { 36 | Registrars: [aliceRegistrar, bobRegistrar], 37 | }, 38 | }) 39 | 40 | export const peoplePolkadot = defineChain({ 41 | name: 'peoplePolkadot', 42 | endpoint: 'wss://polkadot-people-rpc.polkadot.io', 43 | paraId: 1004, 44 | custom: custom.peoplePolkadot, 45 | initStorages: getInitStorages(custom.peoplePolkadot), 46 | }) 47 | 48 | export const peopleKusama = defineChain({ 49 | name: 'peopleKusama', 50 | endpoint: 'wss://kusama-people-rpc.polkadot.io', 51 | paraId: 1004, 52 | custom: custom.peopleKusama, 53 | initStorages: getInitStorages(custom.peopleKusama), 54 | }) 55 | -------------------------------------------------------------------------------- /packages/networks/src/chains/polkadot.ts: -------------------------------------------------------------------------------- 1 | import { defaultAccounts, defaultAccountsSr25519 } from '../defaultAccounts.js' 2 | import { defineChain } from '../defineChain.js' 3 | 4 | const custom = { 5 | polkadot: { 6 | dot: { Concrete: { parents: 0, interior: 'Here' } }, 7 | }, 8 | kusama: { 9 | ksm: { Concrete: { parents: 0, interior: 'Here' } }, 10 | }, 11 | } 12 | 13 | const getInitStorages = () => ({ 14 | System: { 15 | Account: [ 16 | [[defaultAccounts.alice.address], { providers: 1, data: { free: 1000 * 1e10 } }], 17 | [[defaultAccountsSr25519.alice.address], { providers: 1, data: { free: 1000 * 1e10 } }], 18 | ], 19 | }, 20 | ParasDisputes: { 21 | // these can makes block building super slow 22 | $removePrefix: ['disputes'], 23 | }, 24 | Dmp: { 25 | // clear existing dmp to avoid impacting test result 26 | $removePrefix: ['downwardMessageQueues'], 27 | }, 28 | }) 29 | 30 | export const polkadot = defineChain({ 31 | name: 'polkadot', 32 | endpoint: 'wss://rpc.ibp.network/polkadot', 33 | custom: custom.polkadot, 34 | initStorages: getInitStorages(), 35 | isRelayChain: true, 36 | }) 37 | 38 | export const kusama = defineChain({ 39 | name: 'kusama', 40 | endpoint: 'wss://kusama.dotters.network', 41 | custom: custom.kusama, 42 | initStorages: getInitStorages(), 43 | isRelayChain: true, 44 | }) 45 | -------------------------------------------------------------------------------- /packages/networks/src/createNetwork.ts: -------------------------------------------------------------------------------- 1 | import { connectParachains, connectVertical } from '@acala-network/chopsticks' 2 | import { setupContext } from '@acala-network/chopsticks-testing' 3 | 4 | import type { Chain } from './types.js' 5 | 6 | export async function createNetwork(chainConfig: T) { 7 | const network = await setupContext(chainConfig) 8 | 9 | if (chainConfig.initStorages) { 10 | await network.dev.setStorage(chainConfig.initStorages) 11 | } 12 | 13 | return { 14 | ...network, 15 | config: chainConfig, 16 | } 17 | } 18 | 19 | export type Client = Awaited>> 20 | 21 | export async function createNetworks(...configs: T) { 22 | const networks = (await Promise.all(configs.map(createNetwork))) as { [I in keyof T]: Client } 23 | 24 | const relaychain = networks.find(({ config }) => config.isRelayChain) 25 | const parachains = networks.filter(({ config }) => !config.isRelayChain) 26 | 27 | await connectParachains( 28 | parachains.map(({ chain }) => chain), 29 | true, 30 | ) 31 | if (relaychain) { 32 | for (const parachain of parachains) { 33 | await connectVertical(relaychain.chain, parachain.chain) 34 | } 35 | } 36 | 37 | return networks 38 | } 39 | -------------------------------------------------------------------------------- /packages/networks/src/defaultAccounts.ts: -------------------------------------------------------------------------------- 1 | import { testingPairs } from '@acala-network/chopsticks-testing' 2 | import type { Keyring } from '@polkadot/keyring' 3 | import type { KeyringInstance, KeyringPair } from '@polkadot/keyring/types' 4 | 5 | import { cryptoWaitReady } from '@polkadot/util-crypto' 6 | 7 | export type DefaultAccounts = ReturnType 8 | 9 | export const defaultAccounts: { 10 | alice: KeyringPair 11 | bob: KeyringPair 12 | charlie: KeyringPair 13 | dave: KeyringPair 14 | eve: KeyringPair 15 | alith: KeyringPair 16 | baltathar: KeyringPair 17 | charleth: KeyringPair 18 | dorothy: KeyringPair 19 | ethan: KeyringPair 20 | keyring: Keyring 21 | keyringEth: KeyringInstance 22 | } = testingPairs() 23 | 24 | /** 25 | * Sr25519 keyring pairs for use in tests. 26 | * 27 | * These are preferrable over Ed25519 because PJS offers Sr25519 development keypairs when used in conjunction with 28 | * `chopsticks`, which helps debugging tests when `pause()`ing. 29 | */ 30 | export const defaultAccountsSr25519: { 31 | alice: KeyringPair 32 | bob: KeyringPair 33 | charlie: KeyringPair 34 | dave: KeyringPair 35 | eve: KeyringPair 36 | alith: KeyringPair 37 | baltathar: KeyringPair 38 | charleth: KeyringPair 39 | dorothy: KeyringPair 40 | ethan: KeyringPair 41 | keyring: Keyring 42 | keyringEth: KeyringInstance 43 | } = await cryptoWaitReady().then(() => testingPairs('sr25519')) 44 | -------------------------------------------------------------------------------- /packages/networks/src/defineChain.ts: -------------------------------------------------------------------------------- 1 | import type { Chain, ChainConfig } from './types.js' 2 | 3 | const toNumber = (value: string | undefined): number | undefined => { 4 | if (value === undefined) { 5 | return undefined 6 | } 7 | 8 | return Number(value) 9 | } 10 | /** 11 | * Defines a new chain configuration with support for custom properties and initial storage. 12 | * 13 | * @template TCustom - Type for custom chain configuration properties 14 | * @template TInitStorages - Type for initial storage configurations 15 | * @param config - Chain configuration object containing required settings 16 | * @returns Chain configuration with extension capabilities 17 | * 18 | * @example 19 | * const chain = defineChain({ 20 | * name: 'testnet', 21 | * endpoint: 'wss://test.network', 22 | * custom: { networkId: 1 } 23 | * }) 24 | */ 25 | export function defineChain< 26 | TCustom extends Record | undefined, 27 | TInitStorages extends Record> | undefined, 28 | >(config: ChainConfig): Chain { 29 | const upperName = config.name.toUpperCase() 30 | const { endpoint, ...rest } = config 31 | const chainConfig = { 32 | wasmOverride: process.env[`${upperName}_WASM`], 33 | endpoint: process.env[`${upperName}_ENDPOINT`] ?? endpoint, 34 | db: process.env.DB_PATH, 35 | runtimeLogLevel: process.env.RUNTIME_LOG_LEVEL ? Number(process.env.RUNTIME_LOG_LEVEL) : 0, 36 | blockNumber: toNumber(process.env[`${upperName}_BLOCK_NUMBER`]), 37 | timeout: 60_000, 38 | port: 0, 39 | allowUnresolvedImports: true, 40 | saveBlock: false, 41 | ...rest, 42 | } as ChainConfig 43 | 44 | function extend>>(base: Base) { 45 | return >(extendFn: (base: Base) => config) => { 46 | const extended = extendFn(base) 47 | const combined = { ...base, ...extended } 48 | return Object.assign(combined, { extend: extend(combined) }) 49 | } 50 | } 51 | 52 | return Object.assign(chainConfig, { extend: extend(chainConfig as any) as any }) as Chain 53 | } 54 | -------------------------------------------------------------------------------- /packages/networks/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './createNetwork.js' 2 | export * from './captureSnapshot.js' 3 | export * from './types.js' 4 | export * from './defaultAccounts.js' 5 | -------------------------------------------------------------------------------- /packages/networks/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { SetupOption } from '@acala-network/chopsticks-testing' 2 | 3 | interface ChainConfigRelaychain { 4 | isRelayChain: true 5 | paraId?: undefined 6 | } 7 | 8 | interface ChainConfigParachain { 9 | isRelayChain?: false 10 | paraId: number 11 | } 12 | 13 | type ChainConfigBase = { 14 | name: string 15 | endpoint: string | string[] 16 | isRelayChain?: boolean 17 | } & (ChainConfigRelaychain | ChainConfigParachain) 18 | 19 | export type ChainConfig< 20 | TCustom extends Record | undefined, 21 | TInitStorages extends Record> | undefined, 22 | > = ChainConfigBase & 23 | SetupOption & { 24 | custom: TCustom 25 | initStorages?: TInitStorages 26 | } 27 | 28 | export type Chain< 29 | TCustom extends Record | undefined = Record | undefined, 30 | TInitStorages extends Record> | undefined = 31 | | Record> 32 | | undefined, 33 | TExtended extends Record | undefined = Record | undefined, 34 | > = ChainConfig & 35 | TExtended & { 36 | extend: >( 37 | fn: (chain: Chain) => config, 38 | ) => Chain 39 | } 40 | -------------------------------------------------------------------------------- /packages/networks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "emitDeclarationOnly": true, 6 | "declarationDir": "dist/esm" 7 | }, 8 | "include": ["src/**/*"], 9 | "references": [{ "path": "../shared/tsconfig.json" }] 10 | } 11 | -------------------------------------------------------------------------------- /packages/polkadot/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@e2e-test/polkadot", 3 | "type": "module", 4 | "dependencies": { 5 | "@acala-network/chopsticks-testing": "^1.0.6", 6 | "@e2e-test/shared": "workspace:*" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/polkadot/src/__snapshots__/assetHubPolkadot.polkadot.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`asset hub & polkadot > Teleport DOT from Asset Hub to Polkadot > balance on from chain 1`] = ` 4 | { 5 | "consumers": 0, 6 | "data": { 7 | "flags": "0x80000000000000000000000000000000", 8 | "free": "(rounded 3000000000000)", 9 | "frozen": 0, 10 | "reserved": 0, 11 | }, 12 | "nonce": 1, 13 | "providers": 1, 14 | "sufficients": 0, 15 | } 16 | `; 17 | 18 | exports[`asset hub & polkadot > Teleport DOT from Asset Hub to Polkadot > balance on to chain 1`] = ` 19 | { 20 | "consumers": 0, 21 | "data": { 22 | "flags": "0x80000000000000000000000000000000", 23 | "free": "(rounded 7000000000000)", 24 | "frozen": 0, 25 | "reserved": 0, 26 | }, 27 | "nonce": 0, 28 | "providers": 1, 29 | "sufficients": 0, 30 | } 31 | `; 32 | 33 | exports[`asset hub & polkadot > Teleport DOT from Asset Hub to Polkadot > from chain ump messages 1`] = ` 34 | [ 35 | { 36 | "v5": [ 37 | { 38 | "receiveTeleportedAsset": [ 39 | { 40 | "fun": { 41 | "fungible": 7000000000000, 42 | }, 43 | "id": { 44 | "interior": { 45 | "here": null, 46 | }, 47 | "parents": 0, 48 | }, 49 | }, 50 | ], 51 | }, 52 | { 53 | "clearOrigin": null, 54 | }, 55 | { 56 | "buyExecution": { 57 | "fees": { 58 | "fun": { 59 | "fungible": 500000000000, 60 | }, 61 | "id": { 62 | "interior": { 63 | "here": null, 64 | }, 65 | "parents": 0, 66 | }, 67 | }, 68 | "weightLimit": { 69 | "unlimited": null, 70 | }, 71 | }, 72 | }, 73 | { 74 | "depositAsset": { 75 | "assets": { 76 | "wild": { 77 | "allCounted": 1, 78 | }, 79 | }, 80 | "beneficiary": { 81 | "interior": { 82 | "x1": [ 83 | { 84 | "accountId32": { 85 | "id": "0xd17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae69", 86 | "network": null, 87 | }, 88 | }, 89 | ], 90 | }, 91 | "parents": 0, 92 | }, 93 | }, 94 | }, 95 | { 96 | "setTopic": "(redacted)", 97 | }, 98 | ], 99 | }, 100 | ] 101 | `; 102 | 103 | exports[`asset hub & polkadot > Teleport DOT from Asset Hub to Polkadot > to chain ump events 1`] = ` 104 | [ 105 | { 106 | "data": { 107 | "id": "(hash)", 108 | "origin": { 109 | "Ump": { 110 | "Para": 1000, 111 | }, 112 | }, 113 | "success": true, 114 | "weightUsed": { 115 | "proofSize": "(rounded 7200)", 116 | "refTime": "(rounded 280000000)", 117 | }, 118 | }, 119 | "method": "Processed", 120 | "section": "messageQueue", 121 | }, 122 | ] 123 | `; 124 | 125 | exports[`asset hub & polkadot > Teleport DOT from Asset Hub to Polkadot > tx events 1`] = ` 126 | [ 127 | { 128 | "data": { 129 | "outcome": { 130 | "Complete": { 131 | "used": { 132 | "proofSize": "(rounded 363000)", 133 | "refTime": "(rounded 42500000000)", 134 | }, 135 | }, 136 | }, 137 | }, 138 | "method": "Attempted", 139 | "section": "polkadotXcm", 140 | }, 141 | ] 142 | `; 143 | 144 | exports[`asset hub & polkadot > Teleport DOT from Polkadot to Asset Hub > balance on from chain 1`] = ` 145 | { 146 | "consumers": 0, 147 | "data": { 148 | "flags": "0x80000000000000000000000000000000", 149 | "free": "(rounded 3000000000000)", 150 | "frozen": 0, 151 | "reserved": 0, 152 | }, 153 | "nonce": 1, 154 | "providers": 1, 155 | "sufficients": 0, 156 | } 157 | `; 158 | 159 | exports[`asset hub & polkadot > Teleport DOT from Polkadot to Asset Hub > balance on to chain 1`] = ` 160 | { 161 | "consumers": 0, 162 | "data": { 163 | "flags": "0x80000000000000000000000000000000", 164 | "free": "(rounded 7000000000000)", 165 | "frozen": 0, 166 | "reserved": 0, 167 | }, 168 | "nonce": 0, 169 | "providers": 1, 170 | "sufficients": 0, 171 | } 172 | `; 173 | 174 | exports[`asset hub & polkadot > Teleport DOT from Polkadot to Asset Hub > to chain dmp events 1`] = ` 175 | [ 176 | { 177 | "data": { 178 | "count": 1, 179 | }, 180 | "method": "DownwardMessagesReceived", 181 | "section": "parachainSystem", 182 | }, 183 | { 184 | "data": { 185 | "dmqHead": "(hash)", 186 | "weightUsed": { 187 | "proofSize": "(rounded 3500)", 188 | "refTime": "(rounded 740000000)", 189 | }, 190 | }, 191 | "method": "DownwardMessagesProcessed", 192 | "section": "parachainSystem", 193 | }, 194 | { 195 | "data": { 196 | "id": "(hash)", 197 | "origin": "Parent", 198 | "success": true, 199 | "weightUsed": { 200 | "proofSize": "(rounded 3600)", 201 | "refTime": "(rounded 160000000)", 202 | }, 203 | }, 204 | "method": "Processed", 205 | "section": "messageQueue", 206 | }, 207 | ] 208 | `; 209 | 210 | exports[`asset hub & polkadot > Teleport DOT from Polkadot to Asset Hub > tx events 1`] = ` 211 | [ 212 | { 213 | "data": { 214 | "outcome": { 215 | "Complete": { 216 | "used": { 217 | "proofSize": "(rounded 7190)", 218 | "refTime": "(rounded 587000000)", 219 | }, 220 | }, 221 | }, 222 | }, 223 | "method": "Attempted", 224 | "section": "xcmPallet", 225 | }, 226 | ] 227 | `; 228 | -------------------------------------------------------------------------------- /packages/polkadot/src/__snapshots__/assetHubPolkadot.vesting.e2e.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`Polkadot Asset Hub Vesting > forced vested transfer and forced removal of vesting schedule work > forced vested transfer event 1`] = ` 4 | [ 5 | "126TwBzBM4jUEK2gTphmW4oLoBWWnYvPp8hygmduTr4uds57", 6 | 5000000000, 7 | ] 8 | `; 9 | 10 | exports[`Polkadot Asset Hub Vesting > forced vested transfer and forced removal of vesting schedule work > forced vesting removal event 1`] = ` 11 | [ 12 | "126TwBzBM4jUEK2gTphmW4oLoBWWnYvPp8hygmduTr4uds57", 13 | ] 14 | `; 15 | 16 | exports[`Polkadot Asset Hub Vesting > signed-origin force-vested transfer fails > force vest events 1`] = ` 17 | [ 18 | { 19 | "data": { 20 | "dispatchError": "BadOrigin", 21 | "dispatchInfo": { 22 | "class": "Normal", 23 | "paysFee": "Yes", 24 | "weight": { 25 | "proofSize": "(rounded 13000)", 26 | "refTime": "(rounded 980000000)", 27 | }, 28 | }, 29 | }, 30 | "method": "ExtrinsicFailed", 31 | "section": "system", 32 | }, 33 | ] 34 | `; 35 | 36 | exports[`Polkadot Asset Hub Vesting > test merger of two vesting schedules > vesting events 1 1`] = ` 37 | [ 38 | { 39 | "data": { 40 | "account": "16D2eVuK5SWfwvtFD3gVdBC2nc2BafK31BY6PrbZHBAGew7L", 41 | "unvested": "(rounded 25000000000)", 42 | }, 43 | "method": "VestingUpdated", 44 | "section": "vesting", 45 | }, 46 | ] 47 | `; 48 | 49 | exports[`Polkadot Asset Hub Vesting > test merger of two vesting schedules > vesting events 2 1`] = ` 50 | [ 51 | { 52 | "data": { 53 | "account": "16D2eVuK5SWfwvtFD3gVdBC2nc2BafK31BY6PrbZHBAGew7L", 54 | "unvested": "(rounded 76000000000)", 55 | }, 56 | "method": "VestingUpdated", 57 | "section": "vesting", 58 | }, 59 | ] 60 | `; 61 | 62 | exports[`Polkadot Asset Hub Vesting > test merger of two vesting schedules > vesting schedules merger events 1`] = ` 63 | [ 64 | { 65 | "data": { 66 | "account": "16D2eVuK5SWfwvtFD3gVdBC2nc2BafK31BY6PrbZHBAGew7L", 67 | "unvested": "(rounded 70000000000)", 68 | }, 69 | "method": "VestingUpdated", 70 | "section": "vesting", 71 | }, 72 | ] 73 | `; 74 | 75 | exports[`Polkadot Asset Hub Vesting > vesting schedule lifecycle > vest events 1`] = ` 76 | [ 77 | { 78 | "data": { 79 | "account": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", 80 | "unvested": 5000000000, 81 | }, 82 | "method": "VestingUpdated", 83 | "section": "vesting", 84 | }, 85 | ] 86 | `; 87 | 88 | exports[`Polkadot Asset Hub Vesting > vesting schedule lifecycle > vest events 2`] = ` 89 | [ 90 | { 91 | "data": { 92 | "account": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", 93 | }, 94 | "method": "VestingCompleted", 95 | "section": "vesting", 96 | }, 97 | ] 98 | `; 99 | 100 | exports[`Polkadot Asset Hub Vesting > vesting schedule lifecycle > vest other events 1`] = ` 101 | [ 102 | { 103 | "data": { 104 | "account": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", 105 | "unvested": 2500000000, 106 | }, 107 | "method": "VestingUpdated", 108 | "section": "vesting", 109 | }, 110 | ] 111 | `; 112 | -------------------------------------------------------------------------------- /packages/polkadot/src/__snapshots__/polkadot.assetHubPolkadot.collectivesPolkadot.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`polkadot & asset hub & collectives > Relay authorizes AssetHub upgrade via Collectives > collectives events emitted when sending xcm 1`] = ` 4 | [ 5 | { 6 | "data": { 7 | "fees": [ 8 | { 9 | "fun": { 10 | "Fungible": "(rounded 300000000)", 11 | }, 12 | "id": { 13 | "interior": "Here", 14 | "parents": 1, 15 | }, 16 | }, 17 | ], 18 | "paying": { 19 | "interior": { 20 | "X1": [ 21 | { 22 | "Plurality": { 23 | "id": "Technical", 24 | "part": "Voice", 25 | }, 26 | }, 27 | ], 28 | }, 29 | "parents": 0, 30 | }, 31 | }, 32 | "method": "FeesPaid", 33 | "section": "polkadotXcm", 34 | }, 35 | { 36 | "data": { 37 | "destination": { 38 | "interior": "Here", 39 | "parents": 1, 40 | }, 41 | "message": [ 42 | { 43 | "UnpaidExecution": { 44 | "checkOrigin": null, 45 | "weightLimit": "Unlimited", 46 | }, 47 | }, 48 | { 49 | "Transact": { 50 | "call": { 51 | "encoded": "0x170089ba36353c2150427d20dc71ab18e6762c07f560a6e485f64c26a608abecb473", 52 | }, 53 | "fallbackMaxWeight": { 54 | "proofSize": 10000, 55 | "refTime": 500000000, 56 | }, 57 | "originKind": "Xcm", 58 | }, 59 | }, 60 | ], 61 | "messageId": "(redacted)", 62 | "origin": { 63 | "interior": { 64 | "X1": [ 65 | { 66 | "Plurality": { 67 | "id": "Technical", 68 | "part": "Voice", 69 | }, 70 | }, 71 | ], 72 | }, 73 | "parents": 0, 74 | }, 75 | }, 76 | "method": "Sent", 77 | "section": "polkadotXcm", 78 | }, 79 | ] 80 | `; 81 | 82 | exports[`polkadot & asset hub & collectives > Relay authorizes AssetHub upgrade via Collectives > events after notePreimge 1`] = ` 83 | [ 84 | { 85 | "data": { 86 | "hash_": "(hash)", 87 | }, 88 | "method": "Noted", 89 | "section": "preimage", 90 | }, 91 | ] 92 | `; 93 | 94 | exports[`polkadot & asset hub & collectives > Relay authorizes AssetHub upgrade via Collectives > events when dispatching non-whitelisted call 1`] = ` 95 | [ 96 | { 97 | "data": { 98 | "id": null, 99 | "result": { 100 | "Err": { 101 | "Module": { 102 | "error": "0x03000000", 103 | "index": 23, 104 | }, 105 | }, 106 | }, 107 | "task": "(redacted)", 108 | }, 109 | "method": "Dispatched", 110 | "section": "scheduler", 111 | }, 112 | ] 113 | `; 114 | 115 | exports[`polkadot & asset hub & collectives > Relay authorizes AssetHub upgrade via Collectives > events when dispatching whitelisted call with bad origin 1`] = ` 116 | [ 117 | { 118 | "data": { 119 | "id": null, 120 | "result": { 121 | "Err": "BadOrigin", 122 | }, 123 | "task": "(redacted)", 124 | }, 125 | "method": "Dispatched", 126 | "section": "scheduler", 127 | }, 128 | ] 129 | `; 130 | 131 | exports[`polkadot & asset hub & collectives > Relay authorizes AssetHub upgrade via Collectives > governing chain events about dispatching whitelisted call 1`] = ` 132 | [ 133 | { 134 | "data": { 135 | "callHash": "0x89ba36353c2150427d20dc71ab18e6762c07f560a6e485f64c26a608abecb473", 136 | "result": { 137 | "Ok": { 138 | "actualWeight": { 139 | "proofSize": "(rounded 3500)", 140 | "refTime": "(rounded 290000000)", 141 | }, 142 | "paysFee": "Yes", 143 | }, 144 | }, 145 | }, 146 | "method": "WhitelistedCallDispatched", 147 | "section": "whitelist", 148 | }, 149 | ] 150 | `; 151 | 152 | exports[`polkadot & asset hub & collectives > Relay authorizes AssetHub upgrade via Collectives > governing chain events emitted on receiving xcm from collectives 1`] = ` 153 | [ 154 | { 155 | "data": { 156 | "callHash": "0x89ba36353c2150427d20dc71ab18e6762c07f560a6e485f64c26a608abecb473", 157 | }, 158 | "method": "CallWhitelisted", 159 | "section": "whitelist", 160 | }, 161 | { 162 | "data": { 163 | "id": "(redacted)", 164 | "origin": { 165 | "Ump": { 166 | "Para": "(rounded 1000)", 167 | }, 168 | }, 169 | "success": true, 170 | "weightUsed": { 171 | "proofSize": "(rounded 3600)", 172 | "refTime": "(rounded 270000000)", 173 | }, 174 | }, 175 | "method": "Processed", 176 | "section": "messageQueue", 177 | }, 178 | ] 179 | `; 180 | 181 | exports[`polkadot & asset hub & collectives > Relay authorizes AssetHub upgrade via Collectives > to-be-upgraded chain events to confirm authorized upgrade 1`] = ` 182 | [ 183 | { 184 | "data": { 185 | "checkVersion": true, 186 | "codeHash": "0x0101010101010101010101010101010101010101010101010101010101010101", 187 | }, 188 | "method": "UpgradeAuthorized", 189 | "section": "system", 190 | }, 191 | { 192 | "data": { 193 | "id": "(redacted)", 194 | "origin": "Parent", 195 | "success": true, 196 | "weightUsed": { 197 | "proofSize": 0, 198 | "refTime": "(rounded 120000000)", 199 | }, 200 | }, 201 | "method": "Processed", 202 | "section": "messageQueue", 203 | }, 204 | ] 205 | `; 206 | -------------------------------------------------------------------------------- /packages/polkadot/src/__snapshots__/polkadot.bridgeHubPolkadot.collectivesPolkadot.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`polkadot & bridgeHub & collectives > Relay authorizes Bridge Hub upgrade via Collectives > collectives events emitted when sending xcm 1`] = ` 4 | [ 5 | { 6 | "data": { 7 | "fees": [ 8 | { 9 | "fun": { 10 | "Fungible": "(rounded 300000000)", 11 | }, 12 | "id": { 13 | "interior": "Here", 14 | "parents": 1, 15 | }, 16 | }, 17 | ], 18 | "paying": { 19 | "interior": { 20 | "X1": [ 21 | { 22 | "Plurality": { 23 | "id": "Technical", 24 | "part": "Voice", 25 | }, 26 | }, 27 | ], 28 | }, 29 | "parents": 0, 30 | }, 31 | }, 32 | "method": "FeesPaid", 33 | "section": "polkadotXcm", 34 | }, 35 | { 36 | "data": { 37 | "destination": { 38 | "interior": "Here", 39 | "parents": 1, 40 | }, 41 | "message": [ 42 | { 43 | "UnpaidExecution": { 44 | "checkOrigin": null, 45 | "weightLimit": "Unlimited", 46 | }, 47 | }, 48 | { 49 | "Transact": { 50 | "call": { 51 | "encoded": "0x1700bec38f9174094d5d36794d04bd0b9d4a4da7ad1db83473bce75b31b465d95a7b", 52 | }, 53 | "fallbackMaxWeight": { 54 | "proofSize": 10000, 55 | "refTime": 500000000, 56 | }, 57 | "originKind": "Xcm", 58 | }, 59 | }, 60 | ], 61 | "messageId": "(redacted)", 62 | "origin": { 63 | "interior": { 64 | "X1": [ 65 | { 66 | "Plurality": { 67 | "id": "Technical", 68 | "part": "Voice", 69 | }, 70 | }, 71 | ], 72 | }, 73 | "parents": 0, 74 | }, 75 | }, 76 | "method": "Sent", 77 | "section": "polkadotXcm", 78 | }, 79 | ] 80 | `; 81 | 82 | exports[`polkadot & bridgeHub & collectives > Relay authorizes Bridge Hub upgrade via Collectives > events after notePreimge 1`] = ` 83 | [ 84 | { 85 | "data": { 86 | "hash_": "(hash)", 87 | }, 88 | "method": "Noted", 89 | "section": "preimage", 90 | }, 91 | ] 92 | `; 93 | 94 | exports[`polkadot & bridgeHub & collectives > Relay authorizes Bridge Hub upgrade via Collectives > events when dispatching non-whitelisted call 1`] = ` 95 | [ 96 | { 97 | "data": { 98 | "id": null, 99 | "result": { 100 | "Err": { 101 | "Module": { 102 | "error": "0x03000000", 103 | "index": 23, 104 | }, 105 | }, 106 | }, 107 | "task": "(redacted)", 108 | }, 109 | "method": "Dispatched", 110 | "section": "scheduler", 111 | }, 112 | ] 113 | `; 114 | 115 | exports[`polkadot & bridgeHub & collectives > Relay authorizes Bridge Hub upgrade via Collectives > events when dispatching whitelisted call with bad origin 1`] = ` 116 | [ 117 | { 118 | "data": { 119 | "id": null, 120 | "result": { 121 | "Err": "BadOrigin", 122 | }, 123 | "task": "(redacted)", 124 | }, 125 | "method": "Dispatched", 126 | "section": "scheduler", 127 | }, 128 | ] 129 | `; 130 | 131 | exports[`polkadot & bridgeHub & collectives > Relay authorizes Bridge Hub upgrade via Collectives > governing chain events about dispatching whitelisted call 1`] = ` 132 | [ 133 | { 134 | "data": { 135 | "callHash": "0xbec38f9174094d5d36794d04bd0b9d4a4da7ad1db83473bce75b31b465d95a7b", 136 | "result": { 137 | "Ok": { 138 | "actualWeight": { 139 | "proofSize": "(rounded 3500)", 140 | "refTime": "(rounded 290000000)", 141 | }, 142 | "paysFee": "Yes", 143 | }, 144 | }, 145 | }, 146 | "method": "WhitelistedCallDispatched", 147 | "section": "whitelist", 148 | }, 149 | ] 150 | `; 151 | 152 | exports[`polkadot & bridgeHub & collectives > Relay authorizes Bridge Hub upgrade via Collectives > governing chain events emitted on receiving xcm from collectives 1`] = ` 153 | [ 154 | { 155 | "data": { 156 | "callHash": "0xbec38f9174094d5d36794d04bd0b9d4a4da7ad1db83473bce75b31b465d95a7b", 157 | }, 158 | "method": "CallWhitelisted", 159 | "section": "whitelist", 160 | }, 161 | { 162 | "data": { 163 | "id": "(redacted)", 164 | "origin": { 165 | "Ump": { 166 | "Para": "(rounded 1000)", 167 | }, 168 | }, 169 | "success": true, 170 | "weightUsed": { 171 | "proofSize": "(rounded 3600)", 172 | "refTime": "(rounded 270000000)", 173 | }, 174 | }, 175 | "method": "Processed", 176 | "section": "messageQueue", 177 | }, 178 | ] 179 | `; 180 | 181 | exports[`polkadot & bridgeHub & collectives > Relay authorizes Bridge Hub upgrade via Collectives > to-be-upgraded chain events to confirm authorized upgrade 1`] = ` 182 | [ 183 | { 184 | "data": { 185 | "checkVersion": true, 186 | "codeHash": "0x0101010101010101010101010101010101010101010101010101010101010101", 187 | }, 188 | "method": "UpgradeAuthorized", 189 | "section": "system", 190 | }, 191 | { 192 | "data": { 193 | "id": "(redacted)", 194 | "origin": "Parent", 195 | "success": true, 196 | "weightUsed": { 197 | "proofSize": 0, 198 | "refTime": "(rounded 140000000)", 199 | }, 200 | }, 201 | "method": "Processed", 202 | "section": "messageQueue", 203 | }, 204 | ] 205 | `; 206 | -------------------------------------------------------------------------------- /packages/polkadot/src/__snapshots__/polkadot.coretimePolkadot.collectivesPolkadot.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`polkadot & coretime & collectives > Relay authorizes Coretime upgrade via Collectives > collectives events emitted when sending xcm 1`] = ` 4 | [ 5 | { 6 | "data": { 7 | "fees": [ 8 | { 9 | "fun": { 10 | "Fungible": "(rounded 300000000)", 11 | }, 12 | "id": { 13 | "interior": "Here", 14 | "parents": 1, 15 | }, 16 | }, 17 | ], 18 | "paying": { 19 | "interior": { 20 | "X1": [ 21 | { 22 | "Plurality": { 23 | "id": "Technical", 24 | "part": "Voice", 25 | }, 26 | }, 27 | ], 28 | }, 29 | "parents": 0, 30 | }, 31 | }, 32 | "method": "FeesPaid", 33 | "section": "polkadotXcm", 34 | }, 35 | { 36 | "data": { 37 | "destination": { 38 | "interior": "Here", 39 | "parents": 1, 40 | }, 41 | "message": [ 42 | { 43 | "UnpaidExecution": { 44 | "checkOrigin": null, 45 | "weightLimit": "Unlimited", 46 | }, 47 | }, 48 | { 49 | "Transact": { 50 | "call": { 51 | "encoded": "0x17008097b9f2e0aa4ab3b2b40d8912071ce5fd27e15432afcd3b204548d56468f21b", 52 | }, 53 | "fallbackMaxWeight": { 54 | "proofSize": 10000, 55 | "refTime": 500000000, 56 | }, 57 | "originKind": "Xcm", 58 | }, 59 | }, 60 | ], 61 | "messageId": "(redacted)", 62 | "origin": { 63 | "interior": { 64 | "X1": [ 65 | { 66 | "Plurality": { 67 | "id": "Technical", 68 | "part": "Voice", 69 | }, 70 | }, 71 | ], 72 | }, 73 | "parents": 0, 74 | }, 75 | }, 76 | "method": "Sent", 77 | "section": "polkadotXcm", 78 | }, 79 | ] 80 | `; 81 | 82 | exports[`polkadot & coretime & collectives > Relay authorizes Coretime upgrade via Collectives > events after notePreimge 1`] = ` 83 | [ 84 | { 85 | "data": { 86 | "hash_": "(hash)", 87 | }, 88 | "method": "Noted", 89 | "section": "preimage", 90 | }, 91 | ] 92 | `; 93 | 94 | exports[`polkadot & coretime & collectives > Relay authorizes Coretime upgrade via Collectives > events when dispatching non-whitelisted call 1`] = ` 95 | [ 96 | { 97 | "data": { 98 | "id": null, 99 | "result": { 100 | "Err": { 101 | "Module": { 102 | "error": "0x03000000", 103 | "index": 23, 104 | }, 105 | }, 106 | }, 107 | "task": "(redacted)", 108 | }, 109 | "method": "Dispatched", 110 | "section": "scheduler", 111 | }, 112 | ] 113 | `; 114 | 115 | exports[`polkadot & coretime & collectives > Relay authorizes Coretime upgrade via Collectives > events when dispatching whitelisted call with bad origin 1`] = ` 116 | [ 117 | { 118 | "data": { 119 | "id": null, 120 | "result": { 121 | "Err": "BadOrigin", 122 | }, 123 | "task": "(redacted)", 124 | }, 125 | "method": "Dispatched", 126 | "section": "scheduler", 127 | }, 128 | ] 129 | `; 130 | 131 | exports[`polkadot & coretime & collectives > Relay authorizes Coretime upgrade via Collectives > governing chain events about dispatching whitelisted call 1`] = ` 132 | [ 133 | { 134 | "data": { 135 | "callHash": "0x8097b9f2e0aa4ab3b2b40d8912071ce5fd27e15432afcd3b204548d56468f21b", 136 | "result": { 137 | "Ok": { 138 | "actualWeight": { 139 | "proofSize": "(rounded 3500)", 140 | "refTime": "(rounded 290000000)", 141 | }, 142 | "paysFee": "Yes", 143 | }, 144 | }, 145 | }, 146 | "method": "WhitelistedCallDispatched", 147 | "section": "whitelist", 148 | }, 149 | ] 150 | `; 151 | 152 | exports[`polkadot & coretime & collectives > Relay authorizes Coretime upgrade via Collectives > governing chain events emitted on receiving xcm from collectives 1`] = ` 153 | [ 154 | { 155 | "data": { 156 | "callHash": "0x8097b9f2e0aa4ab3b2b40d8912071ce5fd27e15432afcd3b204548d56468f21b", 157 | }, 158 | "method": "CallWhitelisted", 159 | "section": "whitelist", 160 | }, 161 | { 162 | "data": { 163 | "id": "(redacted)", 164 | "origin": { 165 | "Ump": { 166 | "Para": "(rounded 1000)", 167 | }, 168 | }, 169 | "success": true, 170 | "weightUsed": { 171 | "proofSize": "(rounded 3600)", 172 | "refTime": "(rounded 270000000)", 173 | }, 174 | }, 175 | "method": "Processed", 176 | "section": "messageQueue", 177 | }, 178 | ] 179 | `; 180 | 181 | exports[`polkadot & coretime & collectives > Relay authorizes Coretime upgrade via Collectives > to-be-upgraded chain events to confirm authorized upgrade 1`] = ` 182 | [ 183 | { 184 | "data": { 185 | "checkVersion": true, 186 | "codeHash": "0x0101010101010101010101010101010101010101010101010101010101010101", 187 | }, 188 | "method": "UpgradeAuthorized", 189 | "section": "system", 190 | }, 191 | { 192 | "data": { 193 | "id": "(redacted)", 194 | "origin": "Parent", 195 | "success": true, 196 | "weightUsed": { 197 | "proofSize": 0, 198 | "refTime": "(rounded 140000000)", 199 | }, 200 | }, 201 | "method": "Processed", 202 | "section": "messageQueue", 203 | }, 204 | ] 205 | `; 206 | -------------------------------------------------------------------------------- /packages/polkadot/src/__snapshots__/polkadot.peoplePolkadot.collectivesPolkadot.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`polkadot & people & collectives > Relay authorizes People upgrade via Collectives > collectives events emitted when sending xcm 1`] = ` 4 | [ 5 | { 6 | "data": { 7 | "fees": [ 8 | { 9 | "fun": { 10 | "Fungible": "(rounded 300000000)", 11 | }, 12 | "id": { 13 | "interior": "Here", 14 | "parents": 1, 15 | }, 16 | }, 17 | ], 18 | "paying": { 19 | "interior": { 20 | "X1": [ 21 | { 22 | "Plurality": { 23 | "id": "Technical", 24 | "part": "Voice", 25 | }, 26 | }, 27 | ], 28 | }, 29 | "parents": 0, 30 | }, 31 | }, 32 | "method": "FeesPaid", 33 | "section": "polkadotXcm", 34 | }, 35 | { 36 | "data": { 37 | "destination": { 38 | "interior": "Here", 39 | "parents": 1, 40 | }, 41 | "message": [ 42 | { 43 | "UnpaidExecution": { 44 | "checkOrigin": null, 45 | "weightLimit": "Unlimited", 46 | }, 47 | }, 48 | { 49 | "Transact": { 50 | "call": { 51 | "encoded": "0x1700f2c2a9c39f6739fafc398dbf1d47610daa6c6deaa774e9885ad95fa6a3bdebac", 52 | }, 53 | "fallbackMaxWeight": { 54 | "proofSize": 10000, 55 | "refTime": 500000000, 56 | }, 57 | "originKind": "Xcm", 58 | }, 59 | }, 60 | ], 61 | "messageId": "(redacted)", 62 | "origin": { 63 | "interior": { 64 | "X1": [ 65 | { 66 | "Plurality": { 67 | "id": "Technical", 68 | "part": "Voice", 69 | }, 70 | }, 71 | ], 72 | }, 73 | "parents": 0, 74 | }, 75 | }, 76 | "method": "Sent", 77 | "section": "polkadotXcm", 78 | }, 79 | ] 80 | `; 81 | 82 | exports[`polkadot & people & collectives > Relay authorizes People upgrade via Collectives > events after notePreimge 1`] = ` 83 | [ 84 | { 85 | "data": { 86 | "hash_": "(hash)", 87 | }, 88 | "method": "Noted", 89 | "section": "preimage", 90 | }, 91 | ] 92 | `; 93 | 94 | exports[`polkadot & people & collectives > Relay authorizes People upgrade via Collectives > events when dispatching non-whitelisted call 1`] = ` 95 | [ 96 | { 97 | "data": { 98 | "id": null, 99 | "result": { 100 | "Err": { 101 | "Module": { 102 | "error": "0x03000000", 103 | "index": 23, 104 | }, 105 | }, 106 | }, 107 | "task": "(redacted)", 108 | }, 109 | "method": "Dispatched", 110 | "section": "scheduler", 111 | }, 112 | ] 113 | `; 114 | 115 | exports[`polkadot & people & collectives > Relay authorizes People upgrade via Collectives > events when dispatching whitelisted call with bad origin 1`] = ` 116 | [ 117 | { 118 | "data": { 119 | "id": null, 120 | "result": { 121 | "Err": "BadOrigin", 122 | }, 123 | "task": "(redacted)", 124 | }, 125 | "method": "Dispatched", 126 | "section": "scheduler", 127 | }, 128 | ] 129 | `; 130 | 131 | exports[`polkadot & people & collectives > Relay authorizes People upgrade via Collectives > governing chain events about dispatching whitelisted call 1`] = ` 132 | [ 133 | { 134 | "data": { 135 | "callHash": "0xf2c2a9c39f6739fafc398dbf1d47610daa6c6deaa774e9885ad95fa6a3bdebac", 136 | "result": { 137 | "Ok": { 138 | "actualWeight": { 139 | "proofSize": "(rounded 3500)", 140 | "refTime": "(rounded 290000000)", 141 | }, 142 | "paysFee": "Yes", 143 | }, 144 | }, 145 | }, 146 | "method": "WhitelistedCallDispatched", 147 | "section": "whitelist", 148 | }, 149 | ] 150 | `; 151 | 152 | exports[`polkadot & people & collectives > Relay authorizes People upgrade via Collectives > governing chain events emitted on receiving xcm from collectives 1`] = ` 153 | [ 154 | { 155 | "data": { 156 | "callHash": "0xf2c2a9c39f6739fafc398dbf1d47610daa6c6deaa774e9885ad95fa6a3bdebac", 157 | }, 158 | "method": "CallWhitelisted", 159 | "section": "whitelist", 160 | }, 161 | { 162 | "data": { 163 | "id": "(redacted)", 164 | "origin": { 165 | "Ump": { 166 | "Para": "(rounded 1000)", 167 | }, 168 | }, 169 | "success": true, 170 | "weightUsed": { 171 | "proofSize": "(rounded 3600)", 172 | "refTime": "(rounded 270000000)", 173 | }, 174 | }, 175 | "method": "Processed", 176 | "section": "messageQueue", 177 | }, 178 | ] 179 | `; 180 | 181 | exports[`polkadot & people & collectives > Relay authorizes People upgrade via Collectives > to-be-upgraded chain events to confirm authorized upgrade 1`] = ` 182 | [ 183 | { 184 | "data": { 185 | "checkVersion": true, 186 | "codeHash": "0x0101010101010101010101010101010101010101010101010101010101010101", 187 | }, 188 | "method": "UpgradeAuthorized", 189 | "section": "system", 190 | }, 191 | { 192 | "data": { 193 | "id": "(redacted)", 194 | "origin": "Parent", 195 | "success": true, 196 | "weightUsed": { 197 | "proofSize": 0, 198 | "refTime": "(rounded 130000000)", 199 | }, 200 | }, 201 | "method": "Processed", 202 | "section": "messageQueue", 203 | }, 204 | ] 205 | `; 206 | -------------------------------------------------------------------------------- /packages/polkadot/src/__snapshots__/polkadot.vesting.e2e.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`Polkadot Vesting > forced vested transfer and forced removal of vesting schedule work > forced vested transfer event 1`] = ` 4 | [ 5 | "126TwBzBM4jUEK2gTphmW4oLoBWWnYvPp8hygmduTr4uds57", 6 | 5000000000, 7 | ] 8 | `; 9 | 10 | exports[`Polkadot Vesting > forced vested transfer and forced removal of vesting schedule work > forced vesting removal event 1`] = ` 11 | [ 12 | "126TwBzBM4jUEK2gTphmW4oLoBWWnYvPp8hygmduTr4uds57", 13 | ] 14 | `; 15 | 16 | exports[`Polkadot Vesting > signed-origin force-vested transfer fails > force vest events 1`] = ` 17 | [ 18 | { 19 | "data": { 20 | "dispatchError": "BadOrigin", 21 | "dispatchInfo": { 22 | "class": "Normal", 23 | "paysFee": "Yes", 24 | "weight": { 25 | "proofSize": "(rounded 13000)", 26 | "refTime": "(rounded 980000000)", 27 | }, 28 | }, 29 | }, 30 | "method": "ExtrinsicFailed", 31 | "section": "system", 32 | }, 33 | ] 34 | `; 35 | 36 | exports[`Polkadot Vesting > test merger of two vesting schedules > vesting events 1 1`] = ` 37 | [ 38 | { 39 | "data": { 40 | "account": "16D2eVuK5SWfwvtFD3gVdBC2nc2BafK31BY6PrbZHBAGew7L", 41 | "unvested": "(rounded 25000000000)", 42 | }, 43 | "method": "VestingUpdated", 44 | "section": "vesting", 45 | }, 46 | ] 47 | `; 48 | 49 | exports[`Polkadot Vesting > test merger of two vesting schedules > vesting events 2 1`] = ` 50 | [ 51 | { 52 | "data": { 53 | "account": "16D2eVuK5SWfwvtFD3gVdBC2nc2BafK31BY6PrbZHBAGew7L", 54 | "unvested": "(rounded 76000000000)", 55 | }, 56 | "method": "VestingUpdated", 57 | "section": "vesting", 58 | }, 59 | ] 60 | `; 61 | 62 | exports[`Polkadot Vesting > test merger of two vesting schedules > vesting schedules merger events 1`] = ` 63 | [ 64 | { 65 | "data": { 66 | "account": "16D2eVuK5SWfwvtFD3gVdBC2nc2BafK31BY6PrbZHBAGew7L", 67 | "unvested": "(rounded 70000000000)", 68 | }, 69 | "method": "VestingUpdated", 70 | "section": "vesting", 71 | }, 72 | ] 73 | `; 74 | 75 | exports[`Polkadot Vesting > vesting schedule lifecycle > vest events 1`] = ` 76 | [ 77 | { 78 | "data": { 79 | "account": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", 80 | "unvested": 5000000000, 81 | }, 82 | "method": "VestingUpdated", 83 | "section": "vesting", 84 | }, 85 | ] 86 | `; 87 | 88 | exports[`Polkadot Vesting > vesting schedule lifecycle > vest events 2`] = ` 89 | [ 90 | { 91 | "data": { 92 | "account": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", 93 | }, 94 | "method": "VestingCompleted", 95 | "section": "vesting", 96 | }, 97 | ] 98 | `; 99 | 100 | exports[`Polkadot Vesting > vesting schedule lifecycle > vest other events 1`] = ` 101 | [ 102 | { 103 | "data": { 104 | "account": "14E5nqKAp3oAJcmzgZhUD2RcptBeUBScxKHgJKU4HPNcKVf3", 105 | "unvested": 2500000000, 106 | }, 107 | "method": "VestingUpdated", 108 | "section": "vesting", 109 | }, 110 | ] 111 | `; 112 | -------------------------------------------------------------------------------- /packages/polkadot/src/acala.assetHubPolkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { acala, assetHubPolkadot } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletHorizontal, runXtokenstHorizontal } from '@e2e-test/shared/xcm' 8 | 9 | describe('acala & assetHubPolkadot', async () => { 10 | const [assetHubPolkadotClient, acalaClient] = await setupNetworks(assetHubPolkadot, acala) 11 | 12 | runXcmPalletHorizontal('assetHubPolkadot transfer USDT to acala', async () => { 13 | return { 14 | fromChain: assetHubPolkadotClient, 15 | toChain: acalaClient, 16 | fromBalance: query.assets(assetHubPolkadot.custom.usdtIndex), 17 | toBalance: query.tokens(acala.custom.usdt), 18 | tx: tx.xcmPallet.limitedReserveTransferAssetsV3( 19 | assetHubPolkadot.custom.usdt, 20 | 1e6, 21 | tx.xcmPallet.parachainV3(1, acala.paraId!), 22 | ), 23 | } 24 | }) 25 | 26 | runXtokenstHorizontal('acala transfer USDT to assetHubPolkadot', async () => { 27 | await acalaClient.dev.setStorage({ 28 | Tokens: { 29 | Accounts: [[[defaultAccounts.alice.address, acala.custom.usdt], { free: 10e6 }]], 30 | }, 31 | }) 32 | 33 | return { 34 | fromChain: acalaClient, 35 | toChain: assetHubPolkadotClient, 36 | fromBalance: query.tokens(acala.custom.usdt), 37 | toBalance: query.assets(assetHubPolkadot.custom.usdtIndex), 38 | tx: tx.xtokens.transfer(acala.custom.usdt, 1e6, tx.xtokens.parachainV3(assetHubPolkadot.paraId!)), 39 | precision: 1, 40 | } 41 | }) 42 | 43 | runXcmPalletHorizontal('assetHubPolkadot transfer ETH to acala', async () => { 44 | return { 45 | fromChain: assetHubPolkadotClient, 46 | toChain: acalaClient, 47 | fromBalance: query.foreignAssets(assetHubPolkadot.custom.eth), 48 | toBalance: query.tokens(acala.custom.eth), 49 | tx: tx.xcmPallet.transferAssetsUsingType( 50 | tx.xcmPallet.parachainV4(1, acala.paraId!), 51 | [ 52 | { 53 | id: assetHubPolkadot.custom.eth, 54 | fun: { Fungible: 10n ** 17n }, 55 | }, 56 | ], 57 | 'LocalReserve', 58 | assetHubPolkadot.custom.eth, 59 | 'LocalReserve', 60 | ), 61 | } 62 | }) 63 | 64 | runXcmPalletHorizontal('acala transfer ETH to assetHubPolkadot', async () => { 65 | await acalaClient.dev.setStorage({ 66 | Tokens: { 67 | Accounts: [[[defaultAccounts.alice.address, acala.custom.eth], { free: 10n ** 18n }]], 68 | TotalIssuance: [[[acala.custom.eth], 10n ** 19n]], 69 | }, 70 | }) 71 | 72 | return { 73 | fromChain: acalaClient, 74 | toChain: assetHubPolkadotClient, 75 | fromBalance: query.tokens(acala.custom.eth), 76 | toBalance: query.foreignAssets(assetHubPolkadot.custom.eth), 77 | tx: tx.xcmPallet.transferAssetsUsingType( 78 | tx.xcmPallet.parachainV4(1, assetHubPolkadot.paraId!), 79 | [ 80 | { 81 | id: assetHubPolkadot.custom.eth, 82 | fun: { Fungible: 10n ** 17n }, 83 | }, 84 | ], 85 | 'DestinationReserve', 86 | assetHubPolkadot.custom.eth, 87 | 'DestinationReserve', 88 | ), 89 | } 90 | }) 91 | }) 92 | -------------------------------------------------------------------------------- /packages/polkadot/src/acala.astar.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { acala, astar } from '@e2e-test/networks/chains' 4 | import { setupNetworks } from '@e2e-test/shared' 5 | import { query, tx } from '@e2e-test/shared/api' 6 | import { runXtokenstHorizontal } from '@e2e-test/shared/xcm' 7 | 8 | describe('acala & astar', async () => { 9 | const [astarClient, acalaClient] = await setupNetworks(astar, acala) 10 | 11 | runXtokenstHorizontal('astar transfer ACA to acala', async () => { 12 | return { 13 | fromChain: astarClient, 14 | toChain: acalaClient, 15 | fromBalance: query.assets(astar.custom.aca), 16 | toBalance: query.balances, 17 | tx: tx.xtokens.transfer(astar.custom.aca, 1e12, tx.xtokens.parachainV3(acala.paraId!)), 18 | } 19 | }) 20 | 21 | runXtokenstHorizontal('acala transfer ACA to astar', async () => { 22 | return { 23 | fromChain: acalaClient, 24 | toChain: astarClient, 25 | fromBalance: query.balances, 26 | toBalance: query.assets(astar.custom.aca), 27 | tx: tx.xtokens.transfer(acala.custom.aca, 1e12, tx.xtokens.parachainV3(astar.paraId!)), 28 | } 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /packages/polkadot/src/acala.moonbeam.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { acala, moonbeam, polkadot } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletHorizontal, runXtokenstHorizontal } from '@e2e-test/shared/xcm' 8 | 9 | describe( 10 | 'acala & moonbeam', 11 | async () => { 12 | const [acalaClient, moonbeamClient, polkadotClient] = await setupNetworks(acala, moonbeam, polkadot) 13 | 14 | const acalaDot = acala.custom.dot 15 | const moonbeamDot = moonbeam.custom.dot 16 | 17 | runXtokenstHorizontal('acala transfer DOT to moonbeam', async () => { 18 | return { 19 | fromChain: acalaClient, 20 | fromBalance: query.tokens(acalaDot), 21 | fromAccount: defaultAccounts.alice, 22 | 23 | toChain: moonbeamClient, 24 | toBalance: query.assets(moonbeamDot), 25 | toAccount: defaultAccounts.alith, 26 | 27 | routeChain: polkadotClient, 28 | isCheckUmp: true, 29 | 30 | tx: tx.xtokens.transfer(acalaDot, 1e12, tx.xtokens.parachainAccountId20V3(moonbeam.paraId!)), 31 | } 32 | }) 33 | 34 | runXcmPalletHorizontal('moonbeam transfer DOT to acala', async () => { 35 | await moonbeamClient.dev.setStorage({ 36 | Assets: { 37 | account: [[[moonbeamDot, defaultAccounts.alith.address], { balance: 10e12 }]], 38 | }, 39 | }) 40 | 41 | return { 42 | fromChain: moonbeamClient, 43 | fromBalance: query.assets(moonbeamDot), 44 | fromAccount: defaultAccounts.alith, 45 | 46 | toChain: acalaClient, 47 | toBalance: query.tokens(acalaDot), 48 | toAccount: defaultAccounts.alice, 49 | 50 | routeChain: polkadotClient, 51 | isCheckUmp: true, 52 | 53 | tx: tx.xcmPallet.transferAssetsV3(moonbeam.custom.xcmDot, 1e12, tx.xcmPallet.parachainV3(1, acala.paraId!)), 54 | } 55 | }) 56 | 57 | runXtokenstHorizontal('acala transfer ACA to moonbeam', async () => { 58 | return { 59 | fromChain: acalaClient, 60 | fromBalance: query.balances, 61 | fromAccount: defaultAccounts.alice, 62 | 63 | toChain: moonbeamClient, 64 | toBalance: query.assets(moonbeam.custom.aca), 65 | toAccount: defaultAccounts.baltathar, 66 | 67 | tx: tx.xtokens.transfer(acala.custom.aca, 1e12, tx.xtokens.parachainAccountId20V3(moonbeam.paraId!)), 68 | } 69 | }) 70 | 71 | runXcmPalletHorizontal('moonbeam transfer ACA to acala', async () => { 72 | await moonbeamClient.dev.setStorage({ 73 | Assets: { 74 | account: [[[moonbeam.custom.aca, defaultAccounts.alith.address], { balance: 10e12 }]], 75 | }, 76 | }) 77 | 78 | return { 79 | fromChain: moonbeamClient, 80 | fromBalance: query.assets(moonbeam.custom.aca), 81 | fromAccount: defaultAccounts.alith, 82 | 83 | toChain: acalaClient, 84 | toBalance: query.balances, 85 | toAccount: defaultAccounts.bob, 86 | 87 | tx: tx.xcmPallet.transferAssetsV3(moonbeam.custom.xcmAca, 1e12, tx.xcmPallet.parachainV3(1, acala.paraId!)), 88 | } 89 | }) 90 | 91 | runXtokenstHorizontal('acala transfer LDOT to moonbeam', async () => { 92 | return { 93 | fromChain: acalaClient, 94 | fromBalance: query.tokens(acala.custom.ldot), 95 | fromAccount: defaultAccounts.alice, 96 | 97 | toChain: moonbeamClient, 98 | toBalance: query.assets(moonbeam.custom.ldot), 99 | toAccount: defaultAccounts.baltathar, 100 | 101 | tx: tx.xtokens.transfer(acala.custom.ldot, 1e12, tx.xtokens.parachainAccountId20V3(moonbeam.paraId!)), 102 | } 103 | }) 104 | 105 | runXcmPalletHorizontal('moonbeam transfer LDOT to acala', async () => { 106 | await moonbeamClient.dev.setStorage({ 107 | Assets: { 108 | account: [[[moonbeam.custom.ldot, defaultAccounts.alith.address], { balance: 10e12 }]], 109 | }, 110 | }) 111 | 112 | return { 113 | fromChain: moonbeamClient, 114 | fromBalance: query.assets(moonbeam.custom.ldot), 115 | fromAccount: defaultAccounts.alith, 116 | 117 | toChain: acalaClient, 118 | toBalance: query.tokens(acala.custom.ldot), 119 | toAccount: defaultAccounts.bob, 120 | 121 | tx: tx.xcmPallet.transferAssetsV3(moonbeam.custom.xcmLdot, 1e12, tx.xcmPallet.parachainV3(1, acala.paraId!)), 122 | } 123 | }) 124 | }, 125 | { skip: true }, // TODO: until we figured out how to query balances on Moonbeam again 126 | ) 127 | -------------------------------------------------------------------------------- /packages/polkadot/src/acala.polkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { acala, polkadot } from '@e2e-test/networks/chains' 4 | import { setupNetworks } from '@e2e-test/shared' 5 | import { query, tx } from '@e2e-test/shared/api' 6 | import { runXcmPalletDown, runXtokensUp } from '@e2e-test/shared/xcm' 7 | 8 | describe('acala & polkadot', async () => { 9 | const [polkadotClient, acalaClient] = await setupNetworks(polkadot, acala) 10 | 11 | const acalaDOT = acalaClient.config.custom.dot 12 | const polkadotDOT = polkadotClient.config.custom.dot 13 | 14 | runXtokensUp('acala transfer DOT to polkadot', async () => { 15 | return { 16 | fromChain: acalaClient, 17 | toChain: polkadotClient, 18 | balance: query.tokens(acalaDOT), 19 | tx: tx.xtokens.transfer(acalaDOT, 1e12, tx.xtokens.relaychainV3), 20 | } 21 | }) 22 | 23 | runXtokensUp('acala transfer DOT wiht limited weight', async () => { 24 | return { 25 | fromChain: acalaClient, 26 | toChain: polkadotClient, 27 | balance: query.tokens(acalaDOT), 28 | tx: tx.xtokens.transfer(acalaDOT, 1e12, tx.xtokens.relaychainV3, { 29 | Limited: { refTime: 5000000000, proofSize: 10000 }, 30 | }), 31 | } 32 | }) 33 | 34 | runXcmPalletDown('polkadot transfer DOT to acala', async () => { 35 | return { 36 | fromChain: polkadotClient, 37 | toChain: acalaClient, 38 | balance: query.tokens(acalaDOT), 39 | tx: tx.xcmPallet.limitedReserveTransferAssetsV3( 40 | polkadotDOT, 41 | 1e12, 42 | tx.xcmPallet.parachainV3(0, acalaClient.config.paraId!), 43 | ), 44 | } 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /packages/polkadot/src/assetHubPolkadot.bridgeHubPolkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { assetHubPolkadot, bridgeHubPolkadot } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 8 | 9 | describe('assetHubPolkadot & bridgeHubPolkadot', async () => { 10 | const [assetHubPolkadotClient, bridgeHubPolkadotClient] = await setupNetworks(assetHubPolkadot, bridgeHubPolkadot) 11 | 12 | const bridgeHubDOT = bridgeHubPolkadot.custom.dot 13 | const polkadotDOT = assetHubPolkadot.custom.dot 14 | 15 | runXcmPalletDown('assetHubPolkadot transfer DOT to bridgeHubPolkadot', async () => { 16 | return { 17 | fromChain: assetHubPolkadotClient, 18 | toChain: bridgeHubPolkadotClient, 19 | balance: query.balances, 20 | toAccount: defaultAccounts.dave, 21 | tx: tx.xcmPallet.limitedTeleportAssets(polkadotDOT, 1e12, tx.xcmPallet.parachainV3(1, bridgeHubPolkadot.paraId!)), 22 | } 23 | }) 24 | 25 | runXcmPalletUp('bridgeHubPolkadot transfer DOT to assetHubPolkadot', async () => { 26 | return { 27 | fromChain: bridgeHubPolkadotClient, 28 | toChain: assetHubPolkadotClient, 29 | balance: query.balances, 30 | toAccount: defaultAccounts.dave, 31 | tx: tx.xcmPallet.limitedTeleportAssets( 32 | bridgeHubDOT, 33 | 1e12, 34 | tx.xcmPallet.parachainV3(1, assetHubPolkadotClient.config.paraId!), 35 | ), 36 | } 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /packages/polkadot/src/assetHubPolkadot.collectivesPolkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { assetHubPolkadot, collectivesPolkadot } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 8 | 9 | describe('assetHubPolkadot & collectivesPolkadot', async () => { 10 | const [assetHubPolkadotClient, collectivesPolkadotClient] = await setupNetworks(assetHubPolkadot, collectivesPolkadot) 11 | 12 | const collectivesDOT = collectivesPolkadot.custom.dot 13 | const polkadotDOT = assetHubPolkadot.custom.dot 14 | 15 | runXcmPalletDown('assetHubPolkadot transfer DOT to collectivesPolkadot', async () => { 16 | return { 17 | fromChain: assetHubPolkadotClient, 18 | toChain: collectivesPolkadotClient, 19 | balance: query.balances, 20 | toAccount: defaultAccounts.dave, 21 | tx: tx.xcmPallet.limitedTeleportAssets( 22 | polkadotDOT, 23 | 1e12, 24 | tx.xcmPallet.parachainV3(1, collectivesPolkadot.paraId!), 25 | ), 26 | } 27 | }) 28 | 29 | runXcmPalletUp('collectivesPolkadot transfer DOT to assetHubPolkadot', async () => { 30 | return { 31 | fromChain: collectivesPolkadotClient, 32 | toChain: assetHubPolkadotClient, 33 | balance: query.balances, 34 | toAccount: defaultAccounts.dave, 35 | tx: tx.xcmPallet.limitedTeleportAssets( 36 | collectivesDOT, 37 | 1e12, 38 | tx.xcmPallet.parachainV3(1, assetHubPolkadotClient.config.paraId!), 39 | ), 40 | } 41 | }) 42 | }) 43 | -------------------------------------------------------------------------------- /packages/polkadot/src/assetHubPolkadot.coretimePolkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { assetHubPolkadot, coretimePolkadot } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 8 | 9 | describe('assetHubPolkadot & coretimePolkadot', async () => { 10 | const [assetHubPolkadotClient, coretimePolkadotClient] = await setupNetworks(assetHubPolkadot, coretimePolkadot) 11 | 12 | const coretimeDOT = coretimePolkadot.custom.dot 13 | const polkadotDOT = assetHubPolkadot.custom.dot 14 | 15 | runXcmPalletDown('assetHubPolkadot transfer DOT to coretimePolkadot', async () => { 16 | return { 17 | fromChain: assetHubPolkadotClient, 18 | toChain: coretimePolkadotClient, 19 | balance: query.balances, 20 | toAccount: defaultAccounts.dave, 21 | tx: tx.xcmPallet.limitedTeleportAssets(polkadotDOT, 1e12, tx.xcmPallet.parachainV3(1, coretimePolkadot.paraId!)), 22 | } 23 | }) 24 | 25 | runXcmPalletUp('coretimePolkadot transfer DOT to assetHubPolkadot', async () => { 26 | return { 27 | fromChain: coretimePolkadotClient, 28 | toChain: assetHubPolkadotClient, 29 | balance: query.balances, 30 | toAccount: defaultAccounts.dave, 31 | tx: tx.xcmPallet.limitedTeleportAssets( 32 | coretimeDOT, 33 | 1e12, 34 | tx.xcmPallet.parachainV3(1, assetHubPolkadotClient.config.paraId!), 35 | ), 36 | } 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /packages/polkadot/src/assetHubPolkadot.peoplePolkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { assetHubPolkadot, peoplePolkadot } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 8 | 9 | describe('assetHubPolkadot & peoplePolkadot', async () => { 10 | const [assetHubPolkadotClient, peopleClient] = await setupNetworks(assetHubPolkadot, peoplePolkadot) 11 | 12 | const peopleDOT = peoplePolkadot.custom.dot 13 | const polkadotDOT = assetHubPolkadot.custom.dot 14 | 15 | runXcmPalletDown('assetHubPolkadot transfer DOT to peoplePolkadot', async () => { 16 | return { 17 | fromChain: assetHubPolkadotClient, 18 | toChain: peopleClient, 19 | balance: query.balances, 20 | toAccount: defaultAccounts.dave, 21 | tx: tx.xcmPallet.limitedTeleportAssets(polkadotDOT, 1e12, tx.xcmPallet.parachainV3(1, peoplePolkadot.paraId!)), 22 | } 23 | }) 24 | 25 | runXcmPalletUp('peoplePolkadot transfer DOT to assetHubPolkadot', async () => { 26 | return { 27 | fromChain: peopleClient, 28 | toChain: assetHubPolkadotClient, 29 | balance: query.balances, 30 | toAccount: defaultAccounts.dave, 31 | tx: tx.xcmPallet.limitedTeleportAssets( 32 | peopleDOT, 33 | 1e12, 34 | tx.xcmPallet.parachainV3(1, assetHubPolkadotClient.config.paraId!), 35 | ), 36 | } 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /packages/polkadot/src/assetHubPolkadot.polkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { assetHubPolkadot, polkadot } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 8 | 9 | describe('asset hub & polkadot', async () => { 10 | const [polkadotClient, ahClient] = await setupNetworks(polkadot, assetHubPolkadot) 11 | 12 | runXcmPalletUp('Teleport DOT from Asset Hub to Polkadot', async () => { 13 | return { 14 | fromChain: ahClient, 15 | toChain: polkadotClient, 16 | balance: query.balances, 17 | tx: tx.xcmPallet.executeXCM( 18 | { 19 | V4: [ 20 | { 21 | WithdrawAsset: [ 22 | { 23 | id: { 24 | parents: 1, 25 | interior: 'Here', 26 | }, 27 | fun: { Fungible: 7e12 }, 28 | }, 29 | ], 30 | }, 31 | { 32 | SetFeesMode: { 33 | jit_withdraw: true, 34 | }, 35 | }, 36 | { 37 | InitiateTeleport: { 38 | assets: { 39 | wild: 'All', 40 | }, 41 | dest: { 42 | parents: 1, 43 | interior: 'Here', 44 | }, 45 | xcm: [ 46 | { 47 | BuyExecution: { 48 | fees: { 49 | id: { 50 | parents: 0, 51 | interior: 'Here', 52 | }, 53 | fun: { 54 | fungible: 500_000_000_000n, 55 | }, 56 | }, 57 | weight_limit: 'unlimited', 58 | }, 59 | }, 60 | { 61 | DepositAsset: { 62 | assets: { 63 | wild: { 64 | allCounted: 1, 65 | }, 66 | }, 67 | beneficiary: { 68 | parents: 0, 69 | interior: { 70 | x1: [ 71 | { 72 | accountId32: { 73 | id: defaultAccounts.bob.addressRaw, 74 | network: null, 75 | }, 76 | }, 77 | ], 78 | }, 79 | }, 80 | }, 81 | }, 82 | ], 83 | }, 84 | }, 85 | ], 86 | }, 87 | { ref_time: 100_000_000_000n, proof_size: 1_000_000n }, 88 | ), 89 | } 90 | }) 91 | 92 | runXcmPalletDown('Teleport DOT from Polkadot to Asset Hub', async () => { 93 | return { 94 | fromChain: polkadotClient, 95 | toChain: ahClient, 96 | balance: query.balances, 97 | tx: tx.xcmPallet.executeXCM( 98 | { 99 | V4: [ 100 | { 101 | WithdrawAsset: [ 102 | { 103 | id: { 104 | parents: 0, 105 | interior: 'Here', 106 | }, 107 | fun: { Fungible: 7e12 }, 108 | }, 109 | ], 110 | }, 111 | { 112 | SetFeesMode: { 113 | jit_withdraw: true, 114 | }, 115 | }, 116 | { 117 | InitiateTeleport: { 118 | assets: { 119 | wild: 'All', 120 | }, 121 | dest: { 122 | parents: 0, 123 | interior: { 124 | x1: [ 125 | { 126 | Parachain: 1000, 127 | }, 128 | ], 129 | }, 130 | }, 131 | xcm: [ 132 | { 133 | BuyExecution: { 134 | fees: { 135 | id: { 136 | parents: 1, 137 | interior: 'Here', 138 | }, 139 | fun: { 140 | fungible: 500_000_000_000n, 141 | }, 142 | }, 143 | weight_limit: 'unlimited', 144 | }, 145 | }, 146 | { 147 | DepositAsset: { 148 | assets: { 149 | wild: { 150 | allCounted: 1, 151 | }, 152 | }, 153 | beneficiary: { 154 | parents: 0, 155 | interior: { 156 | x1: [ 157 | { 158 | accountId32: { 159 | id: defaultAccounts.bob.addressRaw, 160 | network: null, 161 | }, 162 | }, 163 | ], 164 | }, 165 | }, 166 | }, 167 | }, 168 | ], 169 | }, 170 | }, 171 | ], 172 | }, 173 | { ref_time: 100_000_000_000n, proof_size: 1_000_000n }, 174 | ), 175 | } 176 | }) 177 | }) 178 | -------------------------------------------------------------------------------- /packages/polkadot/src/assetHubPolkadot.proxy.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { assetHubPolkadot } from '@e2e-test/networks/chains' 2 | 3 | import { proxyE2ETests } from '@e2e-test/shared' 4 | import { AssetHubProxyTypes } from '@e2e-test/shared' 5 | 6 | proxyE2ETests(assetHubPolkadot, { testSuiteName: 'Polkadot AssetHub Proxy', addressEncoding: 0 }, AssetHubProxyTypes) 7 | -------------------------------------------------------------------------------- /packages/polkadot/src/assetHubPolkadot.scheduler.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { polkadot } from '@e2e-test/networks/chains' 2 | 3 | import { schedulerE2ETests } from '@e2e-test/shared' 4 | 5 | schedulerE2ETests(polkadot, { testSuiteName: 'Asset Hub Polkadot Scheduler E2E tests', addressEncoding: 0 }) 6 | -------------------------------------------------------------------------------- /packages/polkadot/src/assetHubPolkadot.vesting.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { polkadot } from '@e2e-test/networks/chains' 2 | 3 | import { vestingE2ETests } from '@e2e-test/shared' 4 | 5 | vestingE2ETests(polkadot, { testSuiteName: 'Polkadot Asset Hub Vesting', addressEncoding: 0 }) 6 | -------------------------------------------------------------------------------- /packages/polkadot/src/astar.polkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { astar, polkadot } from '@e2e-test/networks/chains' 4 | import { setupNetworks } from '@e2e-test/shared' 5 | import { query, tx } from '@e2e-test/shared/api' 6 | import { runXcmPalletDown, runXtokensUp } from '@e2e-test/shared/xcm' 7 | 8 | describe('astar & polkadot', async () => { 9 | const [polkadotClient, astarClient] = await setupNetworks(polkadot, astar) 10 | 11 | const astarDOT = astarClient.config.custom!.dot 12 | const polkadotDOT = polkadotClient.config.custom!.dot 13 | 14 | runXcmPalletDown('polkadot transfer DOT to astar', async () => { 15 | return { 16 | fromChain: polkadotClient, 17 | toChain: astarClient, 18 | balance: query.assets(astarDOT), 19 | tx: tx.xcmPallet.limitedReserveTransferAssetsV3( 20 | polkadotDOT, 21 | 1e12, 22 | tx.xcmPallet.parachainV3(0, astarClient.config.paraId!), 23 | ), 24 | } 25 | }) 26 | 27 | runXtokensUp('astar transfer DOT to polkadot', async () => { 28 | return { 29 | fromChain: astarClient, 30 | toChain: polkadotClient, 31 | balance: query.assets(astarDOT), 32 | tx: tx.xtokens.transfer(astarDOT, 1e12, tx.xtokens.relaychainV3), 33 | } 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /packages/polkadot/src/bridgeHubPolkadot.polkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { bridgeHubPolkadot, polkadot } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 8 | 9 | describe('polkadot & bridgeHubPolkadot', async () => { 10 | const [polkadotClient, bridgeHubClient] = await setupNetworks(polkadot, bridgeHubPolkadot) 11 | 12 | const bridgeHubDOT = bridgeHubPolkadot.custom.dot 13 | const polkadotDOT = polkadot.custom.dot 14 | 15 | runXcmPalletDown('polkadot transfer DOT to bridgeHubPolkadot', async () => { 16 | return { 17 | fromChain: polkadotClient, 18 | toChain: bridgeHubClient, 19 | balance: query.balances, 20 | toAccount: defaultAccounts.dave, 21 | tx: tx.xcmPallet.teleportAssetsV3(polkadotDOT, 1e12, tx.xcmPallet.parachainV3(0, bridgeHubPolkadot.paraId!)), 22 | totalIssuanceProvider: () => query.totalIssuance(polkadotClient), 23 | } 24 | }) 25 | 26 | runXcmPalletUp('bridgeHubPolkadot transfer DOT to polkadot', async () => { 27 | return { 28 | fromChain: bridgeHubClient, 29 | toChain: polkadotClient, 30 | balance: query.balances, 31 | toAccount: defaultAccounts.dave, 32 | tx: tx.xcmPallet.teleportAssetsV3(bridgeHubDOT, 1e12, tx.xcmPallet.relaychainV4), 33 | totalIssuanceProvider: () => query.totalIssuance(polkadotClient), 34 | } 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /packages/polkadot/src/collectivesPolkadot.polkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { collectivesPolkadot, polkadot } from '@e2e-test/networks/chains' 2 | 3 | import { collectivesChainE2ETests, setupNetworks } from '@e2e-test/shared' 4 | import { query, tx } from '@e2e-test/shared/api' 5 | import { authorizeUpgradeViaCollectives } from '@e2e-test/shared/upgrade.js' 6 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 7 | import { describe, test } from 'vitest' 8 | 9 | collectivesChainE2ETests(polkadot, collectivesPolkadot, { testSuiteName: 'collectives & polkadot' }) 10 | 11 | describe('collectives & polkadot', async () => { 12 | const [polkadotClient, collectivesClient] = await setupNetworks(polkadot, collectivesPolkadot) 13 | 14 | const collectivesDOT = collectivesPolkadot.custom.dot 15 | const polkadotDOT = polkadot.custom.dot 16 | 17 | runXcmPalletDown('polkadot teleport DOT to collectivesPolkadot', async () => { 18 | return { 19 | fromChain: polkadotClient, 20 | toChain: collectivesClient, 21 | balance: query.balances, 22 | tx: tx.xcmPallet.teleportAssetsV3(polkadotDOT, 1e12, tx.xcmPallet.parachainV3(0, collectivesPolkadot.paraId!)), 23 | totalIssuanceProvider: () => query.totalIssuance(polkadotClient), 24 | } 25 | }) 26 | 27 | runXcmPalletUp('collectivesPolkadot teleport DOT to polkadot', async () => { 28 | return { 29 | fromChain: collectivesClient, 30 | toChain: polkadotClient, 31 | balance: query.balances, 32 | tx: tx.xcmPallet.teleportAssetsV3(collectivesDOT, 1e12, tx.xcmPallet.relaychainV4), 33 | totalIssuanceProvider: () => query.totalIssuance(polkadotClient), 34 | } 35 | }) 36 | 37 | test('Relay authorizes upgrade for itself', async () => { 38 | await authorizeUpgradeViaCollectives(polkadotClient, polkadotClient, collectivesClient) 39 | }) 40 | 41 | test('Relay authorizes Collectives upgrade via Collectives', async () => { 42 | await authorizeUpgradeViaCollectives(polkadotClient, collectivesClient, collectivesClient) 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /packages/polkadot/src/collectivesPolkadot.proxy.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { collectivesPolkadot } from '@e2e-test/networks/chains' 2 | 3 | import { proxyE2ETests } from '@e2e-test/shared' 4 | import { CollectivesProxyTypes } from '@e2e-test/shared' 5 | 6 | proxyE2ETests( 7 | collectivesPolkadot, 8 | { testSuiteName: 'Polkadot Collectives Proxy', addressEncoding: 0 }, 9 | CollectivesProxyTypes, 10 | ) 11 | -------------------------------------------------------------------------------- /packages/polkadot/src/collectivesPolkadot.scheduler.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { collectivesPolkadot } from '@e2e-test/networks/chains' 2 | 3 | import { schedulerE2ETests } from '@e2e-test/shared' 4 | 5 | schedulerE2ETests(collectivesPolkadot, { 6 | testSuiteName: 'Collectives Polkadot Scheduler E2E tests', 7 | addressEncoding: 0, 8 | }) 9 | -------------------------------------------------------------------------------- /packages/polkadot/src/coretimePolkadot.polkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { coretimePolkadot, polkadot } from '@e2e-test/networks/chains' 4 | import { setupNetworks } from '@e2e-test/shared' 5 | import { query, tx } from '@e2e-test/shared/api' 6 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 7 | 8 | describe('polkadot & coretimePolkadot', async () => { 9 | const [polkadotClient, coretimeClient] = await setupNetworks(polkadot, coretimePolkadot) 10 | 11 | const coretimeDOT = coretimePolkadot.custom.dot 12 | const polkadotDOT = polkadot.custom.dot 13 | 14 | runXcmPalletDown('polkadot transfer DOT to coretimePolkadot', async () => { 15 | return { 16 | fromChain: polkadotClient, 17 | toChain: coretimeClient, 18 | balance: query.balances, 19 | tx: tx.xcmPallet.teleportAssetsV3(polkadotDOT, 1e12, tx.xcmPallet.parachainV3(0, coretimePolkadot.paraId!)), 20 | totalIssuanceProvider: () => query.totalIssuance(polkadotClient), 21 | } 22 | }) 23 | 24 | runXcmPalletUp('coretimePolkadot transfer DOT to polkadot', async () => { 25 | return { 26 | fromChain: coretimeClient, 27 | toChain: polkadotClient, 28 | balance: query.balances, 29 | tx: tx.xcmPallet.teleportAssetsV3(coretimeDOT, 1e12, tx.xcmPallet.relaychainV4), 30 | totalIssuanceProvider: () => query.totalIssuance(polkadotClient), 31 | } 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /packages/polkadot/src/coretimePolkadot.proxy.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { coretimePolkadot } from '@e2e-test/networks/chains' 2 | 3 | import { proxyE2ETests } from '@e2e-test/shared' 4 | import { CoretimeProxyTypes } from '@e2e-test/shared' 5 | 6 | proxyE2ETests(coretimePolkadot, { testSuiteName: 'Polkadot Coretime Proxy', addressEncoding: 0 }, CoretimeProxyTypes) 7 | -------------------------------------------------------------------------------- /packages/polkadot/src/hydration.moonbeam.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { hydration, moonbeam, polkadot } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletHorizontal, runXtokenstHorizontal } from '@e2e-test/shared/xcm' 8 | 9 | describe( 10 | 'hydration & moonbeam', 11 | async () => { 12 | const [hydrationClient, moonbeamClient, polkadotClient] = await setupNetworks(hydration, moonbeam, polkadot) 13 | 14 | const hydrationDot = hydration.custom.relayToken 15 | const moonbeamDot = moonbeam.custom.dot 16 | const glmr = hydration.custom.glmr 17 | 18 | runXtokenstHorizontal('hydration transfer DOT to moonbeam', async () => { 19 | return { 20 | fromChain: hydrationClient, 21 | fromBalance: query.tokens(hydrationDot), 22 | fromAccount: defaultAccounts.alice, 23 | 24 | toChain: moonbeamClient, 25 | toBalance: query.assets(moonbeamDot), 26 | toAccount: defaultAccounts.alith, 27 | 28 | routeChain: polkadotClient, 29 | isCheckUmp: true, 30 | 31 | tx: tx.xtokens.transfer(hydrationDot, 2e12, tx.xtokens.parachainAccountId20V3(moonbeam.paraId!)), 32 | } 33 | }) 34 | 35 | runXcmPalletHorizontal('moonbeam transfer DOT to hydration', async () => { 36 | await moonbeamClient.dev.setStorage({ 37 | Assets: { 38 | account: [[[moonbeamDot, defaultAccounts.alith.address], { balance: 10e12 }]], 39 | }, 40 | }) 41 | 42 | return { 43 | fromChain: moonbeamClient, 44 | fromBalance: query.assets(moonbeamDot), 45 | fromAccount: defaultAccounts.alith, 46 | 47 | toChain: hydrationClient, 48 | toBalance: query.tokens(hydrationDot), 49 | toAccount: defaultAccounts.bob, 50 | 51 | routeChain: polkadotClient, 52 | isCheckUmp: true, 53 | 54 | tx: tx.xcmPallet.transferAssetsV3(moonbeam.custom.xcmDot, 2e10, tx.xcmPallet.parachainV3(1, hydration.paraId!)), 55 | } 56 | }) 57 | 58 | runXtokenstHorizontal('hydration transfer GLMR to moonbeam', async () => { 59 | await hydrationClient.dev.setStorage({ 60 | Tokens: { 61 | Accounts: [[[defaultAccounts.alice.address, glmr], { free: '50000000000000000000000' }]], 62 | }, 63 | }) 64 | 65 | return { 66 | fromChain: hydrationClient, 67 | fromBalance: query.tokens(glmr), 68 | fromAccount: defaultAccounts.alice, 69 | routeChain: polkadotClient, 70 | toChain: moonbeamClient, 71 | toBalance: query.balances, 72 | toAccount: defaultAccounts.baltathar, 73 | 74 | tx: tx.xtokens.transfer(glmr, '200000000000000000000', tx.xtokens.parachainAccountId20V3(moonbeam.paraId!)), 75 | } 76 | }) 77 | }, 78 | { skip: true }, // TODO: until we figured out how to query balances on Moonbeam again 79 | ) 80 | -------------------------------------------------------------------------------- /packages/polkadot/src/peoplePolkadot.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { peoplePolkadot, polkadot } from '@e2e-test/networks/chains' 2 | 3 | import { peopleChainE2ETests } from '@e2e-test/shared' 4 | 5 | peopleChainE2ETests(polkadot, peoplePolkadot, { testSuiteName: 'Polkadot People', addressEncoding: 0 }) 6 | -------------------------------------------------------------------------------- /packages/polkadot/src/peoplePolkadot.polkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe } from 'vitest' 2 | 3 | import { defaultAccounts } from '@e2e-test/networks' 4 | import { peoplePolkadot, polkadot } from '@e2e-test/networks/chains' 5 | import { setupNetworks } from '@e2e-test/shared' 6 | import { query, tx } from '@e2e-test/shared/api' 7 | import { runXcmPalletDown, runXcmPalletUp } from '@e2e-test/shared/xcm' 8 | 9 | describe('polkadot & peoplePolkadot', async () => { 10 | const [polkadotClient, peopleClient] = await setupNetworks(polkadot, peoplePolkadot) 11 | 12 | const peopleDOT = peoplePolkadot.custom.dot 13 | const polkadotDOT = polkadot.custom.dot 14 | 15 | runXcmPalletDown('polkadot transfer DOT to peoplePolkadot', async () => { 16 | return { 17 | fromChain: polkadotClient, 18 | toChain: peopleClient, 19 | balance: query.balances, 20 | toAccount: defaultAccounts.dave, 21 | tx: tx.xcmPallet.teleportAssetsV3(polkadotDOT, 1e12, tx.xcmPallet.parachainV3(0, peoplePolkadot.paraId!)), 22 | totalIssuanceProvider: () => query.totalIssuance(polkadotClient), 23 | } 24 | }) 25 | 26 | runXcmPalletUp('peoplePolkadot transfer DOT to polkadot', async () => { 27 | return { 28 | fromChain: peopleClient, 29 | toChain: polkadotClient, 30 | balance: query.balances, 31 | toAccount: defaultAccounts.dave, 32 | tx: tx.xcmPallet.teleportAssetsV3(peopleDOT, 1e12, tx.xcmPallet.relaychainV4), 33 | totalIssuanceProvider: () => query.totalIssuance(polkadotClient), 34 | } 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /packages/polkadot/src/peoplePolkadot.proxy.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { peoplePolkadot } from '@e2e-test/networks/chains' 2 | 3 | import { proxyE2ETests } from '@e2e-test/shared' 4 | import { PeopleProxyTypes } from '@e2e-test/shared' 5 | 6 | proxyE2ETests(peoplePolkadot, { testSuiteName: 'People Polkadot Proxy', addressEncoding: 0 }, PeopleProxyTypes) 7 | -------------------------------------------------------------------------------- /packages/polkadot/src/polkadot.assetHubPolkadot.collectivesPolkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test } from 'vitest' 2 | 3 | import { assetHubPolkadot, collectivesPolkadot, polkadot } from '@e2e-test/networks/chains' 4 | import { setupNetworks } from '@e2e-test/shared' 5 | import { authorizeUpgradeViaCollectives } from '@e2e-test/shared/upgrade.js' 6 | 7 | describe('polkadot & asset hub & collectives', async () => { 8 | const [polkadotClient, ahClient, collectivesClient] = await setupNetworks( 9 | polkadot, 10 | assetHubPolkadot, 11 | collectivesPolkadot, 12 | ) 13 | 14 | test('Relay authorizes AssetHub upgrade via Collectives', async () => { 15 | await authorizeUpgradeViaCollectives(polkadotClient, ahClient, collectivesClient) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /packages/polkadot/src/polkadot.bridgeHubPolkadot.collectivesPolkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test } from 'vitest' 2 | 3 | import { bridgeHubPolkadot, collectivesPolkadot, polkadot } from '@e2e-test/networks/chains' 4 | import { setupNetworks } from '@e2e-test/shared' 5 | import { authorizeUpgradeViaCollectives } from '@e2e-test/shared/upgrade.js' 6 | 7 | describe('polkadot & bridgeHub & collectives', async () => { 8 | const [polkadotClient, bridgeHubClient, collectivesClient] = await setupNetworks( 9 | polkadot, 10 | bridgeHubPolkadot, 11 | collectivesPolkadot, 12 | ) 13 | 14 | test('Relay authorizes Bridge Hub upgrade via Collectives', async () => { 15 | await authorizeUpgradeViaCollectives(polkadotClient, bridgeHubClient, collectivesClient) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /packages/polkadot/src/polkadot.coretimePolkadot.collectivesPolkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test } from 'vitest' 2 | 3 | import { collectivesPolkadot, coretimePolkadot, polkadot } from '@e2e-test/networks/chains' 4 | import { setupNetworks } from '@e2e-test/shared' 5 | import { authorizeUpgradeViaCollectives } from '@e2e-test/shared/upgrade.js' 6 | 7 | describe('polkadot & coretime & collectives', async () => { 8 | const [polkadotClient, coretimeClient, collectivesClient] = await setupNetworks( 9 | polkadot, 10 | coretimePolkadot, 11 | collectivesPolkadot, 12 | ) 13 | 14 | test('Relay authorizes Coretime upgrade via Collectives', async () => { 15 | await authorizeUpgradeViaCollectives(polkadotClient, coretimeClient, collectivesClient) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /packages/polkadot/src/polkadot.governance.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { polkadot } from '@e2e-test/networks/chains' 2 | 3 | import { governanceE2ETests } from '@e2e-test/shared' 4 | 5 | governanceE2ETests(polkadot, { testSuiteName: 'Polkadot Governance', addressEncoding: 0 }) 6 | -------------------------------------------------------------------------------- /packages/polkadot/src/polkadot.nominationPools.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { polkadot } from '@e2e-test/networks/chains' 2 | 3 | import { nominationPoolsE2ETests } from '@e2e-test/shared' 4 | 5 | nominationPoolsE2ETests(polkadot, { testSuiteName: 'Polkadot Nomination Pools', addressEncoding: 0 }) 6 | -------------------------------------------------------------------------------- /packages/polkadot/src/polkadot.peoplePolkadot.collectivesPolkadot.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, test } from 'vitest' 2 | 3 | import { collectivesPolkadot, peoplePolkadot, polkadot } from '@e2e-test/networks/chains' 4 | import { setupNetworks } from '@e2e-test/shared' 5 | import { authorizeUpgradeViaCollectives } from '@e2e-test/shared/upgrade.js' 6 | 7 | describe('polkadot & people & collectives', async () => { 8 | const [polkadotClient, peopleClient, collectivesClient] = await setupNetworks( 9 | polkadot, 10 | peoplePolkadot, 11 | collectivesPolkadot, 12 | ) 13 | 14 | test('Relay authorizes People upgrade via Collectives', async () => { 15 | await authorizeUpgradeViaCollectives(polkadotClient, peopleClient, collectivesClient) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /packages/polkadot/src/polkadot.proxy.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { polkadot } from '@e2e-test/networks/chains' 2 | 3 | import { proxyE2ETests } from '@e2e-test/shared' 4 | import { PolkadotProxyTypes } from '@e2e-test/shared' 5 | 6 | proxyE2ETests(polkadot, { testSuiteName: 'Polkadot Proxy', addressEncoding: 0 }, PolkadotProxyTypes) 7 | -------------------------------------------------------------------------------- /packages/polkadot/src/polkadot.scheduler.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { polkadot } from '@e2e-test/networks/chains' 2 | 3 | import { schedulerE2ETests } from '@e2e-test/shared' 4 | 5 | schedulerE2ETests(polkadot, { testSuiteName: 'Polkadot Scheduler', addressEncoding: 0 }) 6 | -------------------------------------------------------------------------------- /packages/polkadot/src/polkadot.staking.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { polkadot } from '@e2e-test/networks/chains' 2 | 3 | import { stakingE2ETests } from '@e2e-test/shared' 4 | 5 | stakingE2ETests(polkadot, { testSuiteName: 'Polkadot Staking', addressEncoding: 0 }) 6 | -------------------------------------------------------------------------------- /packages/polkadot/src/polkadot.vesting.e2e.test.ts: -------------------------------------------------------------------------------- 1 | import { polkadot } from '@e2e-test/networks/chains' 2 | 3 | import { vestingE2ETests } from '@e2e-test/shared' 4 | 5 | vestingE2ETests(polkadot, { testSuiteName: 'Polkadot Vesting', addressEncoding: 0 }) 6 | -------------------------------------------------------------------------------- /packages/polkadot/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "emitDeclarationOnly": true, 6 | "declarationDir": "dist/esm" 7 | }, 8 | "include": ["src/**/*"], 9 | "references": [{ "path": "../networks/tsconfig.json" }, { "path": "../shared/tsconfig.json" }] 10 | } 11 | -------------------------------------------------------------------------------- /packages/shared/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@e2e-test/shared", 3 | "type": "module", 4 | "dependencies": { 5 | "@acala-network/chopsticks": "^1.0.6", 6 | "@acala-network/chopsticks-testing": "^1.0.6", 7 | "@e2e-test/networks": "workspace:*", 8 | "@polkadot/api": "^16.1.1", 9 | "@polkadot/types": "^16.1.1", 10 | "@polkadot/types-augment": "^16.1.1" 11 | }, 12 | "main": "./dist/cjs/index.js", 13 | "module": "./dist/esm/index.js", 14 | "files": [ 15 | "*", 16 | "!tsconfig.json", 17 | "!**/*.test.ts" 18 | ], 19 | "exports": { 20 | ".": { 21 | "require": "./dist/cjs/index.js", 22 | "import": "./dist/esm/index.js", 23 | "default": "./dist/esm/index.js" 24 | }, 25 | "./api": { 26 | "require": "./dist/cjs/api/index.js", 27 | "import": "./dist/esm/api/index.js", 28 | "default": "./dist/esm/api/index.js" 29 | }, 30 | "./helpers": { 31 | "require": "./dist/cjs/helpers/index.js", 32 | "import": "./dist/esm/helpers/index.js", 33 | "default": "./dist/esm/helpers/index.js" 34 | }, 35 | "./xcm": { 36 | "require": "./dist/cjs/xcm/index.js", 37 | "import": "./dist/esm/xcm/index.js", 38 | "default": "./dist/esm/xcm/index.js" 39 | }, 40 | "./*": { 41 | "require": "./dist/cjs/*.js", 42 | "import": "./dist/esm/*.js", 43 | "default": "./dist/esm/*.js" 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/shared/src/api/index.ts: -------------------------------------------------------------------------------- 1 | import type { ApiPromise } from '@polkadot/api' 2 | 3 | export type TransferType = 'Teleport' | 'LocalReserve' | 'DestinationReserve' | 'RemoteReserve' 4 | 5 | export const xtokens = { 6 | relaychainV3: (acc: any) => ({ 7 | V3: { 8 | parents: 1, 9 | interior: { 10 | X1: { 11 | AccountId32: { 12 | id: acc, 13 | }, 14 | }, 15 | }, 16 | }, 17 | }), 18 | relaychainV4: (acc: any) => ({ 19 | V4: { 20 | parents: 1, 21 | interior: { 22 | X1: { 23 | AccountId32: { 24 | id: acc, 25 | }, 26 | }, 27 | }, 28 | }, 29 | }), 30 | parachainAccountId20V3: (paraId: number) => (acc: any) => ({ 31 | V3: { 32 | parents: 1, 33 | interior: { 34 | X2: [ 35 | { Parachain: paraId }, 36 | { 37 | AccountKey20: { 38 | key: acc, 39 | }, 40 | }, 41 | ], 42 | }, 43 | }, 44 | }), 45 | parachainV3: (paraId: number) => (acc: any) => ({ 46 | V3: { 47 | parents: 1, 48 | interior: { 49 | X2: [ 50 | { Parachain: paraId }, 51 | { 52 | AccountId32: { 53 | id: acc, 54 | }, 55 | }, 56 | ], 57 | }, 58 | }, 59 | }), 60 | parachainV4: (paraId: number) => (acc: any) => ({ 61 | V4: { 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 | relaychainV4: { 95 | V4: { 96 | parents: 1, 97 | interior: 'Here', 98 | }, 99 | }, 100 | parachainV3: (parents: number, paraId: any) => ({ 101 | V3: { 102 | parents, 103 | interior: { 104 | X1: { Parachain: paraId }, 105 | }, 106 | }, 107 | }), 108 | parachainV4: (parents: number, paraId: any) => ({ 109 | V4: { 110 | parents, 111 | interior: { 112 | X1: [{ Parachain: paraId }], 113 | }, 114 | }, 115 | }), 116 | limitedTeleportAssets: 117 | (token: any, amount: any, dest: any) => 118 | ({ api }: { api: ApiPromise }, acc: any) => 119 | (api.tx.xcmPallet || api.tx.polkadotXcm).limitedTeleportAssets( 120 | dest, 121 | { 122 | V3: { 123 | parents: 0, 124 | interior: { 125 | X1: { 126 | AccountId32: { 127 | // network: 'Any', 128 | id: acc, 129 | }, 130 | }, 131 | }, 132 | }, 133 | }, 134 | { 135 | V3: [ 136 | { 137 | id: token, 138 | fun: { Fungible: amount }, 139 | }, 140 | ], 141 | }, 142 | 0, 143 | 'Unlimited', 144 | ), 145 | limitedReserveTransferAssetsV3: 146 | (token: any, amount: any, dest: any) => 147 | ({ api }: { api: ApiPromise }, acc: any) => 148 | (api.tx.xcmPallet || api.tx.polkadotXcm).limitedReserveTransferAssets( 149 | dest, 150 | { 151 | V3: { 152 | parents: 0, 153 | interior: { 154 | X1: { 155 | AccountId32: { 156 | id: acc, 157 | }, 158 | }, 159 | }, 160 | }, 161 | }, 162 | { 163 | V3: [ 164 | { 165 | id: token, 166 | fun: { Fungible: amount }, 167 | }, 168 | ], 169 | }, 170 | 0, 171 | 'Unlimited', 172 | ), 173 | teleportAssetsV3: 174 | (token: any, amount: any, dest: any) => 175 | ({ api }: { api: ApiPromise }, acc: any) => 176 | (api.tx.xcmPallet || api.tx.polkadotXcm).teleportAssets( 177 | dest, 178 | { 179 | V3: { 180 | parents: 0, 181 | interior: { 182 | X1: { 183 | AccountId32: { 184 | id: acc, 185 | }, 186 | }, 187 | }, 188 | }, 189 | }, 190 | { 191 | V3: [ 192 | { 193 | id: token, 194 | fun: { Fungible: amount }, 195 | }, 196 | ], 197 | }, 198 | 0, 199 | ), 200 | executeXCM: 201 | (xcm: any, max_weight: any) => 202 | ({ api }: { api: ApiPromise }) => { 203 | return (api.tx.xcmPallet || api.tx.polkadotXcm).execute(xcm, max_weight) 204 | }, 205 | transferAssetsV3: 206 | (token: any, amount: any, dest: any) => 207 | ({ api }: { api: ApiPromise }, acc: any) => 208 | (api.tx.xcmPallet || api.tx.polkadotXcm).transferAssets( 209 | dest, 210 | { 211 | V3: { 212 | parents: 0, 213 | interior: { 214 | X1: { 215 | AccountId32: { 216 | id: acc, 217 | }, 218 | }, 219 | }, 220 | }, 221 | }, 222 | { 223 | V3: [ 224 | { 225 | id: token, 226 | fun: { Fungible: amount }, 227 | }, 228 | ], 229 | }, 230 | 0, 231 | 'Unlimited', 232 | ), 233 | transferAssetsUsingType: 234 | (dest: any, tokens: any[], assetTransferType: TransferType, remoteFeesId: any, feesTransferType: TransferType) => 235 | ({ api }: { api: ApiPromise }, acc: any) => 236 | (api.tx.xcmPallet || api.tx.polkadotXcm).transferAssetsUsingTypeAndThen( 237 | dest, 238 | { V4: tokens }, 239 | assetTransferType, 240 | { V4: remoteFeesId }, 241 | feesTransferType, 242 | { 243 | V4: [ 244 | { 245 | DepositAsset: { 246 | assets: { 247 | Wild: { 248 | AllCounted: 2, 249 | }, 250 | }, 251 | beneficiary: { 252 | parents: 0, 253 | interior: { X1: [{ AccountId32: { id: acc } }] }, 254 | }, 255 | }, 256 | }, 257 | ], 258 | }, 259 | 'Unlimited', 260 | ), 261 | } 262 | 263 | export const tx = { 264 | xtokens, 265 | xcmPallet, 266 | } 267 | 268 | export const query = { 269 | balances: ({ api }: { api: ApiPromise }, address: string) => api.query.system.account(address), 270 | totalIssuance: ({ api }: { api: ApiPromise }) => api.query.balances.totalIssuance(), 271 | tokens: 272 | (token: any) => 273 | ({ api }: { api: ApiPromise }, address: string) => 274 | api.query.tokens.accounts(address, token), 275 | assets: 276 | (token: number | bigint) => 277 | ({ api }: { api: ApiPromise }, address: string) => 278 | api.query.assets.account(token, address), 279 | foreignAssets: 280 | (token: any) => 281 | ({ api }: { api: ApiPromise }, address: string) => 282 | api.query.foreignAssets.account(token, address), 283 | evm: 284 | (contract: string, slot: string) => 285 | ({ api }: { api: ApiPromise }, _address: string) => 286 | api.query.evm.accountStorages(contract, slot), 287 | } 288 | -------------------------------------------------------------------------------- /packages/shared/src/api/query.ts: -------------------------------------------------------------------------------- 1 | import type { 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 | -------------------------------------------------------------------------------- /packages/shared/src/collectives.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Utilities for collectives chain tests - both Polkadot and Kusama. 3 | * 4 | * Tests are defined here, parametrized over relay/parachain datatypes, and each corresponding 5 | * implementing module can then instantiates tests with the appropriate chains inside a `describe`. 6 | * 7 | * Also contains helpers used in those tests. 8 | * @module 9 | */ 10 | 11 | import { describe, test } from 'vitest' 12 | 13 | import type { Chain, Client } from '@e2e-test/networks' 14 | 15 | import { checkSystemEvents, createXcmTransactSend, scheduleInlineCallWithOrigin } from './helpers/index.js' 16 | import { setupNetworks } from './setup.js' 17 | /** 18 | * Test the process of whitelisting a call 19 | * 20 | * @param destClient The destination chain that is intented to execute whitelist call 21 | * @param collectivesClient Collectives parachain 22 | */ 23 | export async function fellowshipWhitelistCall(destClient: Client, collectivesClient: Client) { 24 | /** 25 | * Example 32 byte call hash; value is not important for the test 26 | */ 27 | const callHashToWhitelist = '0x0101010101010101010101010101010101010101010101010101010101010101' 28 | 29 | await sendWhitelistCallViaXcmTransact(destClient, collectivesClient, callHashToWhitelist, { 30 | proofSize: '10000', 31 | refTime: '1000000000', 32 | }) 33 | 34 | await collectivesClient.dev.newBlock() 35 | await checkSystemEvents(collectivesClient, 'polkadotXcm') 36 | .redact({ hash: false, redactKeys: /messageId/ }) 37 | .toMatchSnapshot('source chain events') 38 | 39 | await destClient.dev.newBlock() 40 | await checkSystemEvents(destClient, 'whitelist', 'messageQueue') 41 | .redact({ hash: false, redactKeys: /id/ }) 42 | .toMatchSnapshot('destination chain events') 43 | } 44 | 45 | /** 46 | * Send an XCM message containing an extrinsic to be executed in the destination chain as 47 | * 48 | * @param destClient Destination chain client form which to execute xcm send 49 | * @param encodedChainCallData Hex-encoded call extrinsic to be executed at the destination 50 | * @param requireWeightAtMost Optional reftime/proof size parameters that the extrinsic may require 51 | */ 52 | export async function sendWhitelistCallViaXcmTransact( 53 | destClient: Client, 54 | collectivesClient: Client, 55 | encodedChainCallData: `0x${string}`, 56 | requireWeightAtMost = { proofSize: '10000', refTime: '100000000' }, 57 | ): Promise { 58 | let dest: { parents: number; interior: any } 59 | 60 | if (destClient.config.isRelayChain) { 61 | dest = { 62 | parents: 1, 63 | interior: 'Here', 64 | } 65 | } else { 66 | dest = { 67 | parents: 1, 68 | interior: { X1: [{ Parachain: destClient.config.paraId }] }, 69 | } 70 | } 71 | 72 | const xcmTx = createXcmTransactSend( 73 | collectivesClient, 74 | dest, 75 | destClient.api.tx.whitelist.whitelistCall(encodedChainCallData).method.toHex(), 76 | 'Xcm', 77 | requireWeightAtMost, 78 | ) 79 | 80 | await scheduleInlineCallWithOrigin(collectivesClient, xcmTx.method.toHex(), { FellowshipOrigins: 'Fellows' }) 81 | } 82 | 83 | /** 84 | * Test runner for collectives chains' E2E tests. 85 | * 86 | * Tests that are meant to be run in a collectives chain *must* be added to as a `vitest.test` to the 87 | * `describe` runner this function creates. 88 | * 89 | * @param topLevelDescription A description of this test runner e.g. "Polkadot Collectives E2E tests" 90 | * @param relayClient The relay chain to be used by these tests 91 | * @param collectivesClient The collectives's chain associated to the previous `relayChain` 92 | */ 93 | export function collectivesChainE2ETests< 94 | TCustom extends Record | undefined, 95 | TInitStoragesRelay extends Record> | undefined, 96 | TInitStoragesPara extends Record> | undefined, 97 | >( 98 | relayChain: Chain, 99 | collectivesChain: Chain, 100 | testConfig: { testSuiteName: string }, 101 | ) { 102 | describe(testConfig.testSuiteName, async () => { 103 | const [relayClient, collectivesClient] = await setupNetworks(relayChain, collectivesChain) 104 | 105 | test('whitelisting a call by fellowship', async () => { 106 | await fellowshipWhitelistCall(relayClient, collectivesClient) 107 | }) 108 | }) 109 | } 110 | -------------------------------------------------------------------------------- /packages/shared/src/helpers/proxyTypes.ts: -------------------------------------------------------------------------------- 1 | /// A map of proxy type names to their corresponding numeric values, for a given network. 2 | export type ProxyTypeMap = Record 3 | 4 | /** 5 | * Proxy types in the Polkadot relay chain. 6 | */ 7 | export const PolkadotProxyTypes: ProxyTypeMap = { 8 | Any: 0, 9 | NonTransfer: 1, 10 | Governance: 2, 11 | Staking: 3, 12 | CancelProxy: 6, 13 | Auction: 7, 14 | NominationPools: 8, 15 | ParaRegistration: 9, 16 | } 17 | 18 | export const KusamaProxyTypes: ProxyTypeMap = { 19 | Any: 0, 20 | NonTransfer: 1, 21 | Governance: 2, 22 | Staking: 3, 23 | CancelProxy: 5, 24 | Auction: 6, 25 | Society: 7, 26 | NominationPools: 8, 27 | Spokesperson: 9, 28 | ParaRegistration: 10, 29 | } 30 | 31 | export const AssetHubProxyTypes: ProxyTypeMap = { 32 | Any: 0, 33 | NonTransfer: 1, 34 | CancelProxy: 2, 35 | Assets: 3, 36 | AssetOwner: 4, 37 | AssetManager: 5, 38 | Collator: 6, 39 | } 40 | 41 | export const CollectivesProxyTypes: ProxyTypeMap = { 42 | Any: 0, 43 | NonTransfer: 1, 44 | CancelProxy: 2, 45 | Collator: 3, 46 | Alliance: 4, 47 | Fellowship: 5, 48 | Ambassador: 6, 49 | } 50 | 51 | export const CoretimeProxyTypes: ProxyTypeMap = { 52 | Any: 0, 53 | NonTransfer: 1, 54 | CancelProxy: 2, 55 | Broker: 3, 56 | CoretimeRenewer: 4, 57 | OnDemandPurchaser: 5, 58 | Collator: 6, 59 | } 60 | 61 | export const PeopleProxyTypes: ProxyTypeMap = { 62 | Any: 0, 63 | NonTransfer: 1, 64 | CancelProxy: 2, 65 | Identity: 3, 66 | IdentityJudgement: 4, 67 | Collator: 5, 68 | } 69 | -------------------------------------------------------------------------------- /packages/shared/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './setup.js' 2 | 3 | export * from './collectives.js' 4 | export * from './governance.js' 5 | export * from './nomination-pools.js' 6 | export * from './people.js' 7 | export * from './proxy.js' 8 | export * from './scheduler.js' 9 | export * from './staking.js' 10 | export * from './vesting.js' 11 | 12 | export * from './types.js' 13 | export * from './helpers/proxyTypes.js' 14 | -------------------------------------------------------------------------------- /packages/shared/src/setup.ts: -------------------------------------------------------------------------------- 1 | import { afterAll, beforeEach } from 'vitest' 2 | 3 | import { type Chain, captureSnapshot, createNetworks } from '@e2e-test/networks' 4 | 5 | /** 6 | * Sets up blockchain networks for testing with automatic snapshot restore and cleanup. 7 | * 8 | * This function creates test networks for the specified chain types and sets up test fixtures 9 | * to automatically restore snapshots between tests and clean up when finished. 10 | * 11 | * @param chains - Array of Chain type parameters defining which networks to create 12 | * @returns Promise resolving to array of created network instances 13 | * 14 | * @example 15 | * const [assetHubPolkadotClient, acalaClient] = await setupNetworks(assetHubPolkadot, acala) 16 | */ 17 | export async function setupNetworks(...chains: T) { 18 | const networks = await createNetworks(...chains) 19 | 20 | const restoreSnapshot = captureSnapshot(...networks) 21 | 22 | beforeEach(async () => { 23 | await restoreSnapshot() 24 | await Promise.all( 25 | networks.map(async (network) => { 26 | const blockNumber = (await network.api.rpc.chain.getHeader()).number.toNumber() 27 | 28 | network.dev.setHead(blockNumber) 29 | }), 30 | ) 31 | }) 32 | 33 | afterAll(async () => { 34 | await Promise.all(networks.map((network) => network.teardown())) 35 | }) 36 | 37 | return networks 38 | } 39 | -------------------------------------------------------------------------------- /packages/shared/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { Blockchain, StorageValues } from '@acala-network/chopsticks' 2 | import type { Chain } from '@e2e-test/networks' 3 | import type { ApiPromise, WsProvider } from '@polkadot/api' 4 | 5 | export type Prettify = { 6 | [K in keyof T]: T[K] 7 | } & {} 8 | 9 | /** 10 | * Type of client object produced by `setupNetworks` in E2E test suites. 11 | */ 12 | export type Client< 13 | TCustom extends Record | undefined, 14 | TInitStorages extends Record> | undefined, 15 | > = { 16 | config: Chain 17 | url: string 18 | chain: Blockchain 19 | ws: WsProvider 20 | api: ApiPromise 21 | dev: { 22 | newBlock: (param?: Partial) => Promise 23 | setStorage: (values: StorageValues, blockHash?: string) => Promise 24 | timeTravel: (date: string | number) => Promise 25 | setHead: (hashOrNumber: string | number) => Promise 26 | } 27 | teardown(): Promise 28 | pause(): Promise 29 | } 30 | -------------------------------------------------------------------------------- /packages/shared/src/upgrade.ts: -------------------------------------------------------------------------------- 1 | import { assert } from 'vitest' 2 | 3 | import { sendTransaction } from '@acala-network/chopsticks-testing' 4 | import { type Chain, type Client, defaultAccounts } from '@e2e-test/networks' 5 | import { sendWhitelistCallViaXcmTransact } from '@e2e-test/shared' 6 | import type { HexString } from '@polkadot/util/types' 7 | import { checkEvents, checkSystemEvents, createXcmTransactSend, scheduleInlineCallWithOrigin } from './helpers/index.js' 8 | 9 | /** 10 | * Computes the XCM `MultiLocation` route from a source chain to a destination chain. 11 | * 12 | * @param from - The source chain (the chain initiating the XCM message). 13 | * @param to - The destination chain (the chain intended to receive and execute the XCM message). 14 | */ 15 | function getXcmRoute(from: Chain, to: Chain) { 16 | let parents: number 17 | let interior: any 18 | 19 | if (from.isRelayChain) { 20 | parents = 0 21 | } else { 22 | parents = 1 23 | } 24 | 25 | if (to.isRelayChain) { 26 | interior = 'Here' 27 | } else { 28 | interior = { X1: [{ Parachain: to.paraId }] } 29 | } 30 | 31 | return { parents, interior } 32 | } 33 | 34 | /** 35 | * Constructs an XCM forceBatch transaction that authorizes a runtime upgrade on a destination chain. 36 | * 37 | * 38 | * @param codeHash - The code hash of the new runtime to be authorized. 39 | * @param sourceClient - The client instance representing the source chain (where the XCM is sent from). 40 | * @param destClient - The client instance representing the destination chain (where the upgrade is authorized). 41 | */ 42 | export function createXcmAuthorizeUpgradeBatch(codeHash: HexString, sourceClient: Client, destClient: Client) { 43 | const authorizeUpgradeCall = destClient.api.tx.system.authorizeUpgrade(codeHash) 44 | const dest = getXcmRoute(sourceClient.config, destClient.config) 45 | 46 | const xcmTx = createXcmTransactSend(sourceClient, dest, authorizeUpgradeCall.method.toHex(), 'Superuser', { 47 | refTime: '5000000000', 48 | proofSize: '500000', 49 | }) 50 | 51 | return sourceClient.api.tx.utility.forceBatch([xcmTx]) 52 | } 53 | 54 | /** 55 | * Simulates and executes the full governance workflow to authorize a runtime upgrade 56 | * on a target chain, optionally across chains using collectives and XCM. 57 | * 58 | * - Considering any existing authorized upgrade 59 | * - Submitting the upgrade call preimage 60 | * - Attempt to dispatch when call is not yet whitelisted 61 | * - Whitelisting the call via a Collectives chain 62 | * - Attempting to dispatch with both valid and invalid origins. 63 | * - Validating that the upgrade was correctly authorized on the target chain. 64 | * 65 | * @param governingChain - The chain where the governance is running, allowed to execute as superuser on other chains 66 | * @param chainToUpgrade - The chain whose runtime is being upgraded. 67 | * @param collectivesChain - The chain that hosts the collective body which will whitelist the upgrade call. 68 | */ 69 | export async function authorizeUpgradeViaCollectives( 70 | governingChain: Client, 71 | chainToUpgrade: Client, 72 | collectivesChain: Client, 73 | ) { 74 | // NOTE: Since the test is run against some live chain data, it may happen that at some moment some upgrade 75 | // is already authorized - expected result is that the authorized hash will be overriden by this test 76 | // 77 | // specific value of codeHash is not important for the test 78 | const codeHash = '0x0101010101010101010101010101010101010101010101010101010101010101' 79 | const assertAuthorizedUpgradeUnchanged = async () => { 80 | const currentAuthorizedUpgrade = await chainToUpgrade.api.query.system.authorizedUpgrade() 81 | assert(currentAuthorizedUpgrade.isNone || currentAuthorizedUpgrade.value.codeHash.toHex() !== codeHash) 82 | } 83 | await assertAuthorizedUpgradeUnchanged() 84 | 85 | const authorizeUpgradeCall = 86 | governingChain.url === chainToUpgrade.url 87 | ? chainToUpgrade.api.tx.system.authorizeUpgrade(codeHash) 88 | : createXcmAuthorizeUpgradeBatch(codeHash, governingChain, chainToUpgrade) 89 | 90 | const whiteListCall = governingChain.api.tx.whitelist.dispatchWhitelistedCallWithPreimage( 91 | authorizeUpgradeCall.method.toHex(), 92 | ) 93 | 94 | const notePreimageTx = governingChain.api.tx.preimage.notePreimage(authorizeUpgradeCall.method.toHex()) 95 | 96 | const okOrigin = { Origins: 'WhitelistedCaller' } 97 | // some existing but not allowed to dispatch whitelisted call origin 98 | const badOrigin = { Origins: 'StakingAdmin' } 99 | 100 | // it does not matter who is the origin which notes the preimage 101 | const noteEvents = await sendTransaction(notePreimageTx.signAsync(defaultAccounts.alice)) 102 | await governingChain.dev.newBlock() 103 | await checkEvents(noteEvents, 'preimage').toMatchSnapshot('events after notePreimge') 104 | 105 | // try to dispatch a call that has not yet been whitelisted - should result in dispatching error 106 | await scheduleInlineCallWithOrigin(governingChain, whiteListCall.method.toHex(), okOrigin) 107 | await governingChain.dev.newBlock() 108 | await checkSystemEvents(governingChain, 'scheduler') 109 | .redact({ hash: false, redactKeys: /task/ }) 110 | .toMatchSnapshot('events when dispatching non-whitelisted call') 111 | await assertAuthorizedUpgradeUnchanged() 112 | 113 | // collectives whitelisting a call 114 | await sendWhitelistCallViaXcmTransact(governingChain, collectivesChain, authorizeUpgradeCall.method.hash.toHex(), { 115 | proofSize: '10000', 116 | refTime: '500000000', 117 | }) 118 | await collectivesChain.dev.newBlock() 119 | await checkSystemEvents(collectivesChain, 'polkadotXcm') 120 | .redact({ hash: false, redactKeys: /messageId/ }) 121 | .toMatchSnapshot('collectives events emitted when sending xcm') 122 | await governingChain.dev.newBlock() 123 | await checkSystemEvents(governingChain, 'whitelist', 'messageQueue') 124 | .redact({ hash: false, redactKeys: /id/ }) 125 | .toMatchSnapshot('governing chain events emitted on receiving xcm from collectives') 126 | 127 | // trying to dispatch whitelisted call using bad origin - should result in error 128 | await scheduleInlineCallWithOrigin(governingChain, whiteListCall.method.toHex(), badOrigin) 129 | await governingChain.dev.newBlock() 130 | await checkSystemEvents(governingChain, 'scheduler') 131 | .redact({ hash: false, redactKeys: /task/ }) 132 | .toMatchSnapshot('events when dispatching whitelisted call with bad origin') 133 | await assertAuthorizedUpgradeUnchanged() 134 | 135 | // call is whitelisted, origin is ok - success expected 136 | await scheduleInlineCallWithOrigin(governingChain, whiteListCall.method.toHex(), okOrigin) 137 | await governingChain.dev.newBlock() 138 | await checkSystemEvents(governingChain, 'whitelist') 139 | .redact({ hash: false }) 140 | .toMatchSnapshot('governing chain events about dispatching whitelisted call') 141 | 142 | if (governingChain.url === chainToUpgrade.url) { 143 | await checkSystemEvents(chainToUpgrade, { section: 'system', method: 'UpgradeAuthorized' }) 144 | .redact({ hash: false }) 145 | .toMatchSnapshot('to-be-upgraded chain events to confirm authorized upgrade') 146 | } else { 147 | await chainToUpgrade.dev.newBlock() 148 | await checkSystemEvents(chainToUpgrade, 'messageQueue', { section: 'system', method: 'UpgradeAuthorized' }) 149 | .redact({ hash: false, redactKeys: /id/ }) 150 | .toMatchSnapshot('to-be-upgraded chain events to confirm authorized upgrade') 151 | } 152 | 153 | assert.equal((await chainToUpgrade.api.query.system.authorizedUpgrade()).value.codeHash.toHex(), codeHash) 154 | } 155 | -------------------------------------------------------------------------------- /packages/shared/src/xcm/index.ts: -------------------------------------------------------------------------------- 1 | export * from './runXcmPalletDown.js' 2 | export * from './runXcmPalletHorizontal.js' 3 | export * from './runXcmPalletUp.js' 4 | export * from './runXtokenstHorizontal.js' 5 | export * from './runXtokensUp.js' 6 | -------------------------------------------------------------------------------- /packages/shared/src/xcm/runXcmPalletDown.ts: -------------------------------------------------------------------------------- 1 | import { sendTransaction } from '@acala-network/chopsticks-testing' 2 | import type { KeyringPair } from '@polkadot/keyring/types' 3 | import { assert, it } from 'vitest' 4 | 5 | import { type Client, defaultAccounts } from '@e2e-test/networks' 6 | import { check, checkEvents, checkSystemEvents } from '../helpers/index.js' 7 | import type { GetBalance, GetTotalIssuance, Tx } from './types.js' 8 | 9 | export const runXcmPalletDown = ( 10 | name: string, 11 | setup: () => Promise<{ 12 | fromChain: Client 13 | toChain: Client 14 | tx: Tx 15 | balance: GetBalance 16 | 17 | fromAccount?: KeyringPair 18 | toAccount?: KeyringPair 19 | precision?: number 20 | totalIssuanceProvider?: GetTotalIssuance 21 | }>, 22 | options: { only?: boolean } = {}, 23 | ) => { 24 | const itfn = options.only ? it.only : it 25 | itfn( 26 | name, 27 | async () => { 28 | const { 29 | fromChain, 30 | toChain, 31 | tx, 32 | balance, 33 | fromAccount = defaultAccounts.alice, 34 | toAccount = defaultAccounts.bob, 35 | precision = 3, 36 | totalIssuanceProvider = undefined, 37 | } = await setup() 38 | 39 | const totalIssuanceBefore = await totalIssuanceProvider?.() 40 | 41 | const tx0 = await sendTransaction(tx(fromChain, toAccount.addressRaw).signAsync(fromAccount)) 42 | 43 | await fromChain.chain.newBlock() 44 | 45 | await check(fromChain.api.query.system.account(fromAccount.address)) 46 | .redact({ number: precision }) 47 | .toMatchSnapshot('balance on from chain') 48 | await checkEvents(tx0, 'polkadotXcm', 'xcmPallet').redact({ number: precision }).toMatchSnapshot('tx events') 49 | 50 | await toChain.chain.newBlock() 51 | 52 | await check(balance(toChain, toAccount.address)) 53 | .redact({ number: precision }) 54 | .toMatchSnapshot('balance on to chain') 55 | await checkSystemEvents(toChain, 'parachainSystem', 'dmpQueue', 'messageQueue').toMatchSnapshot( 56 | 'to chain dmp events', 57 | ) 58 | 59 | const totalIssuanceAfter = await totalIssuanceProvider?.() 60 | 61 | assert( 62 | !totalIssuanceProvider || totalIssuanceBefore.eq(totalIssuanceAfter), 63 | 'Expecting total issuance to stay the same despite transfers', 64 | ) 65 | }, 66 | 240000, 67 | ) 68 | } 69 | -------------------------------------------------------------------------------- /packages/shared/src/xcm/runXcmPalletHorizontal.ts: -------------------------------------------------------------------------------- 1 | import { sendTransaction } from '@acala-network/chopsticks-testing' 2 | import type { KeyringPair } from '@polkadot/keyring/types' 3 | import { assert, it } from 'vitest' 4 | 5 | import { type Client, defaultAccounts } from '@e2e-test/networks' 6 | import { check, checkEvents, checkHrmp, checkSystemEvents, checkUmp } from '../helpers/index.js' 7 | import type { GetBalance, GetTotalIssuance, Tx } from './types.js' 8 | 9 | export const runXcmPalletHorizontal = ( 10 | name: string, 11 | setup: () => Promise<{ 12 | fromChain: Client 13 | toChain: Client 14 | tx: Tx 15 | fromBalance: GetBalance 16 | toBalance: GetBalance 17 | 18 | routeChain?: Client 19 | fromAccount?: KeyringPair 20 | toAccount?: KeyringPair 21 | isCheckUmp?: boolean 22 | precision?: number 23 | totalIssuanceProvider?: GetTotalIssuance 24 | }>, 25 | options: { only?: boolean } = {}, 26 | ) => { 27 | const itfn = options.only ? it.only : it 28 | itfn( 29 | name, 30 | async () => { 31 | const { 32 | fromChain, 33 | toChain, 34 | tx, 35 | fromBalance, 36 | toBalance, 37 | routeChain, 38 | fromAccount = defaultAccounts.alice, 39 | toAccount = defaultAccounts.bob, 40 | isCheckUmp = false, 41 | precision = 3, 42 | totalIssuanceProvider = undefined, 43 | } = await setup() 44 | 45 | const totalIssuanceBefore = await totalIssuanceProvider?.() 46 | 47 | const txx = tx(fromChain, toAccount.addressRaw) 48 | const tx0 = await sendTransaction(txx.signAsync(fromAccount)) 49 | 50 | await fromChain.chain.newBlock() 51 | 52 | await check(fromBalance(fromChain, fromAccount.address)) 53 | .redact({ number: precision }) 54 | .toMatchSnapshot('balance on from chain') 55 | await checkEvents(tx0, 'polkadotXcm', 'xcmPallet').toMatchSnapshot('tx events') 56 | 57 | if (isCheckUmp) { 58 | await checkUmp(fromChain) 59 | .redact({ redactKeys: /setTopic/ }) 60 | .toMatchSnapshot('from chain ump messages') 61 | } else { 62 | await checkHrmp(fromChain) 63 | .redact({ redactKeys: /setTopic/ }) 64 | .toMatchSnapshot('from chain hrmp messages') 65 | } 66 | 67 | if (routeChain) { 68 | await routeChain.chain.newBlock() 69 | await checkSystemEvents(routeChain, 'messageQueue').toMatchSnapshot('route chain xcm events') 70 | } 71 | 72 | await toChain.chain.newBlock() 73 | 74 | await check(toBalance(toChain, toAccount.address)) 75 | .redact({ number: precision }) 76 | .toMatchSnapshot('balance on to chain') 77 | await checkSystemEvents(toChain, 'xcmpQueue', 'dmpQueue', 'messageQueue').toMatchSnapshot('to chain xcm events') 78 | 79 | const totalIssuanceAfter = await totalIssuanceProvider?.() 80 | 81 | assert( 82 | !totalIssuanceProvider || totalIssuanceBefore.eq(totalIssuanceAfter), 83 | 'Expecting total issuance to stay the same despite transfers', 84 | ) 85 | }, 86 | 240000, 87 | ) 88 | } 89 | -------------------------------------------------------------------------------- /packages/shared/src/xcm/runXcmPalletUp.ts: -------------------------------------------------------------------------------- 1 | import { sendTransaction } from '@acala-network/chopsticks-testing' 2 | import type { KeyringPair } from '@polkadot/keyring/types' 3 | import { assert, it } from 'vitest' 4 | 5 | import { type Client, defaultAccounts } from '@e2e-test/networks' 6 | import { check, checkEvents, checkSystemEvents, checkUmp } from '../helpers/index.js' 7 | import type { GetBalance, GetTotalIssuance, Tx } from './types.js' 8 | 9 | export const runXcmPalletUp = ( 10 | name: string, 11 | setup: () => Promise<{ 12 | fromChain: Client 13 | toChain: Client 14 | tx: Tx 15 | balance: GetBalance 16 | 17 | fromAccount?: KeyringPair 18 | toAccount?: KeyringPair 19 | precision?: number 20 | totalIssuanceProvider?: GetTotalIssuance 21 | }>, 22 | options: { only?: boolean } = {}, 23 | ) => { 24 | const itfn = options.only ? it.only : it 25 | itfn( 26 | name, 27 | async () => { 28 | const { 29 | fromChain, 30 | toChain, 31 | tx, 32 | balance, 33 | fromAccount = defaultAccounts.alice, 34 | toAccount = defaultAccounts.bob, 35 | precision = 3, 36 | totalIssuanceProvider = undefined, 37 | } = await setup() 38 | 39 | const totalIssuanceBefore = await totalIssuanceProvider?.() 40 | 41 | const tx0 = await sendTransaction(tx(fromChain, toAccount.addressRaw).signAsync(fromAccount)) 42 | 43 | await fromChain.chain.newBlock() 44 | 45 | await check(balance(fromChain, fromAccount.address)) 46 | .redact({ number: precision }) 47 | .toMatchSnapshot('balance on from chain') 48 | await checkEvents(tx0, 'polkadotXcm', 'xcmPallet').redact({ number: precision }).toMatchSnapshot('tx events') 49 | await checkUmp(fromChain) 50 | .redact({ redactKeys: /setTopic/ }) 51 | .toMatchSnapshot('from chain ump messages') 52 | 53 | await toChain.chain.newBlock() 54 | 55 | await check(toChain.api.query.system.account(toAccount.address)) 56 | .redact({ number: precision }) 57 | .toMatchSnapshot('balance on to chain') 58 | await checkSystemEvents(toChain, 'ump', 'messageQueue').toMatchSnapshot('to chain ump events') 59 | 60 | const totalIssuanceAfter = await totalIssuanceProvider?.() 61 | 62 | assert( 63 | !totalIssuanceProvider || totalIssuanceBefore.eq(totalIssuanceAfter), 64 | 'Expecting total issuance to stay the same despite transfers', 65 | ) 66 | }, 67 | 240000, 68 | ) 69 | } 70 | -------------------------------------------------------------------------------- /packages/shared/src/xcm/runXtokensUp.ts: -------------------------------------------------------------------------------- 1 | import { sendTransaction } from '@acala-network/chopsticks-testing' 2 | import type { KeyringPair } from '@polkadot/keyring/types' 3 | import { it } from 'vitest' 4 | 5 | import { type Client, defaultAccounts } from '@e2e-test/networks' 6 | import { check, checkEvents, checkSystemEvents, checkUmp } from '../helpers/index.js' 7 | import type { GetBalance, Tx } from './types.js' 8 | 9 | export const runXtokensUp = ( 10 | name: string, 11 | setup: () => Promise<{ 12 | fromChain: Client 13 | toChain: Client 14 | tx: Tx 15 | balance: GetBalance 16 | 17 | fromAccount?: KeyringPair 18 | toAccount?: KeyringPair 19 | precision?: number 20 | }>, 21 | options: { only?: boolean } = {}, 22 | ) => { 23 | const itfn = options.only ? it.only : it 24 | itfn( 25 | name, 26 | async () => { 27 | const { 28 | fromChain, 29 | toChain, 30 | tx, 31 | balance, 32 | fromAccount = defaultAccounts.alice, 33 | toAccount = defaultAccounts.bob, 34 | precision = 3, 35 | } = await setup() 36 | const tx0 = await sendTransaction(tx(fromChain, toAccount.addressRaw).signAsync(fromAccount)) 37 | 38 | await fromChain.chain.newBlock() 39 | 40 | await check(balance(fromChain, fromAccount.address)) 41 | .redact({ number: precision }) 42 | .toMatchSnapshot('balance on from chain') 43 | await checkEvents(tx0, 'xTokens').redact({ number: precision }).toMatchSnapshot('tx events') 44 | await checkUmp(fromChain).toMatchSnapshot('from chain ump messages') 45 | 46 | await toChain.chain.newBlock() 47 | 48 | await check(toChain.api.query.system.account(toAccount.address)) 49 | .redact({ number: precision }) 50 | .toMatchSnapshot('balance on to chain') 51 | await checkSystemEvents(toChain, 'ump', 'messageQueue').toMatchSnapshot('to chain ump events') 52 | }, 53 | 240000, 54 | ) 55 | } 56 | -------------------------------------------------------------------------------- /packages/shared/src/xcm/runXtokenstHorizontal.ts: -------------------------------------------------------------------------------- 1 | import { sendTransaction } from '@acala-network/chopsticks-testing' 2 | import type { KeyringPair } from '@polkadot/keyring/types' 3 | import { it } from 'vitest' 4 | 5 | import { type Client, defaultAccounts } from '@e2e-test/networks' 6 | import { check, checkEvents, checkHrmp, checkSystemEvents, checkUmp } from '../helpers/index.js' 7 | import type { GetBalance, Tx } from './types.js' 8 | 9 | export const runXtokenstHorizontal = ( 10 | name: string, 11 | setup: () => Promise<{ 12 | fromChain: Client 13 | toChain: Client 14 | tx: Tx 15 | fromBalance: GetBalance 16 | toBalance: GetBalance 17 | 18 | routeChain?: Client 19 | fromAccount?: KeyringPair 20 | toAccount?: KeyringPair 21 | isCheckUmp?: boolean 22 | precision?: number 23 | }>, 24 | options: { only?: boolean; skip?: boolean } = {}, 25 | ) => { 26 | const itfn = options.only ? it.only : options.skip ? it.skip : it 27 | itfn( 28 | name, 29 | async () => { 30 | const { 31 | fromChain, 32 | toChain, 33 | tx, 34 | fromBalance, 35 | toBalance, 36 | routeChain, 37 | fromAccount = defaultAccounts.alice, 38 | toAccount = defaultAccounts.bob, 39 | isCheckUmp = false, 40 | precision = 3, 41 | } = await setup() 42 | 43 | const txx = tx(fromChain, toAccount.addressRaw) 44 | const tx0 = await sendTransaction(txx.signAsync(fromAccount)) 45 | 46 | await fromChain.chain.newBlock() 47 | 48 | await check(fromBalance(fromChain, fromAccount.address)) 49 | .redact({ number: precision }) 50 | .toMatchSnapshot('balance on from chain') 51 | await checkEvents(tx0, 'xTokens').toMatchSnapshot('tx events') 52 | 53 | if (isCheckUmp) { 54 | await checkUmp(fromChain) 55 | .redact({ redactKeys: /setTopic/ }) 56 | .toMatchSnapshot('from chain ump messages') 57 | } else { 58 | await checkHrmp(fromChain) 59 | .redact({ redactKeys: /setTopic/ }) 60 | .toMatchSnapshot('from chain hrmp messages') 61 | } 62 | 63 | if (routeChain) { 64 | await routeChain.chain.newBlock() 65 | await checkSystemEvents(routeChain, 'messageQueue').toMatchSnapshot('route chain xcm events') 66 | } 67 | await toChain.chain.newBlock() 68 | 69 | await check(toBalance(toChain, toAccount.address)) 70 | .redact({ number: precision }) 71 | .toMatchSnapshot('balance on to chain') 72 | await checkSystemEvents(toChain, 'xcmpQueue', 'dmpQueue', 'messageQueue').toMatchSnapshot('to chain xcm events') 73 | }, 74 | 240000, 75 | ) 76 | } 77 | -------------------------------------------------------------------------------- /packages/shared/src/xcm/types.ts: -------------------------------------------------------------------------------- 1 | import type { ApiPromise } from '@polkadot/api' 2 | import type { SubmittableExtrinsic } from '@polkadot/api/types' 3 | 4 | export type Tx = ({ api }: { api: ApiPromise }, acc: any) => SubmittableExtrinsic<'promise'> 5 | export type GetBalance = ({ api }: { api: ApiPromise }, address: string) => Promise 6 | export type GetTotalIssuance = () => Promise 7 | -------------------------------------------------------------------------------- /packages/shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "emitDeclarationOnly": true, 6 | "declarationDir": "dist/esm" 7 | }, 8 | "include": ["src/**/*"], 9 | "references": [{ "path": "../networks/tsconfig.json" }] 10 | } 11 | -------------------------------------------------------------------------------- /scripts/update-env.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs' 2 | import path, { dirname } from 'node:path' 3 | import { fileURLToPath } from 'node:url' 4 | 5 | const __filename = fileURLToPath(import.meta.url) 6 | import * as chains from '@e2e-test/networks/chains' 7 | import { ApiPromise, HttpProvider, WsProvider } from '@polkadot/api' 8 | 9 | const isUpdateKnownGood = process.argv.includes('--update-known-good') 10 | const envFile = isUpdateKnownGood ? 'KNOWN_GOOD_BLOCK_NUMBERS.env' : '.env' 11 | const envPath = path.resolve(dirname(__filename), '../', envFile) 12 | 13 | const readEnvFile = () => { 14 | try { 15 | return fs.readFileSync(envPath, 'utf8').toString() 16 | } catch (_err) { 17 | return '' 18 | } 19 | } 20 | 21 | const main = async () => { 22 | let envFile = readEnvFile() 23 | 24 | // comment out current ones 25 | envFile = envFile.replaceAll(/(^[A-Z0-9]+_BLOCK_NUMBER=\d+)/gm, '# $1') 26 | 27 | // prepend new ones 28 | const blockNumbers: Promise[] = [] 29 | for (const [name, chain] of Object.entries(chains)) { 30 | const fn = async () => { 31 | const api = await ApiPromise.create({ 32 | provider: 33 | Array.isArray(chain.endpoint) || chain.endpoint.startsWith('ws') 34 | ? new WsProvider(chain.endpoint) 35 | : new HttpProvider(chain.endpoint), 36 | noInitWarn: true, 37 | }) 38 | const header = await api.rpc.chain.getHeader() 39 | const blockNumber = header.number.toNumber() 40 | return `${name.toUpperCase()}_BLOCK_NUMBER=${blockNumber}` 41 | } 42 | blockNumbers.push(fn()) 43 | } 44 | 45 | const blockNumbersStr = (await Promise.all(blockNumbers)).join('\n') 46 | 47 | if (isUpdateKnownGood) { 48 | envFile = `${blockNumbersStr}\n` 49 | } else { 50 | envFile = `${blockNumbersStr}\n\n${envFile}` 51 | } 52 | 53 | console.log(blockNumbersStr) 54 | fs.writeFileSync(envPath, envFile) 55 | } 56 | 57 | main() 58 | .catch(console.error) 59 | .finally(() => process.exit(0)) 60 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "esModuleInterop": true, 5 | "lib": ["esnext", "dom", "dom.iterable"], 6 | "isolatedModules": true, 7 | "module": "nodenext", 8 | "moduleResolution": "nodenext", 9 | "noUnusedLocals": true, 10 | "noUnusedParameters": true, 11 | "noImplicitAny": false, 12 | "target": "esnext", 13 | "skipLibCheck": true, 14 | "strict": true, 15 | "declaration": true, 16 | "resolveJsonModule": true, 17 | "forceConsistentCasingInFileNames": true, 18 | "baseUrl": ".", 19 | "composite": true, 20 | "paths": { 21 | "@e2e-test/networks": ["packages/networks/src/index.ts"], 22 | "@e2e-test/networks/chains": ["packages/networks/src/chains/index.ts"], 23 | "@e2e-test/networks/*": ["packages/networks/src/*"], 24 | "@e2e-test/shared": ["packages/shared/src/index.ts"], 25 | "@e2e-test/shared/api": ["packages/shared/src/api/index.ts"], 26 | "@e2e-test/shared/xcm": ["packages/shared/src/xcm/index.ts"], 27 | "@e2e-test/shared/*": ["packages/shared/src/*"] 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "exclude": ["**/node_modules", "**/lib"], 4 | "include": ["./packages/**/*", "./scripts/**/*"] 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.lint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /vitest.config.mts: -------------------------------------------------------------------------------- 1 | import swc from 'unplugin-swc' 2 | import { defineConfig } from 'vitest/config' 3 | 4 | import { resolve } from 'node:path' 5 | import dotenv from 'dotenv' 6 | import tsconfigPaths from 'vite-tsconfig-paths' 7 | 8 | dotenv.config() 9 | dotenv.config({ path: resolve(__dirname, 'KNOWN_GOOD_BLOCK_NUMBERS.env') }) 10 | if (process.env.LOG_LEVEL === undefined) { 11 | process.env.LOG_LEVEL = 'error' 12 | } 13 | 14 | export default defineConfig({ 15 | test: { 16 | hookTimeout: 240_000, 17 | testTimeout: 240_000, 18 | pool: 'forks', 19 | passWithNoTests: true, 20 | retry: 1, 21 | reporters: process.env.GITHUB_ACTIONS ? ['verbose', 'github-actions'] : ['default'], 22 | }, 23 | build: { 24 | outDir: '../../dist', 25 | }, 26 | plugins: [tsconfigPaths(), swc.vite()], 27 | }) 28 | --------------------------------------------------------------------------------