diff --git a/test/helpers/eth-transactions.ts b/test/helpers/eth-transactions.ts index b7874c6b9..d7a8f1150 100644 --- a/test/helpers/eth-transactions.ts +++ b/test/helpers/eth-transactions.ts @@ -2,62 +2,50 @@ import "@moonbeam-network/api-augment"; import { expect } from "@moonwall/cli"; import { EventRecord } from "@polkadot/types/interfaces"; import { - EvmCoreErrorExitError, - EvmCoreErrorExitFatal, - EvmCoreErrorExitReason, - EvmCoreErrorExitRevert, - EvmCoreErrorExitSucceed, + EvmCoreErrorExitError, + EvmCoreErrorExitFatal, + EvmCoreErrorExitReason, + EvmCoreErrorExitRevert, + EvmCoreErrorExitSucceed, } from "@polkadot/types/lookup"; export type Errors = { - Succeed: EvmCoreErrorExitSucceed["type"]; - Error: EvmCoreErrorExitError["type"]; - Revert: EvmCoreErrorExitRevert["type"]; - Fatal: EvmCoreErrorExitFatal["type"]; + Succeed: EvmCoreErrorExitSucceed["type"]; + Error: EvmCoreErrorExitError["type"]; + Revert: EvmCoreErrorExitRevert["type"]; + Fatal: EvmCoreErrorExitFatal["type"]; }; - export function expectEVMResult( - events: EventRecord[], - resultType: Type, - reason?: T[Type] + events: EventRecord[], + resultType: Type, + reason?: T[Type] ) { - expect(events, `Missing events, probably failed execution`).to.be.length.at.least(1); - const ethereumResult = events.find( - ({ event: { section, method } }) => section == "ethereum" && method == "Executed" - )!.event.data[3] as EvmCoreErrorExitReason; + expect(events, `Missing events, probably failed execution`).to.be.length.at.least(1); + const ethereumResult = events.find( + ({ event: { section, method } }) => section == "ethereum" && method == "Executed" + )!.event.data[3] as EvmCoreErrorExitReason; - const foundReason = ethereumResult.isError - ? ethereumResult.asError.type - : ethereumResult.isFatal - ? ethereumResult.asFatal.type - : ethereumResult.isRevert - ? ethereumResult.asRevert.type - : ethereumResult.asSucceed.type; + const foundReason = ethereumResult.isError + ? ethereumResult.asError.type + : ethereumResult.isFatal + ? ethereumResult.asFatal.type + : ethereumResult.isRevert + ? ethereumResult.asRevert.type + : ethereumResult.asSucceed.type; - expect( - ethereumResult.type, - `Invalid EVM Execution - (${ethereumResult.type}.${foundReason})` - ).to.equal(resultType); - if (reason) { - if (ethereumResult.isError) { - expect( - ethereumResult.asError.type, - `Invalid EVM Execution ${ethereumResult.type} Reason` - ).to.equal(reason); - } else if (ethereumResult.isFatal) { - expect( - ethereumResult.asFatal.type, - `Invalid EVM Execution ${ethereumResult.type} Reason` - ).to.equal(reason); - } else if (ethereumResult.isRevert) { - expect( - ethereumResult.asRevert.type, - `Invalid EVM Execution ${ethereumResult.type} Reason` - ).to.equal(reason); - } else - expect( - ethereumResult.asSucceed.type, - `Invalid EVM Execution ${ethereumResult.type} Reason` - ).to.equal(reason); - } + expect(ethereumResult.type, `Invalid EVM Execution - (${ethereumResult.type}.${foundReason})`).to.equal(resultType); + if (reason) { + if (ethereumResult.isError) { + expect(ethereumResult.asError.type, `Invalid EVM Execution ${ethereumResult.type} Reason`).to.equal(reason); + } else if (ethereumResult.isFatal) { + expect(ethereumResult.asFatal.type, `Invalid EVM Execution ${ethereumResult.type} Reason`).to.equal(reason); + } else if (ethereumResult.isRevert) { + expect(ethereumResult.asRevert.type, `Invalid EVM Execution ${ethereumResult.type} Reason`).to.equal( + reason + ); + } else + expect(ethereumResult.asSucceed.type, `Invalid EVM Execution ${ethereumResult.type} Reason`).to.equal( + reason + ); + } } diff --git a/test/helpers/index.ts b/test/helpers/index.ts index 1d1846d1a..3c98932f8 100644 --- a/test/helpers/index.ts +++ b/test/helpers/index.ts @@ -1,2 +1,2 @@ export * from "./eth-transactions"; -export * from "./xcm"; \ No newline at end of file +export * from "./xcm"; diff --git a/test/helpers/xcm.ts b/test/helpers/xcm.ts index b56438867..84059872d 100644 --- a/test/helpers/xcm.ts +++ b/test/helpers/xcm.ts @@ -2,23 +2,23 @@ import { DevModeContext } from "@moonwall/cli"; import { u8aToHex } from "@polkadot/util"; export function descendOriginFromAddress20( - context: DevModeContext, - address: `0x${string}` = "0x0101010101010101010101010101010101010101", - paraId: number = 1 + context: DevModeContext, + address: `0x${string}` = "0x0101010101010101010101010101010101010101", + paraId: number = 1 ) { - const toHash = new Uint8Array([ - ...new TextEncoder().encode("SiblingChain"), - ...context.polkadotJs().createType("Compact", paraId).toU8a(), - ...context - .polkadotJs() - .createType("Compact", "AccountKey20".length + 20) - .toU8a(), - ...new TextEncoder().encode("AccountKey20"), - ...context.polkadotJs().createType("AccountId", address).toU8a(), - ]); + const toHash = new Uint8Array([ + ...new TextEncoder().encode("SiblingChain"), + ...context.polkadotJs().createType("Compact", paraId).toU8a(), + ...context + .polkadotJs() + .createType("Compact", "AccountKey20".length + 20) + .toU8a(), + ...new TextEncoder().encode("AccountKey20"), + ...context.polkadotJs().createType("AccountId", address).toU8a(), + ]); - return { - originAddress: address, - descendOriginAddress: u8aToHex(context.polkadotJs().registry.hash(toHash).slice(0, 20)), - }; + return { + originAddress: address, + descendOriginAddress: u8aToHex(context.polkadotJs().registry.hash(toHash).slice(0, 20)), + }; } diff --git a/test/suites/dev-frontier-template/test-precompiles/test-precompile-xcm-utils.ts b/test/suites/dev-frontier-template/test-precompiles/test-precompile-xcm-utils.ts index 8c3883088..fcf1219b2 100644 --- a/test/suites/dev-frontier-template/test-precompiles/test-precompile-xcm-utils.ts +++ b/test/suites/dev-frontier-template/test-precompiles/test-precompile-xcm-utils.ts @@ -9,431 +9,433 @@ export const CLEAR_ORIGIN_WEIGHT = 1_000_000_000n; const XCM_UTILS_ADDRESS = "0x0000000000000000000000000000000000000803"; describeSuite({ - id: "DF0904", - title: "Precompiles - xcm utils", - foundationMethods: "dev", - testCases: ({ context, it }) => { - it({ - id: "T01", - title: "allows to retrieve parent-based ML account", - test: async function () { - const multilocation: [number, any[]] = [1, []]; - const expectedAddress = u8aToHex(new Uint8Array([...new TextEncoder().encode("Parent")])) - .padEnd(42, "0") - .toLowerCase(); - - expect( - ( - (await context.readContract!({ - contractAddress: XCM_UTILS_ADDRESS, - contractName: "XcmUtils", - functionName: "multilocationToAddress", - args: [multilocation], - })) as any - ).toLowerCase() - ).to.equal(expectedAddress); - }, - }); - - it({ - id: "T02", - title: "allows to retrieve parachain-based ML account", - test: async function () { - const x2_parachain_asset_enum_selector = "0x00"; - const x2_parachain_id = "000007D0"; - const paraId = context.polkadotJs().createType("ParaId", 2000); - - const multilocation: [number, any[]] = [ - 1, - // Parachain(2000) - [x2_parachain_asset_enum_selector + x2_parachain_id], - ]; - - const expectedAddress = u8aToHex( - new Uint8Array([...new TextEncoder().encode("sibl"), ...paraId.toU8a()]) - ).padEnd(42, "0"); - - expect( - ( - (await context.readContract!({ - contractAddress: XCM_UTILS_ADDRESS, - contractName: "XcmUtils", - functionName: "multilocationToAddress", - args: [multilocation], - })) as any - ).toLowerCase() - ).to.equal(expectedAddress); - }, - }); - - it({ - id: "T03", - title: "allows to retrieve generic ML-based derivated account", - test: async function () { - const x2_parachain_asset_enum_selector = "0x00"; - const x2_parachain_id = "00000001"; - - // Junction::AccountKey20 - const account20EnumSelector = "0x03"; - // [0x01; 20] - const account20Address = "0101010101010101010101010101010101010101"; - // NetworkId::Any - const account20NetworkId = "00"; - - const multilocation: [number, any[]] = - // Destination as multilocation - [ - // one parent - 1, - // X2(Parachain(2000), AccountId32(account32Address)) - [ - x2_parachain_asset_enum_selector + x2_parachain_id, - account20EnumSelector + account20Address + account20NetworkId, - ], - ]; - - const { descendOriginAddress } = descendOriginFromAddress20(context); - expect( - ( - (await context.readContract!({ - contractAddress: XCM_UTILS_ADDRESS, - contractName: "XcmUtils", - functionName: "multilocationToAddress", - args: [multilocation], - })) as any - ).toLowerCase() - ).toBe(descendOriginAddress); - }, - }); - - it({ - id: "T04", - title: "allows to retrieve weight of message", - test: async function () { - const message = { - V2: [ - { - ClearOrigin: null, + id: "DF0904", + title: "Precompiles - xcm utils", + foundationMethods: "dev", + testCases: ({ context, it }) => { + it({ + id: "T01", + title: "allows to retrieve parent-based ML account", + test: async function () { + const multilocation: [number, any[]] = [1, []]; + const expectedAddress = u8aToHex(new Uint8Array([...new TextEncoder().encode("Parent")])) + .padEnd(42, "0") + .toLowerCase(); + + expect( + ( + (await context.readContract!({ + contractAddress: XCM_UTILS_ADDRESS, + contractName: "XcmUtils", + functionName: "multilocationToAddress", + args: [multilocation], + })) as any + ).toLowerCase() + ).to.equal(expectedAddress); }, - ], - }; - const xcm = context.polkadotJs().createType("VersionedXcm", message); - - expect( - await context.readContract!({ - contractAddress: XCM_UTILS_ADDRESS, - contractName: "XcmUtils", - functionName: "weightMessage", - args: [xcm.toHex()], - }) - ).to.equal(CLEAR_ORIGIN_WEIGHT); - }, - }); - - it({ - id: "T05", - title: "allows to retrieve units per second for an asset", - test: async function () { - // Junction::PalletInstance(3) - const x2_pallet_instance_enum_selector = "0x04"; - const x2_instance = "0A"; - - // This represents X1(PalletInstance(3))) - - // This multilocation represents our native token - const asset = [ - // zero parents - 0, - // X1(PalletInstance) - // PalletInstance: Selector (04) + palconst instance 1 byte (03) - [x2_pallet_instance_enum_selector + x2_instance], - ]; - - const baseWeight = extractWeight(context.polkadotJs().consts.system.blockWeights.perClass.normal.baseExtrinsic).toBigInt(); - const expectedUnitsPerSecond = 1_000_000_000_000n * 1_000n / baseWeight * 1_000n; - - expect( - await context.readContract!({ - contractAddress: XCM_UTILS_ADDRESS, - contractName: "XcmUtils", - functionName: "getUnitsPerSecond", - args: [asset], - }) - ).to.equal(expectedUnitsPerSecond); - }, - }); - - it({ - id: "T06", - title: "allows to execute a custom xcm message", - test: async function () { - const random = generateKeyringPair(); - - const transferCall = context.polkadotJs().tx.balances.transfer(random.address, 1n * GLMR); - const transferCallEncoded = transferCall?.method.toHex(); - - const xcmMessage = { - V2: [ - { - Transact: { - originType: "SovereignAccount", - requireWeightAtMost: 525_000_000n + 100_000_000n, // 21_000 gas limit - call: { - encoded: transferCallEncoded, - }, - }, + }); + + it({ + id: "T02", + title: "allows to retrieve parachain-based ML account", + test: async function () { + const x2_parachain_asset_enum_selector = "0x00"; + const x2_parachain_id = "000007D0"; + const paraId = context.polkadotJs().createType("ParaId", 2000); + + const multilocation: [number, any[]] = [ + 1, + // Parachain(2000) + [x2_parachain_asset_enum_selector + x2_parachain_id], + ]; + + const expectedAddress = u8aToHex( + new Uint8Array([...new TextEncoder().encode("sibl"), ...paraId.toU8a()]) + ).padEnd(42, "0"); + + expect( + ( + (await context.readContract!({ + contractAddress: XCM_UTILS_ADDRESS, + contractName: "XcmUtils", + functionName: "multilocationToAddress", + args: [multilocation], + })) as any + ).toLowerCase() + ).to.equal(expectedAddress); }, - ], - }; - - const receivedMessage: StagingXcmVersionedXcm = context - .polkadotJs() - .createType("StagingXcmVersionedXcm", xcmMessage) as any; - - const rawTxn = await context.writeContract!({ - contractAddress: XCM_UTILS_ADDRESS, - contractName: "XcmUtils", - functionName: "xcmExecute", - args: [receivedMessage.toHex(), 2_000_000_000n], - rawTxOnly: true, }); - const { result } = await context.createBlock(rawTxn); - expectEVMResult(result!.events, "Succeed"); - - const testAccountBalance = ( - await context.polkadotJs().query.system.account(random.address) - ).data.free.toBigInt(); - - expect(testAccountBalance).to.eq(1n * GLMR); - }, - }); - - // it({ - // id: "T07", - // title: "allows to execute a custom xcm evm to evm, but reentrancy forbids", - // test: async function () { - // const random = generateKeyringPair(); - - // const ethTx = { - // V1: { - // gas_limit: 21000, - // fee_payment: { - // Auto: { - // Low: null, - // }, - // }, - // action: { - // Call: random.address, - // }, - // value: 1n * GLMR, - // input: [], - // access_list: null, - // }, - // }; - // const transferCall = context.polkadotJs().tx.ethereumXcm.transact(ethTx as any); - // const transferCallEncoded = transferCall?.method.toHex(); - - // const xcmMessage = { - // V2: [ - // { - // Transact: { - // originType: "SovereignAccount", - // requireWeightAtMost: 525_000_000n + 25_000_000n, // 21_000 gas limit - // call: { - // encoded: transferCallEncoded, - // }, - // }, - // }, - // ], - // }; - - // const receivedMessage: StagingXcmVersionedXcm = context - // .polkadotJs() - // .createType("StagingXcmVersionedXcm", xcmMessage); - - // const rawTxn = await context.writeContract!({ - // contractAddress: XCM_UTILS_ADDRESS, - // contractName: "XcmUtils", - // functionName: "xcmExecute", - // args: [receivedMessage.toHex(), 4_000_000_000], - // rawTxOnly: true, - // gas: 5_000_000n, - // }); - - // const { result } = await context.createBlock(rawTxn); - // expectEVMResult(result!.events, "Succeed"); - - // // Tokens transferred - // const testAccountBalance = ( - // await context.polkadotJs().query.system.account(random.address) - // ).data.free.toBigInt(); - - // expect(testAccountBalance, "Transfer went through, possible EVM re-entrancy").to.eq(0n); - // }, - // }); - - it({ - id: "T08", - title: "does not allow to self-send a custom xcm message", - test: async function () { - const ownParaId = (await context.polkadotJs().query.parachainInfo.parachainId()) as any; - const x1_parachain_asset_enum_selector = "0x00"; - const x1_parachain_id = ownParaId.toHex().slice(2); - - // Sending it here - // { parents:0, Here} - const destHere: [number, any[]] = [ - // one parents - 0, - // Here - [], - ]; - - // Sending it with the representation of the para as seen by the relay - // { parents:0, parachain(0)} - const destParaRelayView: [number, any[]] = [ - // one parents - 0, - // Parachain(0) - [x1_parachain_asset_enum_selector + x1_parachain_id], - ]; - - // Sending it with the representation of the para as seen by other paras - // { parents:1, parachain(0)} - const destParaOtherParaView: [number, any[]] = [ - // one parents - 1, - // Parachain(0) - [x1_parachain_asset_enum_selector + x1_parachain_id], - ]; - - const xcmMessage = { - V2: [ - { - ClearOrigin: null, + it({ + id: "T03", + title: "allows to retrieve generic ML-based derivated account", + test: async function () { + const x2_parachain_asset_enum_selector = "0x00"; + const x2_parachain_id = "00000001"; + + // Junction::AccountKey20 + const account20EnumSelector = "0x03"; + // [0x01; 20] + const account20Address = "0101010101010101010101010101010101010101"; + // NetworkId::Any + const account20NetworkId = "00"; + + const multilocation: [number, any[]] = + // Destination as multilocation + [ + // one parent + 1, + // X2(Parachain(2000), AccountId32(account32Address)) + [ + x2_parachain_asset_enum_selector + x2_parachain_id, + account20EnumSelector + account20Address + account20NetworkId, + ], + ]; + + const { descendOriginAddress } = descendOriginFromAddress20(context); + expect( + ( + (await context.readContract!({ + contractAddress: XCM_UTILS_ADDRESS, + contractName: "XcmUtils", + functionName: "multilocationToAddress", + args: [multilocation], + })) as any + ).toLowerCase() + ).toBe(descendOriginAddress); }, - ], - }; - - const sentMessage: StagingXcmVersionedXcm = context - .polkadotJs() - .createType("StagingXcmVersionedXcm", xcmMessage) as any; - - // Try sending it with local view - const localRawTxn = await context.writeContract!({ - contractAddress: XCM_UTILS_ADDRESS, - contractName: "XcmUtils", - functionName: "xcmSend", - args: [destHere, sentMessage.toHex()], - rawTxOnly: true, - gas: 1_000_000n, }); - const { result: localResult } = await context.createBlock(localRawTxn); - expectEVMResult(localResult!.events, "Revert"); - expect( - async () => - await context.writeContract!({ - contractAddress: XCM_UTILS_ADDRESS, - contractName: "XcmUtils", - functionName: "xcmSend", - args: [destHere, sentMessage.toHex()], - }) - ).rejects.toThrowError( - "Dispatched call failed with error: Module(ModuleError " + - '{ index: 73, error: [0, 0, 0, 0], message: Some("Unreachable") })' - ); - - const paraRawTxn = await context.writeContract!({ - contractAddress: XCM_UTILS_ADDRESS, - contractName: "XcmUtils", - functionName: "xcmSend", - args: [destParaRelayView, sentMessage.toHex()], - rawTxOnly: true, - gas: 1_000_000n, + it({ + id: "T04", + title: "allows to retrieve weight of message", + test: async function () { + const message = { + V2: [ + { + ClearOrigin: null, + }, + ], + }; + const xcm = context.polkadotJs().createType("VersionedXcm", message); + + expect( + await context.readContract!({ + contractAddress: XCM_UTILS_ADDRESS, + contractName: "XcmUtils", + functionName: "weightMessage", + args: [xcm.toHex()], + }) + ).to.equal(CLEAR_ORIGIN_WEIGHT); + }, }); - const { result: paraResult } = await context.createBlock(paraRawTxn); - - expectEVMResult(paraResult!.events, "Revert"); - expect( - async () => - await context.writeContract!({ - contractAddress: XCM_UTILS_ADDRESS, - contractName: "XcmUtils", - functionName: "xcmSend", - args: [destParaRelayView, sentMessage.toHex()], - }) - ).rejects.toThrowError( - "Dispatched call failed with error: Module(ModuleError " + - '{ index: 73, error: [0, 0, 0, 0], message: Some("Unreachable") })' - ); - - const paraRawTxn2 = await context.writeContract!({ - contractAddress: XCM_UTILS_ADDRESS, - contractName: "XcmUtils", - functionName: "xcmSend", - args: [destParaOtherParaView, sentMessage.toHex()], - rawTxOnly: true, - gas: 1_000_000n, + it({ + id: "T05", + title: "allows to retrieve units per second for an asset", + test: async function () { + // Junction::PalletInstance(3) + const x2_pallet_instance_enum_selector = "0x04"; + const x2_instance = "0A"; + + // This represents X1(PalletInstance(3))) + + // This multilocation represents our native token + const asset = [ + // zero parents + 0, + // X1(PalletInstance) + // PalletInstance: Selector (04) + palconst instance 1 byte (03) + [x2_pallet_instance_enum_selector + x2_instance], + ]; + + const baseWeight = extractWeight( + context.polkadotJs().consts.system.blockWeights.perClass.normal.baseExtrinsic + ).toBigInt(); + const expectedUnitsPerSecond = ((1_000_000_000_000n * 1_000n) / baseWeight) * 1_000n; + + expect( + await context.readContract!({ + contractAddress: XCM_UTILS_ADDRESS, + contractName: "XcmUtils", + functionName: "getUnitsPerSecond", + args: [asset], + }) + ).to.equal(expectedUnitsPerSecond); + }, }); - const { result: paraResult2 } = await context.createBlock(paraRawTxn2); - - expectEVMResult(paraResult2!.events, "Revert"); - expect( - async () => - await context.writeContract!({ - contractAddress: XCM_UTILS_ADDRESS, - contractName: "XcmUtils", - functionName: "xcmSend", - args: [destParaOtherParaView, sentMessage.toHex()], - }) - ).rejects.toThrowError( - "Dispatched call failed with error: Module(ModuleError " + - '{ index: 73, error: [1, 0, 0, 0], message: Some("SendFailure") })' - ); - }, - }); - - it({ - id: "T09", - title: "allows to send a custom xcm message", - test: async function () { - // Sending it to the relay - // { parents:1, Here} - const dest = [ - // one parents - 1, - // Here - [], - ]; - - const xcmMessage = { - V2: [ - { - ClearOrigin: null, + it({ + id: "T06", + title: "allows to execute a custom xcm message", + test: async function () { + const random = generateKeyringPair(); + + const transferCall = context.polkadotJs().tx.balances.transfer(random.address, 1n * GLMR); + const transferCallEncoded = transferCall?.method.toHex(); + + const xcmMessage = { + V2: [ + { + Transact: { + originType: "SovereignAccount", + requireWeightAtMost: 525_000_000n + 100_000_000n, // 21_000 gas limit + call: { + encoded: transferCallEncoded, + }, + }, + }, + ], + }; + + const receivedMessage: StagingXcmVersionedXcm = context + .polkadotJs() + .createType("StagingXcmVersionedXcm", xcmMessage) as any; + + const rawTxn = await context.writeContract!({ + contractAddress: XCM_UTILS_ADDRESS, + contractName: "XcmUtils", + functionName: "xcmExecute", + args: [receivedMessage.toHex(), 2_000_000_000n], + rawTxOnly: true, + }); + + const { result } = await context.createBlock(rawTxn); + expectEVMResult(result!.events, "Succeed"); + + const testAccountBalance = ( + await context.polkadotJs().query.system.account(random.address) + ).data.free.toBigInt(); + + expect(testAccountBalance).to.eq(1n * GLMR); }, - ], - }; - - const sentMessage: StagingXcmVersionedXcm = context - .polkadotJs() - .createType("StagingXcmVersionedXcm", xcmMessage); - - const rawTxn = await context.writeContract!({ - contractAddress: XCM_UTILS_ADDRESS, - contractName: "XcmUtils", - functionName: "xcmSend", - args: [dest, sentMessage.toHex()], - rawTxOnly: true, - gas: 1_000_000n, }); - const { result } = await context.createBlock(rawTxn); - expectEVMResult(result!.events, "Succeed"); - }, - }); - }, + // it({ + // id: "T07", + // title: "allows to execute a custom xcm evm to evm, but reentrancy forbids", + // test: async function () { + // const random = generateKeyringPair(); + + // const ethTx = { + // V1: { + // gas_limit: 21000, + // fee_payment: { + // Auto: { + // Low: null, + // }, + // }, + // action: { + // Call: random.address, + // }, + // value: 1n * GLMR, + // input: [], + // access_list: null, + // }, + // }; + // const transferCall = context.polkadotJs().tx.ethereumXcm.transact(ethTx as any); + // const transferCallEncoded = transferCall?.method.toHex(); + + // const xcmMessage = { + // V2: [ + // { + // Transact: { + // originType: "SovereignAccount", + // requireWeightAtMost: 525_000_000n + 25_000_000n, // 21_000 gas limit + // call: { + // encoded: transferCallEncoded, + // }, + // }, + // }, + // ], + // }; + + // const receivedMessage: StagingXcmVersionedXcm = context + // .polkadotJs() + // .createType("StagingXcmVersionedXcm", xcmMessage); + + // const rawTxn = await context.writeContract!({ + // contractAddress: XCM_UTILS_ADDRESS, + // contractName: "XcmUtils", + // functionName: "xcmExecute", + // args: [receivedMessage.toHex(), 4_000_000_000], + // rawTxOnly: true, + // gas: 5_000_000n, + // }); + + // const { result } = await context.createBlock(rawTxn); + // expectEVMResult(result!.events, "Succeed"); + + // // Tokens transferred + // const testAccountBalance = ( + // await context.polkadotJs().query.system.account(random.address) + // ).data.free.toBigInt(); + + // expect(testAccountBalance, "Transfer went through, possible EVM re-entrancy").to.eq(0n); + // }, + // }); + + it({ + id: "T08", + title: "does not allow to self-send a custom xcm message", + test: async function () { + const ownParaId = (await context.polkadotJs().query.parachainInfo.parachainId()) as any; + const x1_parachain_asset_enum_selector = "0x00"; + const x1_parachain_id = ownParaId.toHex().slice(2); + + // Sending it here + // { parents:0, Here} + const destHere: [number, any[]] = [ + // one parents + 0, + // Here + [], + ]; + + // Sending it with the representation of the para as seen by the relay + // { parents:0, parachain(0)} + const destParaRelayView: [number, any[]] = [ + // one parents + 0, + // Parachain(0) + [x1_parachain_asset_enum_selector + x1_parachain_id], + ]; + + // Sending it with the representation of the para as seen by other paras + // { parents:1, parachain(0)} + const destParaOtherParaView: [number, any[]] = [ + // one parents + 1, + // Parachain(0) + [x1_parachain_asset_enum_selector + x1_parachain_id], + ]; + + const xcmMessage = { + V2: [ + { + ClearOrigin: null, + }, + ], + }; + + const sentMessage: StagingXcmVersionedXcm = context + .polkadotJs() + .createType("StagingXcmVersionedXcm", xcmMessage) as any; + + // Try sending it with local view + const localRawTxn = await context.writeContract!({ + contractAddress: XCM_UTILS_ADDRESS, + contractName: "XcmUtils", + functionName: "xcmSend", + args: [destHere, sentMessage.toHex()], + rawTxOnly: true, + gas: 1_000_000n, + }); + + const { result: localResult } = await context.createBlock(localRawTxn); + expectEVMResult(localResult!.events, "Revert"); + expect( + async () => + await context.writeContract!({ + contractAddress: XCM_UTILS_ADDRESS, + contractName: "XcmUtils", + functionName: "xcmSend", + args: [destHere, sentMessage.toHex()], + }) + ).rejects.toThrowError( + "Dispatched call failed with error: Module(ModuleError " + + '{ index: 73, error: [0, 0, 0, 0], message: Some("Unreachable") })' + ); + + const paraRawTxn = await context.writeContract!({ + contractAddress: XCM_UTILS_ADDRESS, + contractName: "XcmUtils", + functionName: "xcmSend", + args: [destParaRelayView, sentMessage.toHex()], + rawTxOnly: true, + gas: 1_000_000n, + }); + + const { result: paraResult } = await context.createBlock(paraRawTxn); + + expectEVMResult(paraResult!.events, "Revert"); + expect( + async () => + await context.writeContract!({ + contractAddress: XCM_UTILS_ADDRESS, + contractName: "XcmUtils", + functionName: "xcmSend", + args: [destParaRelayView, sentMessage.toHex()], + }) + ).rejects.toThrowError( + "Dispatched call failed with error: Module(ModuleError " + + '{ index: 73, error: [0, 0, 0, 0], message: Some("Unreachable") })' + ); + + const paraRawTxn2 = await context.writeContract!({ + contractAddress: XCM_UTILS_ADDRESS, + contractName: "XcmUtils", + functionName: "xcmSend", + args: [destParaOtherParaView, sentMessage.toHex()], + rawTxOnly: true, + gas: 1_000_000n, + }); + + const { result: paraResult2 } = await context.createBlock(paraRawTxn2); + + expectEVMResult(paraResult2!.events, "Revert"); + expect( + async () => + await context.writeContract!({ + contractAddress: XCM_UTILS_ADDRESS, + contractName: "XcmUtils", + functionName: "xcmSend", + args: [destParaOtherParaView, sentMessage.toHex()], + }) + ).rejects.toThrowError( + "Dispatched call failed with error: Module(ModuleError " + + '{ index: 73, error: [1, 0, 0, 0], message: Some("SendFailure") })' + ); + }, + }); + + it({ + id: "T09", + title: "allows to send a custom xcm message", + test: async function () { + // Sending it to the relay + // { parents:1, Here} + const dest = [ + // one parents + 1, + // Here + [], + ]; + + const xcmMessage = { + V2: [ + { + ClearOrigin: null, + }, + ], + }; + + const sentMessage: StagingXcmVersionedXcm = context + .polkadotJs() + .createType("StagingXcmVersionedXcm", xcmMessage); + + const rawTxn = await context.writeContract!({ + contractAddress: XCM_UTILS_ADDRESS, + contractName: "XcmUtils", + functionName: "xcmSend", + args: [dest, sentMessage.toHex()], + rawTxOnly: true, + gas: 1_000_000n, + }); + + const { result } = await context.createBlock(rawTxn); + expectEVMResult(result!.events, "Succeed"); + }, + }); + }, });