├── .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 |
--------------------------------------------------------------------------------