From ec30dd4f8d24f6a907df12a690f2e20cd8fad267 Mon Sep 17 00:00:00 2001 From: magecnion Date: Tue, 5 Nov 2024 09:09:55 +0100 Subject: [PATCH] fmt --- e2e-tests/tests/test-staking.ts | 94 ++-- e2e-tests/tests/test-teleport-laos.ts | 771 +++++++++++++------------- e2e-tests/tests/util.ts | 1 - 3 files changed, 444 insertions(+), 422 deletions(-) diff --git a/e2e-tests/tests/test-staking.ts b/e2e-tests/tests/test-staking.ts index effea241..41c20838 100644 --- a/e2e-tests/tests/test-staking.ts +++ b/e2e-tests/tests/test-staking.ts @@ -14,52 +14,58 @@ import Contract from "web3-eth-contract"; import { step } from "mocha-steps"; import { Keyring } from "@polkadot/api"; -describeWithExistingNode("Frontier RPC (Staking)", (context) => { - let contract: Contract; +describeWithExistingNode( + "Frontier RPC (Staking)", + (context) => { + let contract: Contract; - before(async function () { - contract = new context.web3.eth.Contract(STAKING_ABI, STAKING_CONTRACT_ADDRESS, { - from: ALITH, + before(async function () { + contract = new context.web3.eth.Contract(STAKING_ABI, STAKING_CONTRACT_ADDRESS, { + from: ALITH, + }); + context.web3.eth.accounts.wallet.add(BALTATHAR_PRIVATE_KEY); + context.web3.eth.accounts.wallet.add(FAITH_PRIVATE_KEY); }); - context.web3.eth.accounts.wallet.add(BALTATHAR_PRIVATE_KEY); - context.web3.eth.accounts.wallet.add(FAITH_PRIVATE_KEY); - }); - step("Faith can join as candidate", async function () { - // insert session key into the node and link to Faith - const faith = new Keyring({ type: "ethereum" }).addFromUri(FAITH_PRIVATE_KEY); - const key = (await context.networks.laos.rpc.author.rotateKeys()).toHex(); - context.networks.laos.tx.session - .setKeys(key, "") - .signAndSend(faith, () => {}) - .catch((error: any) => { - console.log("transaction failed", error); - }); + step("Faith can join as candidate", async function () { + // insert session key into the node and link to Faith + const faith = new Keyring({ type: "ethereum" }).addFromUri(FAITH_PRIVATE_KEY); + const key = (await context.networks.laos.rpc.author.rotateKeys()).toHex(); + context.networks.laos.tx.session + .setKeys(key, "") + .signAndSend(faith, () => {}) + .catch((error: any) => { + console.log("transaction failed", error); + }); - expect(await contract.methods.isCandidate(FAITH).call()).to.be.eq(false); - const candidateCount = await contract.methods.candidateCount().call(); - expect((await context.web3.eth.getBlock("latest")).baseFeePerGas.toString()).to.be.eq( - await context.web3.eth.getGasPrice() - ); // it starts with 1 Gwei and decreases until 0.5 Gwei - const estimatedGas = await contract.methods.joinCandidates(BigInt(20000) * UNIT, candidateCount).estimateGas(); - const gasPrice = (await context.web3.eth.getGasPrice()) + 1; // if we don't add +1 tx never gets included in the block - let nonce = await context.web3.eth.getTransactionCount(FAITH); - const result = await contract.methods - .joinCandidates(BigInt(20000) * UNIT, candidateCount) - .send({ from: FAITH, gas: estimatedGas, gasPrice, nonce: nonce++ }); - expect(result.status).to.be.eq(true); - expect(await contract.methods.isCandidate(FAITH).call()).to.be.eq(true); - }); + expect(await contract.methods.isCandidate(FAITH).call()).to.be.eq(false); + const candidateCount = await contract.methods.candidateCount().call(); + expect((await context.web3.eth.getBlock("latest")).baseFeePerGas.toString()).to.be.eq( + await context.web3.eth.getGasPrice() + ); // it starts with 1 Gwei and decreases until 0.5 Gwei + const estimatedGas = await contract.methods + .joinCandidates(BigInt(20000) * UNIT, candidateCount) + .estimateGas(); + const gasPrice = (await context.web3.eth.getGasPrice()) + 1; // if we don't add +1 tx never gets included in the block + let nonce = await context.web3.eth.getTransactionCount(FAITH); + const result = await contract.methods + .joinCandidates(BigInt(20000) * UNIT, candidateCount) + .send({ from: FAITH, gas: estimatedGas, gasPrice, nonce: nonce++ }); + expect(result.status).to.be.eq(true); + expect(await contract.methods.isCandidate(FAITH).call()).to.be.eq(true); + }); - step("Baltathar can delegate to Faith", async function () { - expect(await contract.methods.isDelegator(BALTATHAR).call()).to.be.eq(false); - let nonce = await context.web3.eth.getTransactionCount(BALTATHAR); - const gasPrice = (await context.web3.eth.getGasPrice()) + 1; // if we don't add +1 tx never gets included in the block - const estimatedGas = await contract.methods.delegate(FAITH, BigInt(1000) * UNIT, 0, 0).estimateGas(); - const result = await contract.methods - .delegate(FAITH, BigInt(1000) * UNIT, 0, 0) - .send({ from: BALTATHAR, gas: estimatedGas, gasPrice, nonce: nonce++ }); - expect(result.status).to.be.eq(true); - expect(await contract.methods.isDelegator(BALTATHAR).call()).to.be.eq(true); - }); -}, true); + step("Baltathar can delegate to Faith", async function () { + expect(await contract.methods.isDelegator(BALTATHAR).call()).to.be.eq(false); + let nonce = await context.web3.eth.getTransactionCount(BALTATHAR); + const gasPrice = (await context.web3.eth.getGasPrice()) + 1; // if we don't add +1 tx never gets included in the block + const estimatedGas = await contract.methods.delegate(FAITH, BigInt(1000) * UNIT, 0, 0).estimateGas(); + const result = await contract.methods + .delegate(FAITH, BigInt(1000) * UNIT, 0, 0) + .send({ from: BALTATHAR, gas: estimatedGas, gasPrice, nonce: nonce++ }); + expect(result.status).to.be.eq(true); + expect(await contract.methods.isDelegator(BALTATHAR).call()).to.be.eq(true); + }); + }, + true +); diff --git a/e2e-tests/tests/test-teleport-laos.ts b/e2e-tests/tests/test-teleport-laos.ts index 91f598cf..f701e29a 100644 --- a/e2e-tests/tests/test-teleport-laos.ts +++ b/e2e-tests/tests/test-teleport-laos.ts @@ -30,79 +30,155 @@ const ONE_LAOS = new BN("1000000000000000000"); const ONE_DOT = new BN("1000000000000"); const WAITING_BLOCKS_FOR_EVENTS = 20; // Number of blocks we wait at max to receive an event -describeWithExistingNode("Teleport Asset Hub <-> Laos", (context) => { - const laosSiblingAccount = sovereignAccountOf(LAOS_PARA_ID); - - // APIS - let apiAssetHub: ExtendedAssetHubApi; - let apiLaos: ApiPromise; - let apiRelaychain: ApiPromise; - - //Accounts - let alice: KeyringPair; - let alith: KeyringPair; - - before(async function () { - // Initialize the APIs - apiAssetHub = context.networks.assetHub; - apiLaos = context.networks.laos; - apiRelaychain = context.networks.relaychain; - - //Initialize the accounts - alice = new Keyring({ type: "sr25519" }).addFromUri("//Alice"); - alith = new Keyring({ type: "ethereum" }).addFromUri(ALITH_PRIVATE_KEY); - - debugTeleport("Waiting until all the relay chain, Asset Hub and Laos produce blocks..."); - await Promise.all([awaitBlockChange(apiRelaychain), awaitBlockChange(apiAssetHub), awaitBlockChange(apiLaos)]); - - debugTeleport("[RELAY_CHAIN] Send transaction to open HRMP channels between AssetHub and Laos..."); // See: https://github.com/paritytech/polkadot-sdk/pull/1616 - await sendOpenHrmpChannelTxs(apiRelaychain, LAOS_PARA_ID, ASSET_HUB_PARA_ID); - }); - - step("HRMP channels between AssetHub and Laos are open", async function () { - expect(await isChannelOpen(apiRelaychain, LAOS_PARA_ID, ASSET_HUB_PARA_ID)).to.be.true; - expect(await isChannelOpen(apiRelaychain, ASSET_HUB_PARA_ID, LAOS_PARA_ID)).to.be.true; - }); - - step("Create $LAOS in AssetHub", async function () { - const laosForeignAssetExists = !(await apiAssetHub.query.foreignAssets.asset(apiAssetHub.laosAssetId)).isEmpty; - - // NOTE: We only create the foreign asset if it hasn't been created yet, in this way we ensure tests are idempotent - if (!laosForeignAssetExists) { - //Fund LAOS sovereigna account - debugTeleport("[ASSET_HUB] Funding Laos sovereign account..."); - await transferBalance(apiAssetHub, alice, laosSiblingAccount, ONE_DOT.muln(100)); - - // Build XCM instruction - const foreign_asset_admin = apiAssetHub.createType("MultiAddress", laosSiblingAccount) as MultiAddress; - const createCall = apiAssetHub.tx.foreignAssets.create( +describeWithExistingNode( + "Teleport Asset Hub <-> Laos", + (context) => { + const laosSiblingAccount = sovereignAccountOf(LAOS_PARA_ID); + + // APIS + let apiAssetHub: ExtendedAssetHubApi; + let apiLaos: ApiPromise; + let apiRelaychain: ApiPromise; + + //Accounts + let alice: KeyringPair; + let alith: KeyringPair; + + before(async function () { + // Initialize the APIs + apiAssetHub = context.networks.assetHub; + apiLaos = context.networks.laos; + apiRelaychain = context.networks.relaychain; + + //Initialize the accounts + alice = new Keyring({ type: "sr25519" }).addFromUri("//Alice"); + alith = new Keyring({ type: "ethereum" }).addFromUri(ALITH_PRIVATE_KEY); + + debugTeleport("Waiting until all the relay chain, Asset Hub and Laos produce blocks..."); + await Promise.all([ + awaitBlockChange(apiRelaychain), + awaitBlockChange(apiAssetHub), + awaitBlockChange(apiLaos), + ]); + + debugTeleport("[RELAY_CHAIN] Send transaction to open HRMP channels between AssetHub and Laos..."); // See: https://github.com/paritytech/polkadot-sdk/pull/1616 + await sendOpenHrmpChannelTxs(apiRelaychain, LAOS_PARA_ID, ASSET_HUB_PARA_ID); + }); + + step("HRMP channels between AssetHub and Laos are open", async function () { + expect(await isChannelOpen(apiRelaychain, LAOS_PARA_ID, ASSET_HUB_PARA_ID)).to.be.true; + expect(await isChannelOpen(apiRelaychain, ASSET_HUB_PARA_ID, LAOS_PARA_ID)).to.be.true; + }); + + step("Create $LAOS in AssetHub", async function () { + const laosForeignAssetExists = !(await apiAssetHub.query.foreignAssets.asset(apiAssetHub.laosAssetId)) + .isEmpty; + + // NOTE: We only create the foreign asset if it hasn't been created yet, in this way we ensure tests are idempotent + if (!laosForeignAssetExists) { + //Fund LAOS sovereigna account + debugTeleport("[ASSET_HUB] Funding Laos sovereign account..."); + await transferBalance(apiAssetHub, alice, laosSiblingAccount, ONE_DOT.muln(100)); + + // Build XCM instruction + const foreign_asset_admin = apiAssetHub.createType("MultiAddress", laosSiblingAccount) as MultiAddress; + const createCall = apiAssetHub.tx.foreignAssets.create( + apiAssetHub.laosAssetId, + foreign_asset_admin, + ONE_LAOS + ); + + const createEncodedCall = apiLaos.createType("DoubleEncodedCall", { + encoded: u8aToHex(createCall.method.toU8a()), + }) as DoubleEncodedCall; + + const instruction = buildXcmInstruction({ + api: apiLaos, + calls: [createEncodedCall], + refTime: new BN(1000000000), + proofSize: new BN(5000), + amount: ONE_DOT, + originKind: apiLaos.createType("XcmOriginKind", "Xcm"), + }); + + const destination = apiLaos.createType("XcmVersionedLocation", { + V3: siblingLocation(ASSET_HUB_PARA_ID), + }) as XcmVersionedLocation; + + // Get balances before teleporting. + const alithBalanceBefore = new BN((await apiLaos.query.system.account(alith.address)).data.free); + const laosBalanceBefore = new BN( + (await apiAssetHub.query.system.account(laosSiblingAccount)).data.free + ); + + // Send the XCM instruction from Laos to Asset Hub + const sudoCall = apiLaos.tx.sudo.sudo(apiLaos.tx.polkadotXcm.send(destination, instruction)); + try { + await sudoCall.signAndSend(alith); + } catch (error) { + console.log("transaction failed", error); + } + + // Check if the foreign asset has been created in Asset Hub + const event = await waitForEvent( + apiAssetHub, + ({ event }) => apiAssetHub.events.foreignAssets.Created.is(event), + WAITING_BLOCKS_FOR_EVENTS + ); + + expect(event).to.not.be.null; + const [assetId, creator, owner] = event.event.data; + expect(assetId.toString()).to.equal(apiAssetHub.laosAssetId.toString()); + expect(creator.toString()).to.equal(laosSiblingAccount); + expect(owner.toString()).to.equal(laosSiblingAccount); + + // Check that balances are correct. + const alithBalance = new BN((await apiLaos.query.system.account(alith.address)).data.free); + expect(alithBalanceBefore.eq(alithBalance), "Alith balance shouldn't change"); + + const laosBalance = new BN((await apiAssetHub.query.system.account(laosSiblingAccount)).data.free); + const decreaseOfLaosBalance = laosBalanceBefore.sub(laosBalance); + expect( + decreaseOfLaosBalance.eq(ONE_DOT.add(apiAssetHub.consts.assets.assetDeposit)), + "Laos balance should decrease by the XCM withdrawn amount plus the asset deposit" + ); + + expect( + (await apiAssetHub.query.foreignAssets.asset(apiAssetHub.laosAssetId)).isEmpty, + "$LAOS has not been created" + ).to.be.false; + } else { + debugTeleport("$LAOS already exists, skipping creation..."); + } + }); + + step("Mint $LAOS in AssetHub", async function () { + // Build XCM instructions + const ferdie = new Keyring({ type: "sr25519" }).addFromUri("//Ferdie"); + const ferdieMultiaddress = apiAssetHub.createType("MultiAddress", ferdie.address) as MultiAddress; + const mintLaosCall = apiAssetHub.tx.foreignAssets.mint( apiAssetHub.laosAssetId, - foreign_asset_admin, - ONE_LAOS + ferdieMultiaddress, + ONE_LAOS.muln(10000) ); - - const createEncodedCall = apiLaos.createType("DoubleEncodedCall", { - encoded: u8aToHex(createCall.method.toU8a()), + const mintLaosEncodedCall = apiLaos.createType("DoubleEncodedCall", { + encoded: u8aToHex(mintLaosCall.method.toU8a()), }) as DoubleEncodedCall; - const instruction = buildXcmInstruction({ api: apiLaos, - calls: [createEncodedCall], - refTime: new BN(1000000000), - proofSize: new BN(5000), + calls: [mintLaosEncodedCall], + refTime: new BN(2000000000), + proofSize: new BN(7000), amount: ONE_DOT, - originKind: apiLaos.createType("XcmOriginKind", "Xcm"), + originKind: apiLaos.createType("XcmOriginKind", "SovereignAccount"), }); - const destination = apiLaos.createType("XcmVersionedLocation", { V3: siblingLocation(ASSET_HUB_PARA_ID), }) as XcmVersionedLocation; - // Get balances before teleporting. + // Send the XCM instruction from Laos to Asset Hub const alithBalanceBefore = new BN((await apiLaos.query.system.account(alith.address)).data.free); const laosBalanceBefore = new BN((await apiAssetHub.query.system.account(laosSiblingAccount)).data.free); - - // Send the XCM instruction from Laos to Asset Hub const sudoCall = apiLaos.tx.sudo.sudo(apiLaos.tx.polkadotXcm.send(destination, instruction)); try { await sudoCall.signAndSend(alith); @@ -110,363 +186,304 @@ describeWithExistingNode("Teleport Asset Hub <-> Laos", (context) => { console.log("transaction failed", error); } - // Check if the foreign asset has been created in Asset Hub + // Check if the foreign asset has been minted in Asset Hub const event = await waitForEvent( apiAssetHub, - ({ event }) => apiAssetHub.events.foreignAssets.Created.is(event), + ({ event }) => apiAssetHub.events.foreignAssets.Issued.is(event), WAITING_BLOCKS_FOR_EVENTS ); expect(event).to.not.be.null; - const [assetId, creator, owner] = event.event.data; - expect(assetId.toString()).to.equal(apiAssetHub.laosAssetId.toString()); - expect(creator.toString()).to.equal(laosSiblingAccount); - expect(owner.toString()).to.equal(laosSiblingAccount); - - // Check that balances are correct. const alithBalance = new BN((await apiLaos.query.system.account(alith.address)).data.free); expect(alithBalanceBefore.eq(alithBalance), "Alith balance shouldn't change"); const laosBalance = new BN((await apiAssetHub.query.system.account(laosSiblingAccount)).data.free); const decreaseOfLaosBalance = laosBalanceBefore.sub(laosBalance); - expect( - decreaseOfLaosBalance.eq(ONE_DOT.add(apiAssetHub.consts.assets.assetDeposit)), - "Laos balance should decrease by the XCM withdrawn amount plus the asset deposit" + expect(decreaseOfLaosBalance.eq(ONE_DOT), "Laos should decrease XCM withdrawn amount"); + + const ferdieXLaosBalance = hexToBn( + (await apiAssetHub.query.foreignAssets.account(apiAssetHub.laosAssetId, ferdie.address)).toJSON()[ + "balance" + ] ); + expect(ferdieXLaosBalance.gte(new BN(0)), "Ferdie balance should be > 0"); + }); + step("Create $LAOS/$DOT pool in AssetHub", async function () { + // NOTE: We only create the pool if it hasn't been created yet, in this way we ensure tests are idempotent + const poolExists = !( + await apiAssetHub.query.assetConversion.pools([apiAssetHub.relayAssetId, apiAssetHub.laosAssetId]) + ).isEmpty; + if (!poolExists) { + // Build XCM instruction to be included in xcm.send call + const createPoolCall = apiAssetHub.tx.assetConversion.createPool( + apiAssetHub.relayAssetId.toU8a(), + apiAssetHub.laosAssetId.toU8a() + ); + const createPoolEncodedCall = apiLaos.createType("DoubleEncodedCall", { + encoded: u8aToHex(createPoolCall.method.toU8a()), + }) as DoubleEncodedCall; + const instruction = buildXcmInstruction({ + api: apiLaos, + calls: [createPoolEncodedCall], + refTime: new BN(2000000000), + proofSize: new BN(7000), + amount: ONE_DOT, + originKind: apiLaos.createType("XcmOriginKind", "SovereignAccount"), + }); + const destination = apiLaos.createType("XcmVersionedLocation", { + V3: siblingLocation(ASSET_HUB_PARA_ID), + }) as XcmVersionedLocation; + + // Send the XCM instruction from Laos to Asset Hub + const laosBalanceBefore = new BN( + (await apiAssetHub.query.system.account(laosSiblingAccount)).data.free + ); + const alithBalanceBefore = new BN((await apiLaos.query.system.account(alith.address)).data.free); + const sudoCall = apiLaos.tx.sudo.sudo(apiLaos.tx.polkadotXcm.send(destination, instruction)); + try { + await sudoCall.signAndSend(alith); + } catch (error) { + console.log("transaction failed", error); + } + + // Check that pool has been created in Asset Hub + const event = await waitForEvent( + apiAssetHub, + ({ event }) => apiAssetHub.events.assetConversion.PoolCreated.is(event), + WAITING_BLOCKS_FOR_EVENTS + ); + + expect(event).to.not.be.null; + const [creator, poolId] = event.event.data; + expect(creator.toString()).to.equal(laosSiblingAccount); + expect(poolId.toJSON()).to.deep.equal([relayLocation(), siblingLocation(LAOS_PARA_ID)]); + expect( + (await apiAssetHub.query.assetConversion.pools([apiAssetHub.relayAssetId, apiAssetHub.laosAssetId])) + .isEmpty + ).to.be.false; + + const alithBalance = new BN((await apiLaos.query.system.account(alith.address)).data.free); + expect(alithBalanceBefore.eq(alithBalance), "Alith balance shouldn't change"); + + const laosBalance = new BN((await apiAssetHub.query.system.account(laosSiblingAccount)).data.free); + const decreaseOfLaosBalance = laosBalanceBefore.sub(laosBalance); + expect( + decreaseOfLaosBalance.eq(ONE_DOT.add(apiAssetHub.consts.assets.assetAccountDeposit)), + "Laos should decrease by the XCM withdrawn amount plus the asset account deposit" + ); + } else { + debugTeleport("Pool already exists, skipping creation..."); + } + + // Add liquidity to the pool + const ferdie = new Keyring({ type: "sr25519" }).addFromUri("//Ferdie"); + const liquidityAmountLaos = new BN(ONE_LAOS.muln(1000)); + const liquidityAmountDot = new BN(ONE_DOT.muln(1000)); + const ferdieBalance = new BN((await apiAssetHub.query.system.account(ferdie.address)).data.free); + const ferdieXLaosBalance = hexToBn( + (await apiAssetHub.query.foreignAssets.account(apiAssetHub.laosAssetId, ferdie.address)).toJSON()[ + "balance" + ] + ); expect( - (await apiAssetHub.query.foreignAssets.asset(apiAssetHub.laosAssetId)).isEmpty, - "$LAOS has not been created" - ).to.be.false; - } else { - debugTeleport("$LAOS already exists, skipping creation..."); - } - }); - - step("Mint $LAOS in AssetHub", async function () { - // Build XCM instructions - const ferdie = new Keyring({ type: "sr25519" }).addFromUri("//Ferdie"); - const ferdieMultiaddress = apiAssetHub.createType("MultiAddress", ferdie.address) as MultiAddress; - const mintLaosCall = apiAssetHub.tx.foreignAssets.mint( - apiAssetHub.laosAssetId, - ferdieMultiaddress, - ONE_LAOS.muln(10000) - ); - const mintLaosEncodedCall = apiLaos.createType("DoubleEncodedCall", { - encoded: u8aToHex(mintLaosCall.method.toU8a()), - }) as DoubleEncodedCall; - const instruction = buildXcmInstruction({ - api: apiLaos, - calls: [mintLaosEncodedCall], - refTime: new BN(2000000000), - proofSize: new BN(7000), - amount: ONE_DOT, - originKind: apiLaos.createType("XcmOriginKind", "SovereignAccount"), - }); - const destination = apiLaos.createType("XcmVersionedLocation", { - V3: siblingLocation(ASSET_HUB_PARA_ID), - }) as XcmVersionedLocation; - - // Send the XCM instruction from Laos to Asset Hub - const alithBalanceBefore = new BN((await apiLaos.query.system.account(alith.address)).data.free); - const laosBalanceBefore = new BN((await apiAssetHub.query.system.account(laosSiblingAccount)).data.free); - const sudoCall = apiLaos.tx.sudo.sudo(apiLaos.tx.polkadotXcm.send(destination, instruction)); - try { - await sudoCall.signAndSend(alith); - } catch (error) { - console.log("transaction failed", error); - } - - // Check if the foreign asset has been minted in Asset Hub - const event = await waitForEvent( - apiAssetHub, - ({ event }) => apiAssetHub.events.foreignAssets.Issued.is(event), - WAITING_BLOCKS_FOR_EVENTS - ); - - expect(event).to.not.be.null; - const alithBalance = new BN((await apiLaos.query.system.account(alith.address)).data.free); - expect(alithBalanceBefore.eq(alithBalance), "Alith balance shouldn't change"); - - const laosBalance = new BN((await apiAssetHub.query.system.account(laosSiblingAccount)).data.free); - const decreaseOfLaosBalance = laosBalanceBefore.sub(laosBalance); - expect(decreaseOfLaosBalance.eq(ONE_DOT), "Laos should decrease XCM withdrawn amount"); - - const ferdieXLaosBalance = hexToBn( - (await apiAssetHub.query.foreignAssets.account(apiAssetHub.laosAssetId, ferdie.address)).toJSON()["balance"] - ); - expect(ferdieXLaosBalance.gte(new BN(0)), "Ferdie balance should be > 0"); - }); - - step("Create $LAOS/$DOT pool in AssetHub", async function () { - // NOTE: We only create the pool if it hasn't been created yet, in this way we ensure tests are idempotent - const poolExists = !( - await apiAssetHub.query.assetConversion.pools([apiAssetHub.relayAssetId, apiAssetHub.laosAssetId]) - ).isEmpty; - if (!poolExists) { - // Build XCM instruction to be included in xcm.send call - const createPoolCall = apiAssetHub.tx.assetConversion.createPool( - apiAssetHub.relayAssetId.toU8a(), - apiAssetHub.laosAssetId.toU8a() + ferdieBalance.gte(liquidityAmountDot), + "Ferdie's DOT balance should be greater than the amount to be sent to the pool" ); - const createPoolEncodedCall = apiLaos.createType("DoubleEncodedCall", { - encoded: u8aToHex(createPoolCall.method.toU8a()), - }) as DoubleEncodedCall; - const instruction = buildXcmInstruction({ - api: apiLaos, - calls: [createPoolEncodedCall], - refTime: new BN(2000000000), - proofSize: new BN(7000), - amount: ONE_DOT, - originKind: apiLaos.createType("XcmOriginKind", "SovereignAccount"), - }); + expect( + ferdieXLaosBalance.gte(liquidityAmountLaos), + "Ferdie's $LAOS balance should be greater than the amount to be sent to the pool" + ); + + try { + await apiAssetHub.tx.assetConversion + .addLiquidity( + apiAssetHub.relayAssetId.toU8a(), + apiAssetHub.laosAssetId.toU8a(), + liquidityAmountDot, + liquidityAmountLaos, + liquidityAmountDot.sub(new BN(ONE_DOT.muln(10))), + liquidityAmountLaos.sub(new BN(ONE_LAOS.muln(10))), + ferdie.address + ) + .signAndSend(ferdie); + } catch (error) { + console.log("transaction failed", error); + } + }); + + step("Teleport from Laos to AssetHub", async function () { + const charlie = new Keyring({ type: "sr25519" }).addFromUri("//Charlie"); + const destination = apiLaos.createType("XcmVersionedLocation", { V3: siblingLocation(ASSET_HUB_PARA_ID), - }) as XcmVersionedLocation; + }); + + // We need to use AssetHub api otherwise we get an error as Laos does not use AccountId32 + let accountId = apiAssetHub.createType("AccountId", charlie.address); + const beneficiary = apiLaos.createType("XcmVersionedLocation", { + V3: { + parents: "0", + interior: { + X1: { + AccountId32: { + // network: 'Any', + id: accountId.toHex(), + }, + }, + }, + }, + }); + + const amount = ONE_LAOS.muln(5); + const assets = apiLaos.createType("XcmVersionedAssets", { + V3: [ + { + id: { + Concrete: hereLocation(), + }, + fun: { + Fungible: amount, + }, + }, + ], + }); + const fee_asset_item = "0"; + const weight_limit = "Unlimited"; + + const charlieBalanceBefore = hexToBn( + (await apiAssetHub.query.foreignAssets.account(apiAssetHub.laosAssetId, charlie.address)).toJSON()?.[ + "balance" + ] ?? "0x0" + ); + const alithBalanceBefore = (await apiLaos.query.system.account(alith.address)).data.free; + const call = apiLaos.tx.polkadotXcm.limitedTeleportAssets( + destination, + beneficiary, + assets, + fee_asset_item, + weight_limit + ); - // Send the XCM instruction from Laos to Asset Hub - const laosBalanceBefore = new BN((await apiAssetHub.query.system.account(laosSiblingAccount)).data.free); - const alithBalanceBefore = new BN((await apiLaos.query.system.account(alith.address)).data.free); - const sudoCall = apiLaos.tx.sudo.sudo(apiLaos.tx.polkadotXcm.send(destination, instruction)); try { - await sudoCall.signAndSend(alith); + await call.signAndSend(alith); } catch (error) { console.log("transaction failed", error); } - // Check that pool has been created in Asset Hub + // Check that $LAOS has been sent in Asset Hub const event = await waitForEvent( apiAssetHub, - ({ event }) => apiAssetHub.events.assetConversion.PoolCreated.is(event), + ({ event }) => apiAssetHub.events.foreignAssets.Issued.is(event), WAITING_BLOCKS_FOR_EVENTS ); expect(event).to.not.be.null; - const [creator, poolId] = event.event.data; - expect(creator.toString()).to.equal(laosSiblingAccount); - expect(poolId.toJSON()).to.deep.equal([relayLocation(), siblingLocation(LAOS_PARA_ID)]); + const [assetId, owner, realAmountReceived] = event.event.data; + expect(assetId.toJSON()).to.deep.equal(apiAssetHub.laosAssetId.toJSON()); + expect(owner.toString()).to.equal(charlie.address); + const charlieBalance = hexToBn( + (await apiAssetHub.query.foreignAssets.account(apiAssetHub.laosAssetId, charlie.address)).toJSON()[ + "balance" + ] + ); expect( - (await apiAssetHub.query.assetConversion.pools([apiAssetHub.relayAssetId, apiAssetHub.laosAssetId])) - .isEmpty - ).to.be.false; - - const alithBalance = new BN((await apiLaos.query.system.account(alith.address)).data.free); - expect(alithBalanceBefore.eq(alithBalance), "Alith balance shouldn't change"); - - const laosBalance = new BN((await apiAssetHub.query.system.account(laosSiblingAccount)).data.free); - const decreaseOfLaosBalance = laosBalanceBefore.sub(laosBalance); + charlieBalanceBefore.add(new BN(realAmountReceived.toString())).eq(charlieBalance), + "Charlie's balance should increase by the amount received" + ); + const realAlithBalance = (await apiLaos.query.system.account(alith.address)).data.free; + const alithBalance = alithBalanceBefore.sub(amount); expect( - decreaseOfLaosBalance.eq(ONE_DOT.add(apiAssetHub.consts.assets.assetAccountDeposit)), - "Laos should decrease by the XCM withdrawn amount plus the asset account deposit" + alithBalance.sub(realAlithBalance).lte(ONE_DOT), + "Alith's balance should decrease by the amount teleported, disregarding fees" ); - } else { - debugTeleport("Pool already exists, skipping creation..."); - } - - // Add liquidity to the pool - const ferdie = new Keyring({ type: "sr25519" }).addFromUri("//Ferdie"); - const liquidityAmountLaos = new BN(ONE_LAOS.muln(1000)); - const liquidityAmountDot = new BN(ONE_DOT.muln(1000)); - const ferdieBalance = new BN((await apiAssetHub.query.system.account(ferdie.address)).data.free); - const ferdieXLaosBalance = hexToBn( - (await apiAssetHub.query.foreignAssets.account(apiAssetHub.laosAssetId, ferdie.address)).toJSON()["balance"] - ); - expect( - ferdieBalance.gte(liquidityAmountDot), - "Ferdie's DOT balance should be greater than the amount to be sent to the pool" - ); - expect( - ferdieXLaosBalance.gte(liquidityAmountLaos), - "Ferdie's $LAOS balance should be greater than the amount to be sent to the pool" - ); - - try { - await apiAssetHub.tx.assetConversion - .addLiquidity( - apiAssetHub.relayAssetId.toU8a(), - apiAssetHub.laosAssetId.toU8a(), - liquidityAmountDot, - liquidityAmountLaos, - liquidityAmountDot.sub(new BN(ONE_DOT.muln(10))), - liquidityAmountLaos.sub(new BN(ONE_LAOS.muln(10))), - ferdie.address - ) - .signAndSend(ferdie); - } catch (error) { - console.log("transaction failed", error); - } - }); - - step("Teleport from Laos to AssetHub", async function () { - const charlie = new Keyring({ type: "sr25519" }).addFromUri("//Charlie"); - - const destination = apiLaos.createType("XcmVersionedLocation", { - V3: siblingLocation(ASSET_HUB_PARA_ID), }); - // We need to use AssetHub api otherwise we get an error as Laos does not use AccountId32 - let accountId = apiAssetHub.createType("AccountId", charlie.address); - const beneficiary = apiLaos.createType("XcmVersionedLocation", { - V3: { - parents: "0", - interior: { - X1: { - AccountId32: { - // network: 'Any', - id: accountId.toHex(), - }, - }, - }, - }, - }); + step("Teleport back from AssetHub to Laos", async function () { + const charlie = new Keyring({ type: "sr25519" }).addFromUri("//Charlie"); - const amount = ONE_LAOS.muln(5); - const assets = apiLaos.createType("XcmVersionedAssets", { - V3: [ - { - id: { - Concrete: hereLocation(), - }, - fun: { - Fungible: amount, - }, - }, - ], - }); - const fee_asset_item = "0"; - const weight_limit = "Unlimited"; - - const charlieBalanceBefore = hexToBn( - (await apiAssetHub.query.foreignAssets.account(apiAssetHub.laosAssetId, charlie.address)).toJSON()?.[ - "balance" - ] ?? "0x0" - ); - const alithBalanceBefore = (await apiLaos.query.system.account(alith.address)).data.free; - const call = apiLaos.tx.polkadotXcm.limitedTeleportAssets( - destination, - beneficiary, - assets, - fee_asset_item, - weight_limit - ); - - try { - await call.signAndSend(alith); - } catch (error) { - console.log("transaction failed", error); - } - - // Check that $LAOS has been sent in Asset Hub - const event = await waitForEvent( - apiAssetHub, - ({ event }) => apiAssetHub.events.foreignAssets.Issued.is(event), - WAITING_BLOCKS_FOR_EVENTS - ); - - expect(event).to.not.be.null; - const [assetId, owner, realAmountReceived] = event.event.data; - expect(assetId.toJSON()).to.deep.equal(apiAssetHub.laosAssetId.toJSON()); - expect(owner.toString()).to.equal(charlie.address); - const charlieBalance = hexToBn( - (await apiAssetHub.query.foreignAssets.account(apiAssetHub.laosAssetId, charlie.address)).toJSON()[ - "balance" - ] - ); - expect( - charlieBalanceBefore.add(new BN(realAmountReceived.toString())).eq(charlieBalance), - "Charlie's balance should increase by the amount received" - ); - const realAlithBalance = (await apiLaos.query.system.account(alith.address)).data.free; - const alithBalance = alithBalanceBefore.sub(amount); - expect( - alithBalance.sub(realAlithBalance).lte(ONE_DOT), - "Alith's balance should decrease by the amount teleported, disregarding fees" - ); - }); - - step("Teleport back from AssetHub to Laos", async function () { - const charlie = new Keyring({ type: "sr25519" }).addFromUri("//Charlie"); - - const destination = apiAssetHub.createType("XcmVersionedLocation", { - V3: siblingLocation(LAOS_PARA_ID), - }); + const destination = apiAssetHub.createType("XcmVersionedLocation", { + V3: siblingLocation(LAOS_PARA_ID), + }); - let beneficiaryAddress = "0x0000000000000000000000000000000000000001"; - const beneficiary = apiAssetHub.createType("XcmVersionedLocation", { - V3: { - parents: "0", - interior: { - X1: { - AccountKey20: { - // network: 'Any', - key: beneficiaryAddress, + let beneficiaryAddress = "0x0000000000000000000000000000000000000001"; + const beneficiary = apiAssetHub.createType("XcmVersionedLocation", { + V3: { + parents: "0", + interior: { + X1: { + AccountKey20: { + // network: 'Any', + key: beneficiaryAddress, + }, }, }, }, - }, - }); + }); - const amount = ONE_LAOS.muln(1); - const assets = apiAssetHub.createType("XcmVersionedAssets", { - V3: [ - { - id: { - Concrete: siblingLocation(LAOS_PARA_ID), - }, - fun: { - Fungible: amount, + const amount = ONE_LAOS.muln(1); + const assets = apiAssetHub.createType("XcmVersionedAssets", { + V3: [ + { + id: { + Concrete: siblingLocation(LAOS_PARA_ID), + }, + fun: { + Fungible: amount, + }, }, + ], + }); + const fee_asset_item = "0"; + const weight_limit = "Unlimited"; + + const charlieBalanceBefore = hexToBn( + (await apiAssetHub.query.foreignAssets.account(apiAssetHub.laosAssetId, charlie.address)).toJSON()[ + "balance" + ] + ); + const beneficiaryBalanceBefore = (await apiLaos.query.system.account(beneficiaryAddress)).data.free; + + const call = apiAssetHub.tx.polkadotXcm.limitedTeleportAssets( + destination, + beneficiary, + assets, + fee_asset_item, + weight_limit + ); + try { + await call.signAndSend(charlie); + } catch (error) { + console.log("transaction failed", error); + } + + // Check that $LAOS has been sent back to Laos + const event = await waitForEvent( + apiLaos, + ({ event }) => { + return apiLaos.events.balances.Minted.is(event) && event.data[0].toString() !== CHECKING_ACCOUNT; }, - ], + WAITING_BLOCKS_FOR_EVENTS + ); + + expect(event).to.not.be.null; + const [receiver, realAmountReceived] = event.event.data; + expect(receiver.toString()).to.equal(beneficiaryAddress); + const charlieBalance = hexToBn( + (await apiAssetHub.query.foreignAssets.account(apiAssetHub.laosAssetId, charlie.address)).toJSON()[ + "balance" + ] + ); + expect( + charlieBalanceBefore.sub(amount).eq(charlieBalance), + "Charlie's balance should decrease by the amount teleported" + ); + const beneficiaryBalance = (await apiLaos.query.system.account(beneficiaryAddress)).data.free; + expect( + beneficiaryBalanceBefore.add(new BN(realAmountReceived.toString())).eq(beneficiaryBalance), + "Alith's balance should increase by the amount received in the teleport" + ); }); - const fee_asset_item = "0"; - const weight_limit = "Unlimited"; - - const charlieBalanceBefore = hexToBn( - (await apiAssetHub.query.foreignAssets.account(apiAssetHub.laosAssetId, charlie.address)).toJSON()[ - "balance" - ] - ); - const beneficiaryBalanceBefore = (await apiLaos.query.system.account(beneficiaryAddress)).data.free; - - const call = apiAssetHub.tx.polkadotXcm.limitedTeleportAssets( - destination, - beneficiary, - assets, - fee_asset_item, - weight_limit - ); - try { - await call.signAndSend(charlie); - } catch (error) { - console.log("transaction failed", error); - } - - // Check that $LAOS has been sent back to Laos - const event = await waitForEvent( - apiLaos, - ({ event }) => { - return apiLaos.events.balances.Minted.is(event) && event.data[0].toString() !== CHECKING_ACCOUNT; - }, - WAITING_BLOCKS_FOR_EVENTS - ); - - expect(event).to.not.be.null; - const [receiver, realAmountReceived] = event.event.data; - expect(receiver.toString()).to.equal(beneficiaryAddress); - const charlieBalance = hexToBn( - (await apiAssetHub.query.foreignAssets.account(apiAssetHub.laosAssetId, charlie.address)).toJSON()[ - "balance" - ] - ); - expect( - charlieBalanceBefore.sub(amount).eq(charlieBalance), - "Charlie's balance should decrease by the amount teleported" - ); - const beneficiaryBalance = (await apiLaos.query.system.account(beneficiaryAddress)).data.free; - expect( - beneficiaryBalanceBefore.add(new BN(realAmountReceived.toString())).eq(beneficiaryBalance), - "Alith's balance should increase by the amount received in the teleport" - ); - }); -}, true); + }, + true +); diff --git a/e2e-tests/tests/util.ts b/e2e-tests/tests/util.ts index 30f55ff3..fcb04bf7 100644 --- a/e2e-tests/tests/util.ts +++ b/e2e-tests/tests/util.ts @@ -85,7 +85,6 @@ export function describeWithExistingNode( before(async () => { context.web3 = new Web3(providerLaosNodeUrl || LAOS_NODE_URL); if (openPolkadotConnections) { - // Laos let provider = new HttpProvider(providerLaosNodeUrl || LAOS_NODE_URL); context.networks.laos = await new ApiPromise({ provider }).isReady;