1234567891011121314151617import type {IKeyringPair} from '@polkadot/types/types';18import config from '../config.js';19import {itSub, expect, describeXCM, usingPlaygrounds, usingWestmintPlaygrounds, usingRelayPlaygrounds} from '../util/index.js';2021const STATEMINE_CHAIN = +(process.env.RELAY_WESTMINT_ID || 1000);22const UNIQUE_CHAIN = +(process.env.RELAY_OPAL_ID || 2095);2324const relayUrl = config.relayUrl;25const westmintUrl = config.westmintUrl;2627const STATEMINE_PALLET_INSTANCE = 50;28const ASSET_ID = 100;29const ASSET_METADATA_DECIMALS = 18;30const ASSET_METADATA_NAME = 'USDT';31const ASSET_METADATA_DESCRIPTION = 'USDT';32const ASSET_METADATA_MINIMAL_BALANCE = 1n;3334const RELAY_DECIMALS = 12;35const WESTMINT_DECIMALS = 12;3637const TRANSFER_AMOUNT = 1_000_000_000_000_000_000n;383940const ASSET_AMOUNT = 1_000_000_000_000_000_000_000n;4142describeXCM('[XCM] Integration test: Exchanging USDT with Westmint', () => {43 let alice: IKeyringPair;44 let bob: IKeyringPair;4546 let balanceStmnBefore: bigint;47 let balanceStmnAfter: bigint;4849 let balanceOpalBefore: bigint;50 let balanceOpalAfter: bigint;51 let balanceOpalFinal: bigint;5253 let balanceBobBefore: bigint;54 let balanceBobAfter: bigint;55 let balanceBobFinal: bigint;5657 let balanceBobRelayTokenBefore: bigint;58 let balanceBobRelayTokenAfter: bigint;596061 before(async () => {62 await usingPlaygrounds(async (_helper, privateKey) => {63 alice = await privateKey('//Alice');64 bob = await privateKey('//Bob'); 65 });6667 await usingWestmintPlaygrounds(westmintUrl, async (helper) => {68 69 const fundingAmount = 3_500_000_000_000n;7071 await helper.assets.create(alice, ASSET_ID, alice.address, ASSET_METADATA_MINIMAL_BALANCE);72 await helper.assets.setMetadata(alice, ASSET_ID, ASSET_METADATA_NAME, ASSET_METADATA_DESCRIPTION, ASSET_METADATA_DECIMALS);73 await helper.assets.mint(alice, ASSET_ID, alice.address, ASSET_AMOUNT);7475 76 const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(UNIQUE_CHAIN);77 await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, fundingAmount);78 });798081 await usingPlaygrounds(async (helper) => {82 const location = {83 V2: {84 parents: 1,85 interior: {X3: [86 {87 Parachain: STATEMINE_CHAIN,88 },89 {90 PalletInstance: STATEMINE_PALLET_INSTANCE,91 },92 {93 GeneralIndex: ASSET_ID,94 },95 ]},96 },97 };9899 const metadata =100 {101 name: ASSET_ID,102 symbol: ASSET_METADATA_NAME,103 decimals: ASSET_METADATA_DECIMALS,104 minimalBalance: ASSET_METADATA_MINIMAL_BALANCE,105 };106 await helper.getSudo().foreignAssets.register(alice, alice.address, location, metadata);107 balanceOpalBefore = await helper.balance.getSubstrate(alice.address);108 });109110111 112 await usingRelayPlaygrounds(relayUrl, async (helper) => {113 const destination = {114 V2: {115 parents: 0,116 interior: {X1: {117 Parachain: UNIQUE_CHAIN,118 },119 },120 }};121122 const beneficiary = {123 V2: {124 parents: 0,125 interior: {X1: {126 AccountId32: {127 network: 'Any',128 id: alice.addressRaw,129 },130 }},131 },132 };133134 const assets = {135 V2: [136 {137 id: {138 Concrete: {139 parents: 0,140 interior: 'Here',141 },142 },143 fun: {144 Fungible: 50_000_000_000_000_000n,145 },146 },147 ],148 };149150 const feeAssetItem = 0;151152 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited');153 });154155 });156157 itSub('Should connect and send USDT from Westmint to Opal', async ({helper}) => {158 await usingWestmintPlaygrounds(westmintUrl, async (helper) => {159 const dest = {160 V2: {161 parents: 1,162 interior: {X1: {163 Parachain: UNIQUE_CHAIN,164 },165 },166 }};167168 const beneficiary = {169 V2: {170 parents: 0,171 interior: {X1: {172 AccountId32: {173 network: 'Any',174 id: alice.addressRaw,175 },176 }},177 },178 };179180 const assets = {181 V2: [182 {183 id: {184 Concrete: {185 parents: 0,186 interior: {187 X2: [188 {189 PalletInstance: STATEMINE_PALLET_INSTANCE,190 },191 {192 GeneralIndex: ASSET_ID,193 },194 ]},195 },196 },197 fun: {198 Fungible: TRANSFER_AMOUNT,199 },200 },201 ],202 };203204 const feeAssetItem = 0;205206 balanceStmnBefore = await helper.balance.getSubstrate(alice.address);207 await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited');208209 balanceStmnAfter = await helper.balance.getSubstrate(alice.address);210211 212 console.log(213 '[Westmint -> Opal] transaction fees on Westmint: %s WND',214 helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, WESTMINT_DECIMALS),215 );216 expect(balanceStmnBefore > balanceStmnAfter).to.be.true;217218 });219220221 222 await helper.wait.newBlocks(3);223224 225 const free = await helper.ft.getBalance(1, {Substrate: alice.address});226227 balanceOpalAfter = await helper.balance.getSubstrate(alice.address);228229 console.log(230 '[Westmint -> Opal] transaction fees on Opal: %s USDT',231 helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, ASSET_METADATA_DECIMALS),232 );233 console.log(234 '[Westmint -> Opal] transaction fees on Opal: %s OPL',235 helper.util.bigIntToDecimals(balanceOpalAfter - balanceOpalBefore),236 );237238 239 expect(free == TRANSFER_AMOUNT).to.be.true;240 241 expect(balanceOpalAfter == balanceOpalBefore).to.be.true;242 });243244 itSub('Should connect and send USDT from Unique to Statemine back', async ({helper}) => {245 const destination = {246 V2: {247 parents: 1,248 interior: {X2: [249 {250 Parachain: STATEMINE_CHAIN,251 },252 {253 AccountId32: {254 network: 'Any',255 id: alice.addressRaw,256 },257 },258 ]},259 },260 };261262 const currencies: [any, bigint][] = [263 [264 {265 ForeignAssetId: 0,266 },267 268 TRANSFER_AMOUNT,269 ],270 [271 {272 NativeAssetId: 'Parent',273 },274 400_000_000_000_000n,275 ],276 ];277278 const feeItem = 1;279280 await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited');281282 283 balanceOpalFinal = await helper.balance.getSubstrate(alice.address);284 expect(balanceOpalAfter > balanceOpalFinal).to.be.true;285286 await usingWestmintPlaygrounds(westmintUrl, async (helper) => {287 await helper.wait.newBlocks(3);288289 290 291 expect((await helper.assets.account(ASSET_ID, alice.address))! == ASSET_AMOUNT).to.be.true;292 });293 });294295 itSub('Should connect and send Relay token to Unique', async ({helper}) => {296 const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n;297298 balanceBobBefore = await helper.balance.getSubstrate(bob.address);299 balanceBobRelayTokenBefore = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});300301 302 await usingRelayPlaygrounds(relayUrl, async (helper) => {303 const destination = {304 V2: {305 parents: 0,306 interior: {X1: {307 Parachain: UNIQUE_CHAIN,308 },309 },310 }};311312 const beneficiary = {313 V2: {314 parents: 0,315 interior: {X1: {316 AccountId32: {317 network: 'Any',318 id: bob.addressRaw,319 },320 }},321 },322 };323324 const assets = {325 V2: [326 {327 id: {328 Concrete: {329 parents: 0,330 interior: 'Here',331 },332 },333 fun: {334 Fungible: TRANSFER_AMOUNT_RELAY,335 },336 },337 ],338 };339340 const feeAssetItem = 0;341342 await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited');343 });344345 await helper.wait.newBlocks(3);346347 balanceBobAfter = await helper.balance.getSubstrate(bob.address);348 balanceBobRelayTokenAfter = await helper.tokens.accounts(bob.address, {NativeAssetId: 'Parent'});349350 const wndFee = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore;351 console.log(352 'Relay (Westend) to Opal transaction fees: %s OPL',353 helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore),354 );355 console.log(356 'Relay (Westend) to Opal transaction fees: %s WND',357 helper.util.bigIntToDecimals(wndFee, WESTMINT_DECIMALS),358 );359 expect(balanceBobBefore == balanceBobAfter).to.be.true;360 expect(balanceBobRelayTokenBefore < balanceBobRelayTokenAfter).to.be.true;361 });362363 itSub('Should connect and send Relay token back', async ({helper}) => {364 let relayTokenBalanceBefore: bigint;365 let relayTokenBalanceAfter: bigint;366 await usingRelayPlaygrounds(relayUrl, async (helper) => {367 relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address);368 });369370 const destination = {371 V2: {372 parents: 1,373 interior: {374 X1:{375 AccountId32: {376 network: 'Any',377 id: bob.addressRaw,378 },379 },380 },381 },382 };383384 const currencies: any = [385 [386 {387 NativeAssetId: 'Parent',388 },389 50_000_000_000_000_000n,390 ],391 ];392393 const feeItem = 0;394395 await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited');396397 balanceBobFinal = await helper.balance.getSubstrate(bob.address);398 console.log('[Opal -> Relay (Westend)] transaction fees: %s OPL', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));399400 await usingRelayPlaygrounds(relayUrl, async (helper) => {401 await helper.wait.newBlocks(10);402 relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);403404 const diff = relayTokenBalanceAfter - relayTokenBalanceBefore;405 console.log('[Opal -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS));406 expect(diff > 0, 'Relay tokens was not delivered back').to.be.true;407 });408 });409});