git.delta.rocks / unique-network / refs/commits / 6ddeec3ac378

difftreelog

Merge branch 'feature/multi-assets-redone' of https://github.com/UniqueNetwork/unique-chain into feature/multi-assets-redone

Dev2022-09-06parents: #28d7737 #042e4c6.patch.diff
in: master

28 files changed

added.docker/xcm-config/launch-config-xcm-unique-rococo.jsondiffbeforeafterboth

no changes

modified.docker/xcm-config/launch-config-xcm-unique.jsondiffbeforeafterboth
101 "id": "2000",101 "id": "2000",
102 "chain": "acala-dev",102 "chain": "acala-dev",
103 "balance": "1000000000000000000000",103 "balance": "1000000000000000000000",
104 "chainInitializer": [
105 "chainql",
106 "-e",
107 "(import '${spec}') {id+: '-local'}"
108 ],
104 "nodes": [109 "nodes": [
105 {110 {
106 "wsPort": 9946,111 "wsPort": 9946,
modified.envdiffbeforeafterboth
1515
16POLKADOT_LAUNCH_BRANCH=feature/rewrite-chain-id-in-spec16POLKADOT_LAUNCH_BRANCH=feature/rewrite-chain-id-in-spec
1717
18KARURA_BUILD_BRANCH=2.9.1
18ACALA_BUILD_BRANCH=2.9.019ACALA_BUILD_BRANCH=2.9.2
20
21MOONRIVER_BUILD_BRANCH=runtime-1701
19MOONBEAM_BUILD_BRANCH=v0.25.022MOONBEAM_BUILD_BRANCH=runtime-1701
23
20CUMULUS_BUILD_BRANCH=release-v0.9.23024STATEMINE_BUILD_BRANCH=parachains-v9270
25STATEMINT_BUILD_BRANCH=release-parachains-v9230
26WESTMINT_BUILD_BRANCH=parachains-v9270
2127
28
modified.github/workflows/ci-develop.ymldiffbeforeafterboth
12jobs:12jobs:
1313
14 yarn-test-dev:14 yarn-test-dev:
15 if: ${{ github.event.pull_request.draft == 'false' }}
16 uses: ./.github/workflows/dev-build-tests_v2.yml15 uses: ./.github/workflows/dev-build-tests_v2.yml
1716
18 unit-test:17 unit-test:
19 if: ${{ github.event.pull_request.draft == 'false' }}
20 uses: ./.github/workflows/unit-test_v2.yml18 uses: ./.github/workflows/unit-test_v2.yml
21
22 forkless:
23 if: ${{ contains( github.event.pull_request.labels.*.name, 'forkless') }}
24 uses: ./.github/workflows/forkless.yml
2519
26 canary:20 canary:
27 if: ${{ contains( github.event.pull_request.labels.*.name, 'canary') }}21 if: ${{ contains( github.event.pull_request.labels.*.name, 'canary') }}
37 codestyle:30 codestyle:
38 uses: ./.github/workflows/codestyle_v2.yml31 uses: ./.github/workflows/codestyle_v2.yml
32
33 yarn_eslint:
34 uses: ./.github/workflows/test_codestyle_v2.yml
35
modified.github/workflows/ci-master.ymldiffbeforeafterboth
12jobs:12jobs:
1313
14 unit-test:14 unit-test:
15 if: ${{ github.event.pull_request.draft != 'true' }}
16 uses: ./.github/workflows/unit-test_v2.yml15 uses: ./.github/workflows/unit-test_v2.yml
1716
18 node-only-update:17 node-only-update:
19 if: ${{ github.event.pull_request.draft == 'false' }}
20 uses: ./.github/workflows/node-only-update_v2.yml18 uses: ./.github/workflows/node-only-update_v2.yml
2119
22 forkless:20 forkless:
34 secrets: inherit # pass all secrets32 secrets: inherit # pass all secrets
3533
36 codestyle:34 codestyle:
37 if: ${{ github.event.pull_request.draft == 'false' }}
38 uses: ./.github/workflows/codestyle_v2.yml35 uses: ./.github/workflows/codestyle_v2.yml
modified.github/workflows/dev-build-tests_v2.ymldiffbeforeafterboth
37 features: "unique-runtime"37 features: "unique-runtime"
3838
39 steps:39 steps:
40 - name: Skip if pull request is in Draft
41 # `if: github.event.pull_request.draft == true` should be kept here, at
42 # the step level, rather than at the job level. The latter is not
43 # recommended because when the PR is moved from "Draft" to "Ready to
44 # review" the workflow will immediately be passing (since it was skipped),
45 # even though it hasn't actually ran, since it takes a few seconds for
46 # the workflow to start. This is also disclosed in:
47 # https://github.community/t/dont-run-actions-on-draft-pull-requests/16817/17
48 # That scenario would open an opportunity for the check to be bypassed:
49 # 1. Get your PR approved
50 # 2. Move it to Draft
51 # 3. Push whatever commits you want
52 # 4. Move it to "Ready for review"; now the workflow is passing (it was
53 # skipped) and "Check reviews" is also passing (it won't be updated
54 # until the workflow is finished)
55 if: github.event.pull_request.draft == true
56 run: exit 1
5740
58 - name: Clean Workspace41 - name: Clean Workspace
59 uses: AutoModality/action-clean@v1.1.042 uses: AutoModality/action-clean@v1.1.0
87 node-version: 1670 node-version: 16
8871
89 - name: Run tests72 - name: Run tests
90 run: |73 run: |
91 cd tests74 cd tests
92 yarn install75 yarn install
93 yarn add mochawesome76 yarn add mochawesome
94 echo "Ready to start tests"77 echo "Ready to start tests"
95 node scripts/readyness.js78 NOW=$(date +%s) && yarn test --reporter mochawesome --reporter-options reportFilename=test-${NOW}
96 NOW=$(date +%s) && yarn test --reporter mochawesome --reporter-options reportFilename=test-${NOW}
97 env:79 env:
98 RPC_URL: http://127.0.0.1:9933/80 RPC_URL: http://127.0.0.1:9933/
9981
modified.github/workflows/test_codestyle_v2.ymldiffbeforeafterboth
55
6jobs:6jobs:
7 code_style:7 code_style:
8 runs-on: self-hosted-ci8 runs-on: [ self-hosted-ci ]
99
10 steps:10 steps:
11 - uses: actions/checkout@v311 - uses: actions/checkout@v3
modified.github/workflows/xcm-testnet-build.ymldiffbeforeafterboth
1818
19 name: Prepare execution matrix19 name: Prepare execution matrix
2020
21 runs-on: XL21 runs-on: [XL]
22 outputs:22 outputs:
23 matrix: ${{ steps.create_matrix.outputs.matrix }}23 matrix: ${{ steps.create_matrix.outputs.matrix }}
2424
39 uses: fabiocaccamo/create-matrix-action@v239 uses: fabiocaccamo/create-matrix-action@v2
40 id: create_matrix40 id: create_matrix
41 with:41 with:
42 matrix: |42 matrix: |
43 network {opal}, runtime {opal}, features {opal-runtime}43 network {opal}, runtime {opal}, features {opal-runtime}, acala_version {${{ env.ACALA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONBEAM_BUILD_BRANCH }}}, cumulus_version {${{ env.WESTMINT_BUILD_BRANCH }}}
44 network {quartz}, runtime {quartz}, features {quartz-runtime}44 network {quartz}, runtime {quartz}, features {quartz-runtime}, acala_version {${{ env.KARURA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONRIVER_BUILD_BRANCH }}}, cumulus_version {${{ env.STATEMINE_BUILD_BRANCH }}}
45 network {unique}, runtime {unique}, features {unique-runtime}45 network {unique}, runtime {unique}, features {unique-runtime}, acala_version {${{ env.ACALA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONBEAM_BUILD_BRANCH }}}, cumulus_version {${{ env.STATEMINT_BUILD_BRANCH }}}
4646
47 xcm-build:47 xcm-build:
48 48
81 with:81 with:
82 template: .docker/Dockerfile-xcm.j282 template: .docker/Dockerfile-xcm.j2
83 output_file: .docker/Dockerfile-xcm.${{ matrix.network }}.yml83 output_file: .docker/Dockerfile-xcm.${{ matrix.network }}.yml
84 variables: |84 variables: |
85 RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}85 RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}
86 NETWORK=${{ matrix.network }}86 NETWORK=${{ matrix.network }}
87 POLKADOT_BUILD_BRANCH=${{ env.POLKADOT_BUILD_BRANCH }}87 POLKADOT_BUILD_BRANCH=${{ env.POLKADOT_BUILD_BRANCH }}
88 POLKADOT_LAUNCH_BRANCH=${{ env.POLKADOT_LAUNCH_BRANCH }}88 POLKADOT_LAUNCH_BRANCH=${{ env.POLKADOT_LAUNCH_BRANCH }}
89 FEATURE=${{ matrix.features }}89 FEATURE=${{ matrix.features }}
90 RUNTIME=${{ matrix.runtime }}90 RUNTIME=${{ matrix.runtime }}
91 BRANCH=${{ github.head_ref }}91 BRANCH=${{ github.head_ref }}
92 ACALA_BUILD_BRANCH=${{ env.ACALA_BUILD_BRANCH }}92 ACALA_BUILD_BRANCH=${{ matrix.acala_version }}
93 MOONBEAM_BUILD_BRANCH=${{ env.MOONBEAM_BUILD_BRANCH }}93 MOONBEAM_BUILD_BRANCH=${{ matrix.moonbeam_version }}
94 CUMULUS_BUILD_BRANCH=${{ env.CUMULUS_BUILD_BRANCH }}94 CUMULUS_BUILD_BRANCH=${{ matrix.cumulus_version }}
9595
96 - name: Show build Dockerfile96 - name: Show build Dockerfile
97 run: cat .docker/Dockerfile-xcm.${{ matrix.network }}.yml97 run: cat .docker/Dockerfile-xcm.${{ matrix.network }}.yml
114 password: ${{ secrets.CORE_DOCKERHUB_TOKEN }}114 password: ${{ secrets.CORE_DOCKERHUB_TOKEN }}
115115
116 - name: Pull acala docker image116 - name: Pull acala docker image
117 run: docker pull uniquenetwork/builder-acala:${{ env.ACALA_BUILD_BRANCH }}117 run: docker pull uniquenetwork/builder-acala:${{ matrix.acala_version }}
118118
119 - name: Pull moonbeam docker image119 - name: Pull moonbeam docker image
120 run: docker pull uniquenetwork/builder-moonbeam:${{ env.MOONBEAM_BUILD_BRANCH }}120 run: docker pull uniquenetwork/builder-moonbeam:${{ matrix.moonbeam_version }}
121121
122 - name: Pull cumulus docker image122 - name: Pull cumulus docker image
123 run: docker pull uniquenetwork/builder-cumulus:${{ env.CUMULUS_BUILD_BRANCH }}123 run: docker pull uniquenetwork/builder-cumulus:${{ matrix.cumulus_version }}
124124
125 - name: Pull polkadot docker image125 - name: Pull polkadot docker image
126 run: docker pull uniquenetwork/builder-polkadot:${{ env.POLKADOT_BUILD_BRANCH }}126 run: docker pull uniquenetwork/builder-polkadot:${{ env.POLKADOT_BUILD_BRANCH }}
modified.github/workflows/xcm-tests_v2.ymldiffbeforeafterboth
143143
144 - name: Run XCM tests 144 - name: Run XCM tests
145 working-directory: tests145 working-directory: tests
146 run: |146 run: |
147 yarn install147 yarn install
148 yarn add mochawesome148 yarn add mochawesome
149 echo "Ready to start tests"149 node scripts/readyness.js
150 echo "Ready to start tests"
150 NOW=$(date +%s) && yarn ${{ matrix.runtest }} --reporter mochawesome --reporter-options reportFilename=test-${NOW}151 NOW=$(date +%s) && yarn ${{ matrix.runtest }} --reporter mochawesome --reporter-options reportFilename=test-${NOW}
151152
152 - name: XCM Test Report153 - name: XCM Test Report
153 uses: phoenix-actions/test-reporting@v8154 uses: phoenix-actions/test-reporting@v8
modifiednode/cli/Cargo.tomldiffbeforeafterboth
302302
303[dependencies]303[dependencies]
304futures = '0.3.17'304futures = '0.3.17'
305log = '0.4.14'305log = '0.4.16'
306flexi_logger = "0.22.5"306flexi_logger = "0.22.5"
307parking_lot = '0.12.1'307parking_lot = '0.12.1'
308clap = "3.1.2"308clap = "3.1.2"
modifiedpallets/evm-contract-helpers/Cargo.tomldiffbeforeafterboth
8scale-info = { version = "2.0.1", default-features = false, features = [8scale-info = { version = "2.0.1", default-features = false, features = [
9 "derive",9 "derive",
10] }10] }
11log = { default-features = false, version = "0.4.14" }11log = { default-features = false, version = "0.4.16" }
1212
13# Substrate13# Substrate
14frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }14frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
modifiedpallets/foreing-assets/Cargo.tomldiffbeforeafterboth
5edition = "2021"5edition = "2021"
66
7[dependencies]7[dependencies]
8log = { version = "0.4.14", default-features = false }8log = { version = "0.4.16", default-features = false }
9serde = { version = "1.0.136", optional = true }9serde = { version = "1.0.136", optional = true }
10scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }10scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
11codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }11codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
modifiedpallets/scheduler/Cargo.tomldiffbeforeafterboth
25frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }25frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
2626
27up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.27" }27up-sponsorship = { version = "0.1.0", default-features = false, git = "https://github.com/uniquenetwork/pallet-sponsoring", branch = "polkadot-v0.9.27" }
28log = { version = "0.4.14", default-features = false }28log = { version = "0.4.16", default-features = false }
2929
30[dev-dependencies]30[dev-dependencies]
31sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }31sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.27" }
modifiedruntime/common/construct_runtime/mod.rsdiffbeforeafterboth
42 Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 34,42 Treasury: pallet_treasury::{Pallet, Call, Storage, Config, Event<T>} = 34,
43 Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>} = 35,43 Sudo: pallet_sudo::{Pallet, Call, Storage, Config<T>, Event<T>} = 35,
44 Vesting: orml_vesting::{Pallet, Storage, Call, Event<T>, Config<T>} = 37,44 Vesting: orml_vesting::{Pallet, Storage, Call, Event<T>, Config<T>} = 37,
45 #[runtimes(opal)]45
46 XTokens: orml_xtokens = 38,46 XTokens: orml_xtokens = 38,
47 Tokens: orml_tokens = 39,47 Tokens: orml_tokens = 39,
48 // Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,48 // Vesting: pallet_vesting::{Pallet, Call, Config<T>, Storage, Event<T>} = 37,
modifiedruntime/opal/src/xcm_config.rsdiffbeforeafterboth
498impl orml_xtokens::Config for Runtime {498impl orml_xtokens::Config for Runtime {
499 type Event = Event;499 type Event = Event;
500 type Balance = Balance;500 type Balance = Balance;
501 type CurrencyId = AssetIds;501 type CurrencyId = CurrencyId;
502 type CurrencyIdConvert = CurrencyIdConvert;502 type CurrencyIdConvert = CurrencyIdConvert;
503 type AccountIdToMultiLocation = AccountIdToMultiLocation;503 type AccountIdToMultiLocation = AccountIdToMultiLocation;
504 type SelfLocation = SelfLocation;504 type SelfLocation = SelfLocation;
modifiedruntime/quartz/src/xcm_config.rsdiffbeforeafterboth
180 type OnKilledTokenAccount = ();180 type OnKilledTokenAccount = ();
181}181}
182182
183/*183impl orml_xtokens::Config for Runtime {
184impl orml_xtokens::Config for Runtime {184 type Event = Event;
185 type Event = Event;185 type Balance = Balance;
186 type Balance = Balance;186 type CurrencyId = CurrencyId;
187 type CurrencyId = AssetIds;187 type CurrencyIdConvert = CurrencyIdConvert;
188 type CurrencyIdConvert = CurrencyIdConvert;188 type AccountIdToMultiLocation = AccountIdToMultiLocation;
189 type AccountIdToMultiLocation = AccountIdToMultiLocation;189 type SelfLocation = SelfLocation;
190 type SelfLocation = SelfLocation;190 type XcmExecutor = XcmExecutor<XcmConfig<Self>>;
191 type XcmExecutor = XcmExecutor<XcmConfig<Self>>;191 type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
192 type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;192 type BaseXcmWeight = BaseXcmWeight;
193 type BaseXcmWeight = BaseXcmWeight;193 type LocationInverter = LocationInverter<Ancestry>;
194 type LocationInverter = LocationInverter<Ancestry>;194 type MaxAssetsForTransfer = MaxAssetsForTransfer;
195 type MaxAssetsForTransfer = MaxAssetsForTransfer;195 type MinXcmFee = ParachainMinFee;
196 type MinXcmFee = ParachainMinFee;196 type MultiLocationsFilter = Everything;
197 type MultiLocationsFilter = Everything;197 type ReserveProvider = AbsoluteReserveProvider;
198 type ReserveProvider = AbsoluteReserveProvider;198}
199}199
200 */
201200
202parameter_type_with_key! {201parameter_type_with_key! {
203 pub ExistentialDeposits: |currency_id: CurrencyId| -> Balance {202 pub ExistentialDeposits: |currency_id: CurrencyId| -> Balance {
219}218}
220219
220
221pub struct CurrencyIdConvert;
222impl Convert<AssetIds, Option<MultiLocation>> for CurrencyIdConvert {
223 fn convert(id: AssetIds) -> Option<MultiLocation> {
224 match id {
225 AssetIds::NativeAssetId(NativeCurrency::Here) => Some(MultiLocation::new(
226 1,
227 X1(Parachain(ParachainInfo::get().into())),
228 )),
229 AssetIds::NativeAssetId(NativeCurrency::Parent) => Some(MultiLocation::parent()),
230 AssetIds::ForeignAssetId(_) => None,
231 }
232 }
233}
221/*234/*
222pub struct CurrencyIdConvert;
223impl Convert<AssetIds, Option<MultiLocation>> for CurrencyIdConvert {
224 fn convert(id: AssetIds) -> Option<MultiLocation> {
225 match id {
226 AssetIds::NativeAssetId(NativeCurrency::Here) => Some(MultiLocation::new(
227 1,
228 X1(Parachain(ParachainInfo::get().into())),
229 )),
230 AssetIds::NativeAssetId(NativeCurrency::Parent) => Some(MultiLocation::parent()),
231 AssetIds::ForeignAssetId(foreign_asset_id) => {
232 XcmForeignAssetIdMapping::<Runtime>::get_multi_location(foreign_asset_id)
233 }
234 }
235 }
236}
237impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {235impl Convert<MultiLocation, Option<CurrencyId>> for CurrencyIdConvert {
238 fn convert(location: MultiLocation) -> Option<CurrencyId> {236 fn convert(location: MultiLocation) -> Option<CurrencyId> {
239 if location == MultiLocation::here()237 if location == MultiLocation::here()
240 || location == MultiLocation::new(1, X1(Parachain(ParachainInfo::get().into())))238 || location == MultiLocation::new(1, X1(Parachain(ParachainInfo::get().into())))
241 {239 {
242 return Some(AssetIds::NativeAssetId(NativeCurrency::Here));240 return Some(AssetIds::NativeAssetId(NativeCurrency::Here));
243 }241 }
244242
245 if location == MultiLocation::parent() {243 if location == MultiLocation::parent() {
246 return Some(AssetIds::NativeAssetId(NativeCurrency::Parent));244 return Some(AssetIds::NativeAssetId(NativeCurrency::Parent));
247 }245 }
248246
249 if let Some(currency_id) =247 if let Some(currency_id) =
250 XcmForeignAssetIdMapping::<Runtime>::get_currency_id(location.clone())248 XcmForeignAssetIdMapping::<Runtime>::get_currency_id(location.clone())
251 {249 {
252 return Some(currency_id);250 return Some(currency_id);
253 }251 }
254252
255 None253 None
256 }254 }
257}255}
258256
259 */257 */
260258
261259
262parameter_types! {260parameter_types! {
modifiedruntime/unique/src/xcm_config.rsdiffbeforeafterboth
88 MultiLocation { parents: 1, interior: Here },88 MultiLocation { parents: 1, interior: Here },
89 // Karura/Acala location89 // Karura/Acala location
90 MultiLocation { parents: 1, interior: X1(Parachain(2000)) },90 MultiLocation { parents: 1, interior: X1(Parachain(2000)) },
91 // Moonbeam location
92 MultiLocation { parents: 1, interior: X1(Parachain(2004)) },
91 // Self parachain address93 // Self parachain address
92 MultiLocation { parents: 1, interior: X1(Parachain(ParachainInfo::get().into())) },94 MultiLocation { parents: 1, interior: X1(Parachain(ParachainInfo::get().into())) },
93 ]95 ]
201 type OnKilledTokenAccount = ();203 type OnKilledTokenAccount = ();
202}204}
203205
206impl orml_xtokens::Config for Runtime {
207 type Event = Event;
208 type Balance = Balance;
209 type CurrencyId = CurrencyId;
210 type CurrencyIdConvert = CurrencyIdConvert;
211 type AccountIdToMultiLocation = AccountIdToMultiLocation;
212 type SelfLocation = SelfLocation;
213 type XcmExecutor = XcmExecutor<XcmConfig<Self>>;
214 type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
215 type BaseXcmWeight = BaseXcmWeight;
216 type LocationInverter = LocationInverter<Ancestry>;
217 type MaxAssetsForTransfer = MaxAssetsForTransfer;
218 type MinXcmFee = ParachainMinFee;
219 type MultiLocationsFilter = Everything;
220 type ReserveProvider = AbsoluteReserveProvider;
221}
222
223pub struct CurrencyIdConvert;
224impl Convert<AssetIds, Option<MultiLocation>> for CurrencyIdConvert {
225 fn convert(id: AssetIds) -> Option<MultiLocation> {
226 match id {
227 AssetIds::NativeAssetId(NativeCurrency::Here) => Some(MultiLocation::new(
228 1,
229 X1(Parachain(ParachainInfo::get().into())),
230 )),
231 _ => None,
232 }
233 }
234}
204235
205parameter_types! {236parameter_types! {
206 pub const BaseXcmWeight: Weight = 100_000_000; // TODO: recheck this237 pub const BaseXcmWeight: Weight = 100_000_000; // TODO: recheck this
207 pub const MaxAssetsForTransfer: usize = 2;238 pub const MaxAssetsForTransfer: usize = 2;
239
240 pub Ancestry: MultiLocation = Parachain(ParachainInfo::parachain_id().into()).into();
241 pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::get().into())));
208}242}
209243
210parameter_type_with_key! {244parameter_type_with_key! {
modifiedtests/package.jsondiffbeforeafterboth
74 "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",74 "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts",
75 "testScheduler": "mocha --timeout 9999999 -r ts-node/register ./**/scheduler.test.ts",75 "testScheduler": "mocha --timeout 9999999 -r ts-node/register ./**/scheduler.test.ts",
76 "testSchedulingEVM": "mocha --timeout 9999999 -r ts-node/register ./**/eth/scheduling.test.ts",76 "testSchedulingEVM": "mocha --timeout 9999999 -r ts-node/register ./**/eth/scheduling.test.ts",
77 "testXcmUnique": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmUnique.test.ts",77 "testXcmUnique": "RUN_XCM_TESTS=1 mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmUnique.test.ts",
78 "testXcmQuartz": "RUN_XCM_TESTS=1 mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmQuartz.test.ts",
78 "testXcmOpal": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmOpal.test.ts",79 "testXcmOpal": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmOpal.test.ts",
79 "testXcmTransferAcala": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferAcala.test.ts acalaId=2000 uniqueId=5000",80 "testXcmTransferAcala": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferAcala.test.ts acalaId=2000 uniqueId=5000",
80 "testXcmTransferStatemine": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferStatemine.test.ts statemineId=1000 uniqueId=5000",81 "testXcmTransferStatemine": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferStatemine.test.ts statemineId=1000 uniqueId=5000",
81 "testXcmTransferMoonbeam": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferMoonbeam.test.ts moonbeamId=2000 uniqueId=5000",82 "testXcmTransferMoonbeam": "mocha --timeout 9999999 -r ts-node/register ./**/xcm/xcmTransferMoonbeam.test.ts",
82 "testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",83 "testPalletPresence": "mocha --timeout 9999999 -r ts-node/register ./**/pallet-presence.test.ts",
83 "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",84 "testBlockProduction": "mocha --timeout 9999999 -r ts-node/register ./**/block-production.test.ts",
84 "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",85 "testEnableDisableTransfers": "mocha --timeout 9999999 -r ts-node/register ./**/enableDisableTransfer.test.ts",
modifiedtests/scripts/readyness.jsdiffbeforeafterboth
6 await api.isReadyOrError;6 await api.isReadyOrError;
77
8 const head = (await api.rpc.chain.getHeader()).number.toNumber();8 const head = (await api.rpc.chain.getHeader()).number.toNumber();
9 await api.disconnect();
9 if(head < 1) throw Error('No block #1');10 if(head < 1) throw Error('No block #1');
1011
11 await api.disconnect();
12}12}
1313
14const sleep = time => {14const sleep = time => {
modifiedtests/src/substrate/substrate-api.tsdiffbeforeafterboth
85 for (const arg of args) {85 for (const arg of args) {
86 if (typeof arg !== 'string')86 if (typeof arg !== 'string')
87 continue;87 continue;
88 if (arg.includes('1000:: Normal connection closure' || arg === 'Normal connection closure'))88 if (arg.includes('1000:: Normal connection closure') || arg.includes('Not decorating unknown runtime apis:') || arg.includes('RPC methods not decorated:') || arg === 'Normal connection closure')
89 return;89 return;
90 }90 }
91 printer(...args);91 printer(...args);
169 /* eslint no-async-promise-executor: "off" */169 /* eslint no-async-promise-executor: "off" */
170 return new Promise(async (resolve, reject) => {170 return new Promise(async (resolve, reject) => {
171 try {171 try {
172 await transaction.signAndSend(sender, ({events = [], status}) => {172 await transaction.signAndSend(sender, ({events = [], status, dispatchError}) => {
173 const transactionStatus = getTransactionStatus(events, status);173 const transactionStatus = getTransactionStatus(events, status);
174174
175 if (transactionStatus === TransactionStatus.Success) {175 if (transactionStatus === TransactionStatus.Success) {
176 resolve(events);176 resolve(events);
177 } else if (transactionStatus === TransactionStatus.Fail) {177 } else if (transactionStatus === TransactionStatus.Fail) {
178 let moduleError = null;
179
180 if (dispatchError) {
181 if (dispatchError.isModule) {
182 const modErr = dispatchError.asModule;
183 const errorMeta = dispatchError.registry.findMetaError(modErr);
184
185 moduleError = JSON.stringify(errorMeta, null, 4);
186 }
187 }
188
178 console.log(`Something went wrong with transaction. Status: ${status}`);189 console.log(`Something went wrong with transaction. Status: ${status}\nModule error: ${moduleError}`);
179 reject(events);190 reject(events);
180 }191 }
181 });192 });
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
1746 return (await api.rpc.unique.collectionById(collectionId)).unwrap();1746 return (await api.rpc.unique.collectionById(collectionId)).unwrap();
1747}1747}
1748
1749export const describe_xcm = (
1750 process.env.RUN_XCM_TESTS
1751 ? describe
1752 : describe.skip
1753);
17481754
1749export async function waitNewBlocks(blocksCount = 1): Promise<void> {1755export async function waitNewBlocks(blocksCount = 1): Promise<void> {
1750 await usingApi(async (api) => {1756 await usingApi(async (api) => {
1762 });1768 });
1763}1769}
1770
1771export async function waitEvent(
1772 api: ApiPromise,
1773 maxBlocksToWait: number,
1774 eventSection: string,
1775 eventMethod: string,
1776): Promise<EventRecord | null> {
1777
1778 const promise = new Promise<EventRecord | null>(async (resolve) => {
1779 const unsubscribe = await api.query.system.events(eventRecords => {
1780 const neededEvent = eventRecords.find(r => {
1781 return r.event.section == eventSection && r.event.method == eventMethod;
1782 });
1783
1784 if (neededEvent) {
1785 unsubscribe();
1786 resolve(neededEvent);
1787 }
1788
1789 if (maxBlocksToWait > 0) {
1790 maxBlocksToWait--;
1791 } else {
1792 unsubscribe();
1793 resolve(null);
1794 }
1795 });
1796 });
1797 return promise;
1798}
17641799
1765export async function repartitionRFT(1800export async function repartitionRFT(
1766 api: ApiPromise,1801 api: ApiPromise,
modifiedtests/src/util/playgrounds/index.tsdiffbeforeafterboth
26 for (const arg of args) {26 for (const arg of args) {
27 if (typeof arg !== 'string')27 if (typeof arg !== 'string')
28 continue;28 continue;
29 if (arg.includes('1000:: Normal connection closure' || arg === 'Normal connection closure'))29 if (arg.includes('1000:: Normal connection closure') || arg.includes('Not decorating unknown runtime apis:') || arg.includes('RPC methods not decorated:') || arg === 'Normal connection closure')
30 return;30 return;
31 }31 }
32 printer(...args);32 printer(...args);
modifiedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth
103 let accountsCreated = false;103 let accountsCreated = false;
104 // checkBalances retry up to 5 blocks104 // checkBalances retry up to 5 blocks
105 for (let index = 0; index < 5; index++) {105 for (let index = 0; index < 5; index++) {
106 console.log(await this.helper.chain.getLatestBlockNumber());
107 accountsCreated = await checkBalances();106 accountsCreated = await checkBalances();
108 if(accountsCreated) break;107 if(accountsCreated) break;
109 await this.waitNewBlocks(1);108 await this.waitNewBlocks(1);
modifiedtests/src/xcm/xcmOpal.test.tsdiffbeforeafterboth
3535
36const RELAY_PORT = '9844';36const RELAY_PORT = '9844';
37const UNIQUE_PORT = '9944';37const UNIQUE_PORT = '9944';
38const STATEMINE_PORT = '9946';38const STATEMINE_PORT = '9948';
39const STATEMINE_PALLET_INSTANCE = 50;39const STATEMINE_PALLET_INSTANCE = 50;
40const ASSET_ID = 100;40const ASSET_ID = 100;
41const ASSET_METADATA_DECIMALS = 18;41const ASSET_METADATA_DECIMALS = 18;
addedtests/src/xcm/xcmQuartz.test.tsdiffbeforeafterboth

no changes

modifiedtests/src/xcm/xcmTransferMoonbeam.test.tsdiffbeforeafterboth
50});50});
5151
52const UNIQUE_PORT = '9944';52const UNIQUE_PORT = '9944';
53const MOONBEAM_PORT = '9946';53const MOONBEAM_PORT = '9947';
54const TRANSFER_AMOUNT = 2000000000000000000000000n;54const TRANSFER_AMOUNT = 2000000000000000000000000n;
5555
56describe('Integration test: Exchanging UNQ with Moonbeam', () => {56describe('Integration test: Exchanging UNQ with Moonbeam', () => {
modifiedtests/src/xcm/xcmTransferStatemine.test.tsdiffbeforeafterboth
5353
54const RELAY_PORT = '9844';54const RELAY_PORT = '9844';
55const UNIQUE_PORT = '9944';55const UNIQUE_PORT = '9944';
56const STATEMINE_PORT = '9946';56const STATEMINE_PORT = '9948';
57const STATEMINE_PALLET_INSTANCE = 50;57const STATEMINE_PALLET_INSTANCE = 50;
58const ASSET_ID = 100;58const ASSET_ID = 100;
59const ASSET_METADATA_DECIMALS = 18;59const ASSET_METADATA_DECIMALS = 18;
modifiedtests/src/xcm/xcmUnique.test.tsdiffbeforeafterboth
17import chai from 'chai';17import chai from 'chai';
18import chaiAsPromised from 'chai-as-promised';18import chaiAsPromised from 'chai-as-promised';
1919
20import {WsProvider} from '@polkadot/api';20import {WsProvider, Keyring} from '@polkadot/api';
21import {ApiOptions} from '@polkadot/api/types';21import {ApiOptions} from '@polkadot/api/types';
22import {IKeyringPair} from '@polkadot/types/types';22import {IKeyringPair} from '@polkadot/types/types';
23import usingApi, {submitTransactionAsync} from '../substrate/substrate-api';23import usingApi, {submitTransactionAsync} from '../substrate/substrate-api';
24import {getGenericResult, generateKeyringPair} from '../util/helpers';24import {getGenericResult, generateKeyringPair, waitEvent, describe_xcm} from '../util/helpers';
25import {MultiLocation} from '@polkadot/types/interfaces';
26import {blake2AsHex} from '@polkadot/util-crypto';
25import waitNewBlocks from '../substrate/wait-new-blocks';27import waitNewBlocks from '../substrate/wait-new-blocks';
26import getBalance from '../substrate/get-balance';28import getBalance from '../substrate/get-balance';
2729
3032
31const UNIQUE_CHAIN = 2037;33const UNIQUE_CHAIN = 2037;
32const ACALA_CHAIN = 2000;34const ACALA_CHAIN = 2000;
35const MOONBEAM_CHAIN = 2004;
3336
34const ACALA_PORT = '9946';37const ACALA_PORT = 9946;
38const MOONBEAM_PORT = 9947;
3539
36const TRANSFER_AMOUNT = 2000000000000000000000000n;40const TRANSFER_AMOUNT = 2000000000000000000000000n;
3741
42function parachainApiOptions(port: number): ApiOptions {
43 return {
44 provider: new WsProvider('ws://127.0.0.1:' + port.toString()),
45 };
46}
47
48function acalaOptions(): ApiOptions {
49 return parachainApiOptions(ACALA_PORT);
50}
51
52function moonbeamOptions(): ApiOptions {
53 return parachainApiOptions(MOONBEAM_PORT);
54}
55
38describe('Integration test: Exchanging UNQ with Acala', () => {56describe_xcm('Integration test: Exchanging tokens with Acala', () => {
39 let alice: IKeyringPair;57 let alice: IKeyringPair;
40 let randomAccount: IKeyringPair;58 let randomAccount: IKeyringPair;
41 59
42 let balanceUniqueTokenBefore: bigint;60 let balanceUniqueTokenInit: bigint;
43 let balanceUniqueTokenAfter: bigint;61 let balanceUniqueTokenMiddle: bigint;
44 let balanceUniqueTokenFinal: bigint;62 let balanceUniqueTokenFinal: bigint;
45 let balanceAcalaTokenBefore: bigint;63 let balanceAcalaTokenInit: bigint;
46 let balanceAcalaTokenAfter: bigint;64 let balanceAcalaTokenMiddle: bigint;
47 let balanceAcalaTokenFinal: bigint;65 let balanceAcalaTokenFinal: bigint;
48 let balanceUniqueForeignTokenAfter: bigint;66 let balanceUniqueForeignTokenInit: bigint;
49 let balanceUniqueForeignTokenBefore: bigint;67 let balanceUniqueForeignTokenMiddle: bigint;
50 let balanceUniqueForeignTokenFinal: bigint;68 let balanceUniqueForeignTokenFinal: bigint;
51 69
52 before(async () => {70 before(async () => {
53 await usingApi(async (api, privateKeyWrapper) => {71 await usingApi(async (api, privateKeyWrapper) => {
54 alice = privateKeyWrapper('//Alice');72 alice = privateKeyWrapper('//Alice');
55 randomAccount = generateKeyringPair();73 randomAccount = generateKeyringPair();
56 });74 });
57 75
58 const acalaApiOptions: ApiOptions = {
59 provider: new WsProvider('ws://127.0.0.1:' + ACALA_PORT),
60 };
61
62 // Acala side76 // Acala side
63 await usingApi(77 await usingApi(
64 async (api) => {78 async (api) => {
91 const result1 = getGenericResult(events1);105 const result1 = getGenericResult(events1);
92 expect(result1.success).to.be.true;106 expect(result1.success).to.be.true;
93 107
94 [balanceAcalaTokenBefore] = await getBalance(api, [randomAccount.address]);108 [balanceAcalaTokenInit] = await getBalance(api, [randomAccount.address]);
95 {109 {
96 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;110 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;
97 balanceUniqueForeignTokenBefore = BigInt(free);111 balanceUniqueForeignTokenInit = BigInt(free);
98 }112 }
99 },113 },
100 acalaApiOptions,114 acalaOptions(),
101 );115 );
102 116
103 // Unique side117 // Unique side
107 const result0 = getGenericResult(events0);121 const result0 = getGenericResult(events0);
108 expect(result0.success).to.be.true;122 expect(result0.success).to.be.true;
109 123
110 [balanceUniqueTokenBefore] = await getBalance(api, [randomAccount.address]);124 [balanceUniqueTokenInit] = await getBalance(api, [randomAccount.address]);
111 });125 });
112 });126 });
113 127
165 const result = getGenericResult(events);179 const result = getGenericResult(events);
166 expect(result.success).to.be.true;180 expect(result.success).to.be.true;
167 181
168 [balanceUniqueTokenAfter] = await getBalance(api, [randomAccount.address]);182 [balanceUniqueTokenMiddle] = await getBalance(api, [randomAccount.address]);
169 183
170 const unqFees = balanceUniqueTokenBefore - balanceUniqueTokenAfter;184 const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
171 console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', unqFees);185 console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', unqFees);
172 expect(unqFees > 0n).to.be.true;186 expect(unqFees > 0n).to.be.true;
173 });187 });
174 188
175 // Acala side189 // Acala side
176 await usingApi(190 await usingApi(
177 async (api) => {191 async (api) => {
178 // todo do something about instant sealing, where there might not be any new blocks
179 await waitNewBlocks(api, 3);192 await waitNewBlocks(api, 3);
180 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;193 const {free} = (await api.query.tokens.accounts(randomAccount.addressRaw, {ForeignAsset: 0})).toJSON() as any;
181 balanceUniqueForeignTokenAfter = BigInt(free);194 balanceUniqueForeignTokenMiddle = BigInt(free);
182 195
183 [balanceAcalaTokenAfter] = await getBalance(api, [randomAccount.address]);196 [balanceAcalaTokenMiddle] = await getBalance(api, [randomAccount.address]);
184197
185 const acaFees = balanceAcalaTokenBefore - balanceAcalaTokenAfter;198 const acaFees = balanceAcalaTokenInit - balanceAcalaTokenMiddle;
186 const unqDiffAfterIncomeTransfer = balanceUniqueForeignTokenAfter - balanceUniqueForeignTokenBefore;199 const unqIncomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenInit;
187200
188 const unqFees = unqDiffAfterIncomeTransfer - TRANSFER_AMOUNT;
189
190 console.log('[Unique -> Acala] transaction fees on Acala: %s ACA', acaFees);201 console.log('[Unique -> Acala] transaction fees on Acala: %s ACA', acaFees);
191 console.log('[Unique -> Acala] transaction fees on Acala: %s UNQ', unqFees);202 console.log('[Unique -> Acala] income %s UNQ', unqIncomeTransfer);
192 expect(acaFees == 0n).to.be.true;203 expect(acaFees == 0n).to.be.true;
193 expect(unqFees == 0n).to.be.true;204 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;
194 },205 },
195 {provider: new WsProvider('ws://127.0.0.1:' + ACALA_PORT)},206 acalaOptions(),
196 );207 );
197 });208 });
198 209
221 const id = {232 const id = {
222 ForeignAsset: 0,233 ForeignAsset: 0,
223 };234 };
224 235
225 const amount = TRANSFER_AMOUNT;
226 const destWeight = 50000000;236 const destWeight = 50000000;
227 237
228 const tx = api.tx.xTokens.transfer(id, amount, destination, destWeight);238 const tx = api.tx.xTokens.transfer(id, TRANSFER_AMOUNT, destination, destWeight);
229 const events = await submitTransactionAsync(randomAccount, tx);239 const events = await submitTransactionAsync(randomAccount, tx);
230 const result = getGenericResult(events);240 const result = getGenericResult(events);
231 expect(result.success).to.be.true;241 expect(result.success).to.be.true;
236 balanceUniqueForeignTokenFinal = BigInt(free);246 balanceUniqueForeignTokenFinal = BigInt(free);
237 }247 }
238 248
239 const acaFees = balanceAcalaTokenAfter - balanceAcalaTokenFinal;249 const acaFees = balanceAcalaTokenMiddle - balanceAcalaTokenFinal;
240 const unqDiffAfterOutcomeTransfer = balanceUniqueForeignTokenAfter - TRANSFER_AMOUNT;250 const unqOutcomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenFinal;
241251
242 const unqFees = unqDiffAfterOutcomeTransfer - balanceUniqueForeignTokenFinal;
243
244 console.log('[Acala -> Unique] transaction fees on Acala: %s ACA', acaFees);252 console.log('[Acala -> Unique] transaction fees on Acala: %s ACA', acaFees);
245 console.log('[Acala -> Unique] transaction fees on Acala: %s UNQ', unqFees);253 console.log('[Acala -> Unique] outcome %s UNQ', unqOutcomeTransfer);
246254
247 expect(acaFees > 0).to.be.true;255 expect(acaFees > 0).to.be.true;
248 expect(unqFees == 0n).to.be.true;256 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;
249 },257 },
250 {provider: new WsProvider('ws://127.0.0.1:' + ACALA_PORT)},258 acalaOptions(),
251 );259 );
252260
253 // Unique side261 // Unique side
254 await usingApi(async (api) => {262 await usingApi(async (api) => {
255 // todo do something about instant sealing, where there might not be any new blocks
256 await waitNewBlocks(api, 3);263 await waitNewBlocks(api, 3);
257 264
258 [balanceUniqueTokenFinal] = await getBalance(api, [randomAccount.address]);265 [balanceUniqueTokenFinal] = await getBalance(api, [randomAccount.address]);
259 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenAfter;266 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;
260 expect(actuallyDelivered > 0).to.be.true;267 expect(actuallyDelivered > 0).to.be.true;
268
269 console.log('[Acala -> Unique] actually delivered %s UNQ', actuallyDelivered);
261 270
262 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;271 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;
263 console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', unqFees);272 console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', unqFees);
273 expect(unqFees == 0n).to.be.true;
274 });
275 });
276
277 it('Unique rejects ACA tokens from Acala', async () => {
278 // This test is relevant only when the foreign asset pallet is disabled
279
280 await usingApi(async (api) => {
281 const destination = {
282 V1: {
283 parents: 1,
284 interior: {
285 X2: [
286 {Parachain: UNIQUE_CHAIN},
287 {
288 AccountId32: {
289 network: 'Any',
290 id: randomAccount.addressRaw,
291 },
292 },
293 ],
294 },
295 },
296 };
297
298 const id = {
299 Token: 'ACA',
300 };
301
302 const destWeight = 50000000;
303
304 const tx = api.tx.xTokens.transfer(id, 100_000_000_000, destination, destWeight);
305 const events = await submitTransactionAsync(alice, tx);
306 const result = getGenericResult(events);
307 expect(result.success).to.be.true;
308 }, acalaOptions());
309
310 await usingApi(async api => {
311 const maxWaitBlocks = 3;
312 const xcmpQueueFailEvent = await waitEvent(api, maxWaitBlocks, 'xcmpQueue', 'Fail');
313
314 expect(
315 xcmpQueueFailEvent != null,
316 'Only native token is supported when the Foreign-Assets pallet is not connected',
317 ).to.be.true;
318 });
319 });
320});
321
322describe_xcm('Integration test: Exchanging UNQ with Moonbeam', () => {
323
324 // Unique constants
325 let uniqueAlice: IKeyringPair;
326 let uniqueAssetLocation;
327
328 let randomAccountUnique: IKeyringPair;
329 let randomAccountMoonbeam: IKeyringPair;
330
331 // Moonbeam constants
332 let assetId: string;
333
334 const moonbeamKeyring = new Keyring({type: 'ethereum'});
335 const alithPrivateKey = '0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133';
336 const baltatharPrivateKey = '0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b';
337 const dorothyPrivateKey = '0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68';
338
339 const alithAccount = moonbeamKeyring.addFromUri(alithPrivateKey, undefined, 'ethereum');
340 const baltatharAccount = moonbeamKeyring.addFromUri(baltatharPrivateKey, undefined, 'ethereum');
341 const dorothyAccount = moonbeamKeyring.addFromUri(dorothyPrivateKey, undefined, 'ethereum');
342
343 const councilVotingThreshold = 2;
344 const technicalCommitteeThreshold = 2;
345 const votingPeriod = 3;
346 const delayPeriod = 0;
347
348 const uniqueAssetMetadata = {
349 name: 'xcUnique',
350 symbol: 'xcUNQ',
351 decimals: 18,
352 isFrozen: false,
353 minimalBalance: 1,
354 };
355
356 let balanceUniqueTokenInit: bigint;
357 let balanceUniqueTokenMiddle: bigint;
358 let balanceUniqueTokenFinal: bigint;
359 let balanceForeignUnqTokenInit: bigint;
360 let balanceForeignUnqTokenMiddle: bigint;
361 let balanceForeignUnqTokenFinal: bigint;
362 let balanceGlmrTokenInit: bigint;
363 let balanceGlmrTokenMiddle: bigint;
364 let balanceGlmrTokenFinal: bigint;
365
366 before(async () => {
367 await usingApi(async (api, privateKeyWrapper) => {
368 uniqueAlice = privateKeyWrapper('//Alice');
369 randomAccountUnique = generateKeyringPair();
370 randomAccountMoonbeam = generateKeyringPair('ethereum');
371
372 balanceForeignUnqTokenInit = 0n;
373 });
374
375 await usingApi(
376 async (api) => {
377
378 // >>> Sponsoring Dorothy >>>
379 console.log('Sponsoring Dorothy.......');
380 const tx0 = api.tx.balances.transfer(dorothyAccount.address, 11_000_000_000_000_000_000n);
381 const events0 = await submitTransactionAsync(alithAccount, tx0);
382 const result0 = getGenericResult(events0);
383 expect(result0.success).to.be.true;
384 console.log('Sponsoring Dorothy.......DONE');
385 // <<< Sponsoring Dorothy <<<
386
387 const sourceLocation: MultiLocation = api.createType(
388 'MultiLocation',
389 {
390 parents: 1,
391 interior: {X1: {Parachain: UNIQUE_CHAIN}},
392 },
393 );
394
395 uniqueAssetLocation = {XCM: sourceLocation};
396 const existentialDeposit = 1;
397 const isSufficient = true;
398 const unitsPerSecond = '1';
399 const numAssetsWeightHint = 0;
400
401 const registerTx = api.tx.assetManager.registerForeignAsset(
402 uniqueAssetLocation,
403 uniqueAssetMetadata,
404 existentialDeposit,
405 isSufficient,
406 );
407 console.log('Encoded proposal for registerAsset is %s', registerTx.method.toHex() || '');
408
409 const setUnitsTx = api.tx.assetManager.setAssetUnitsPerSecond(
410 uniqueAssetLocation,
411 unitsPerSecond,
412 numAssetsWeightHint,
413 );
414 console.log('Encoded proposal for setAssetUnitsPerSecond is %s', setUnitsTx.method.toHex() || '');
415
416 const batchCall = api.tx.utility.batchAll([registerTx, setUnitsTx]);
417 console.log('Encoded proposal for batchCall is %s', batchCall.method.toHex() || '');
418
419 // >>> Note motion preimage >>>
420 console.log('Note motion preimage.......');
421 const encodedProposal = batchCall?.method.toHex() || '';
422 const proposalHash = blake2AsHex(encodedProposal);
423 console.log('Encoded proposal for batch utility after schedule is %s', encodedProposal);
424 console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);
425 console.log('Encoded length %d', encodedProposal.length);
426
427 const tx1 = api.tx.democracy.notePreimage(encodedProposal);
428 const events1 = await submitTransactionAsync(baltatharAccount, tx1);
429 const result1 = getGenericResult(events1);
430 expect(result1.success).to.be.true;
431 console.log('Note motion preimage.......DONE');
432 // <<< Note motion preimage <<<
433
434 // >>> Propose external motion through council >>>
435 console.log('Propose external motion through council.......');
436 const externalMotion = api.tx.democracy.externalProposeMajority(proposalHash);
437 const tx2 = api.tx.councilCollective.propose(
438 councilVotingThreshold,
439 externalMotion,
440 externalMotion.encodedLength,
441 );
442 const events2 = await submitTransactionAsync(baltatharAccount, tx2);
443 const result2 = getGenericResult(events2);
444 expect(result2.success).to.be.true;
445
446 const encodedMotion = externalMotion?.method.toHex() || '';
447 const motionHash = blake2AsHex(encodedMotion);
448 console.log('Motion hash is %s', motionHash);
449
450 const tx3 = api.tx.councilCollective.vote(motionHash, 0, true);
451 {
452 const events3 = await submitTransactionAsync(dorothyAccount, tx3);
453 const result3 = getGenericResult(events3);
454 expect(result3.success).to.be.true;
455 }
456 {
457 const events3 = await submitTransactionAsync(baltatharAccount, tx3);
458 const result3 = getGenericResult(events3);
459 expect(result3.success).to.be.true;
460 }
461
462 const tx4 = api.tx.councilCollective.close(motionHash, 0, 1_000_000_000, externalMotion.encodedLength);
463 const events4 = await submitTransactionAsync(dorothyAccount, tx4);
464 const result4 = getGenericResult(events4);
465 expect(result4.success).to.be.true;
466 console.log('Propose external motion through council.......DONE');
467 // <<< Propose external motion through council <<<
468
469 // >>> Fast track proposal through technical committee >>>
470 console.log('Fast track proposal through technical committee.......');
471 const fastTrack = api.tx.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);
472 const tx5 = api.tx.techCommitteeCollective.propose(
473 technicalCommitteeThreshold,
474 fastTrack,
475 fastTrack.encodedLength,
476 );
477 const events5 = await submitTransactionAsync(alithAccount, tx5);
478 const result5 = getGenericResult(events5);
479 expect(result5.success).to.be.true;
480
481 const encodedFastTrack = fastTrack?.method.toHex() || '';
482 const fastTrackHash = blake2AsHex(encodedFastTrack);
483 console.log('FastTrack hash is %s', fastTrackHash);
484
485 const proposalIdx = Number(await api.query.techCommitteeCollective.proposalCount()) - 1;
486 const tx6 = api.tx.techCommitteeCollective.vote(fastTrackHash, proposalIdx, true);
487 {
488 const events6 = await submitTransactionAsync(baltatharAccount, tx6);
489 const result6 = getGenericResult(events6);
490 expect(result6.success).to.be.true;
491 }
492 {
493 const events6 = await submitTransactionAsync(alithAccount, tx6);
494 const result6 = getGenericResult(events6);
495 expect(result6.success).to.be.true;
496 }
497
498 const tx7 = api.tx.techCommitteeCollective
499 .close(fastTrackHash, proposalIdx, 1_000_000_000, fastTrack.encodedLength);
500 const events7 = await submitTransactionAsync(baltatharAccount, tx7);
501 const result7 = getGenericResult(events7);
502 expect(result7.success).to.be.true;
503 console.log('Fast track proposal through technical committee.......DONE');
504 // <<< Fast track proposal through technical committee <<<
505
506 // >>> Referendum voting >>>
507 console.log('Referendum voting.......');
508 const tx8 = api.tx.democracy.vote(
509 0,
510 {Standard: {balance: 10_000_000_000_000_000_000n, vote: {aye: true, conviction: 1}}},
511 );
512 const events8 = await submitTransactionAsync(dorothyAccount, tx8);
513 const result8 = getGenericResult(events8);
514 expect(result8.success).to.be.true;
515 console.log('Referendum voting.......DONE');
516 // <<< Referendum voting <<<
517
518 // >>> Acquire Unique AssetId Info on Moonbeam >>>
519 console.log('Acquire Unique AssetId Info on Moonbeam.......');
520
521 // Wait for the democracy execute
522 await waitNewBlocks(api, 5);
523
524 assetId = (await api.query.assetManager.assetTypeId({
525 XCM: sourceLocation,
526 })).toString();
527
528 console.log('UNQ asset ID is %s', assetId);
529 console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');
530 // >>> Acquire Unique AssetId Info on Moonbeam >>>
531
532 // >>> Sponsoring random Account >>>
533 console.log('Sponsoring random Account.......');
534 const tx10 = api.tx.balances.transfer(randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);
535 const events10 = await submitTransactionAsync(baltatharAccount, tx10);
536 const result10 = getGenericResult(events10);
537 expect(result10.success).to.be.true;
538 console.log('Sponsoring random Account.......DONE');
539 // <<< Sponsoring random Account <<<
540
541 [balanceGlmrTokenInit] = await getBalance(api, [randomAccountMoonbeam.address]);
542 },
543 moonbeamOptions(),
544 );
545
546 await usingApi(async (api) => {
547 const tx0 = api.tx.balances.transfer(randomAccountUnique.address, 10n * TRANSFER_AMOUNT);
548 const events0 = await submitTransactionAsync(uniqueAlice, tx0);
549 const result0 = getGenericResult(events0);
550 expect(result0.success).to.be.true;
551
552 [balanceUniqueTokenInit] = await getBalance(api, [randomAccountUnique.address]);
553 });
554 });
555
556 it('Should connect and send UNQ to Moonbeam', async () => {
557 await usingApi(async (api) => {
558 const currencyId = {
559 NativeAssetId: 'Here',
560 };
561 const dest = {
562 V1: {
563 parents: 1,
564 interior: {
565 X2: [
566 {Parachain: MOONBEAM_CHAIN},
567 {AccountKey20: {network: 'Any', key: randomAccountMoonbeam.address}},
568 ],
569 },
570 },
571 };
572 const amount = TRANSFER_AMOUNT;
573 const destWeight = 850000000;
574
575 const tx = api.tx.xTokens.transfer(currencyId, amount, dest, destWeight);
576 const events = await submitTransactionAsync(randomAccountUnique, tx);
577 const result = getGenericResult(events);
578 expect(result.success).to.be.true;
579
580 [balanceUniqueTokenMiddle] = await getBalance(api, [randomAccountUnique.address]);
581 expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;
582
583 const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
584 console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', transactionFees);
585 expect(transactionFees > 0).to.be.true;
586 });
587
588 await usingApi(
589 async (api) => {
590 await waitNewBlocks(api, 3);
591
592 [balanceGlmrTokenMiddle] = await getBalance(api, [randomAccountMoonbeam.address]);
593
594 const glmrFees = balanceGlmrTokenInit - balanceGlmrTokenMiddle;
595 console.log('[Unique -> Moonbeam] transaction fees on Moonbeam: %s GLMR', glmrFees);
596 expect(glmrFees == 0n).to.be.true;
597
598 const unqRandomAccountAsset = (
599 await api.query.assets.account(assetId, randomAccountMoonbeam.address)
600 ).toJSON()! as any;
601
602 balanceForeignUnqTokenMiddle = BigInt(unqRandomAccountAsset['balance']);
603 const unqIncomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenInit;
604 console.log('[Unique -> Moonbeam] income %s UNQ', unqIncomeTransfer);
605 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;
606 },
607 moonbeamOptions(),
608 );
609 });
610
611 it('Should connect to Moonbeam and send UNQ back', async () => {
612 await usingApi(
613 async (api) => {
614 const asset = {
615 V1: {
616 id: {
617 Concrete: {
618 parents: 1,
619 interior: {
620 X1: {Parachain: UNIQUE_CHAIN},
621 },
622 },
623 },
624 fun: {
625 Fungible: TRANSFER_AMOUNT,
626 },
627 },
628 };
629 const destination = {
630 V1: {
631 parents: 1,
632 interior: {
633 X2: [
634 {Parachain: UNIQUE_CHAIN},
635 {AccountId32: {network: 'Any', id: randomAccountUnique.addressRaw}},
636 ],
637 },
638 },
639 };
640 const destWeight = 50000000;
641
642 const tx = api.tx.xTokens.transferMultiasset(asset, destination, destWeight);
643 const events = await submitTransactionAsync(randomAccountMoonbeam, tx);
644 const result = getGenericResult(events);
645 expect(result.success).to.be.true;
646
647 [balanceGlmrTokenFinal] = await getBalance(api, [randomAccountMoonbeam.address]);
648
649 const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;
650 console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', glmrFees);
651 expect(glmrFees > 0).to.be.true;
652
653 const unqRandomAccountAsset = (
654 await api.query.assets.account(assetId, randomAccountMoonbeam.address)
655 ).toJSON()! as any;
656
657 expect(unqRandomAccountAsset).to.be.null;
658
659 balanceForeignUnqTokenFinal = 0n;
660
661 const unqOutcomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenFinal;
662 console.log('[Unique -> Moonbeam] outcome %s UNQ', unqOutcomeTransfer);
663 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;
664 },
665 moonbeamOptions(),
666 );
667
668 await usingApi(async (api) => {
669 await waitNewBlocks(api, 3);
670
671 [balanceUniqueTokenFinal] = await getBalance(api, [randomAccountUnique.address]);
672 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;
673 expect(actuallyDelivered > 0).to.be.true;
674
675 console.log('[Moonbeam -> Unique] actually delivered %s UNQ', actuallyDelivered);
676
677 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;
678 console.log('[Moonbeam -> Unique] transaction fees on Unique: %s UNQ', unqFees);
264 expect(unqFees == 0n).to.be.true;679 expect(unqFees == 0n).to.be.true;
265 });680 });
266 });681 });