Skip to content

Commit

Permalink
Add XCM Transactor precompile V3 to Moonriver and Moonbeam (#2513)
Browse files Browse the repository at this point in the history
* xcm precompile v3 in moonbeam and moonriver

* add typescript tests for xcm transactor v3
  • Loading branch information
Agusrodri authored Oct 10, 2023
1 parent 7fee3fd commit e173e26
Show file tree
Hide file tree
Showing 11 changed files with 357 additions and 13 deletions.
7 changes: 3 additions & 4 deletions runtime/moonbeam/src/precompiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use pallet_evm_precompile_relay_encoder::RelayEncoderPrecompile;
use pallet_evm_precompile_sha3fips::Sha3FIPS256;
use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256};
use pallet_evm_precompile_xcm_transactor::{
v1::XcmTransactorPrecompileV1, v2::XcmTransactorPrecompileV2,
v1::XcmTransactorPrecompileV1, v2::XcmTransactorPrecompileV2, v3::XcmTransactorPrecompileV3,
};
use pallet_evm_precompile_xcm_utils::XcmUtilsPrecompile;
use pallet_evm_precompile_xtokens::XtokensPrecompile;
Expand Down Expand Up @@ -234,12 +234,11 @@ type MoonbeamPrecompilesAt<R> = (
(CallableByContract, CallableByPrecompile),
>,
PrecompileAt<AddressU64<2070>, GmpPrecompile<R>, SubcallWithMaxNesting<0>>,
// Address 2071 is reserved for XCM Transactor Precompile V3
/* PrecompileAt<
PrecompileAt<
AddressU64<2071>,
XcmTransactorPrecompileV3<R>,
(CallableByContract, CallableByPrecompile),
>, */
>,
);

/// The PrecompileSet installed in the Moonbeam runtime.
Expand Down
2 changes: 1 addition & 1 deletion runtime/moonbeam/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2519,7 +2519,7 @@ fn precompile_existence() {
let precompile_addresses: std::collections::BTreeSet<_> = vec![
1, 2, 3, 4, 5, 6, 7, 8, 9, 1024, 1025, 1026, 2048, 2049, 2050, 2051, 2052, 2053, 2054,
2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068,
2069, 2070,
2069, 2070, 2071,
]
.into_iter()
.map(H160::from_low_u64_be)
Expand Down
7 changes: 3 additions & 4 deletions runtime/moonriver/src/precompiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use pallet_evm_precompile_relay_encoder::RelayEncoderPrecompile;
use pallet_evm_precompile_sha3fips::Sha3FIPS256;
use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256};
use pallet_evm_precompile_xcm_transactor::{
v1::XcmTransactorPrecompileV1, v2::XcmTransactorPrecompileV2,
v1::XcmTransactorPrecompileV1, v2::XcmTransactorPrecompileV2, v3::XcmTransactorPrecompileV3,
};
use pallet_evm_precompile_xcm_utils::XcmUtilsPrecompile;
use pallet_evm_precompile_xtokens::XtokensPrecompile;
Expand Down Expand Up @@ -234,12 +234,11 @@ type MoonriverPrecompilesAt<R> = (
(CallableByContract, CallableByPrecompile),
>,
PrecompileAt<AddressU64<2070>, GmpPrecompile<R>, SubcallWithMaxNesting<0>>,
// Address 2071 is reserved for XCM Transactor Precompile V3
/* PrecompileAt<
PrecompileAt<
AddressU64<2071>,
XcmTransactorPrecompileV3<R>,
(CallableByContract, CallableByPrecompile),
>, */
>,
);

/// The PrecompileSet installed in the Moonriver runtime.
Expand Down
2 changes: 1 addition & 1 deletion runtime/moonriver/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2425,7 +2425,7 @@ fn precompile_existence() {
let precompile_addresses: std::collections::BTreeSet<_> = vec![
1, 2, 3, 4, 5, 6, 7, 8, 9, 1024, 1025, 1026, 2048, 2049, 2050, 2051, 2052, 2053, 2054,
2055, 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068,
2069, 2070,
2069, 2070, 2071,
]
.into_iter()
.map(H160::from_low_u64_be)
Expand Down
2 changes: 1 addition & 1 deletion test/helpers/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const ALITH_GENESIS_TRANSFERABLE_BALANCE =
: ALITH_GENESIS_FREE_BALANCE;

// Precompiles

export const PRECOMPILE_XCM_TRANSACTOR_V3_ADDRESS = "0x0000000000000000000000000000000000000817";
export const PRECOMPILE_IDENTITY_ADDRESS = "0x0000000000000000000000000000000000000818";

// Fees
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import "@moonbeam-network/api-augment";
import { beforeAll, describeSuite } from "@moonwall/cli";
import { ALITH_PRIVATE_KEY } from "@moonwall/util";
import { fromBytes } from "viem";
import { verifyLatestBlockFees } from "../../../helpers/block.js";
import { expectEVMResult } from "../../../helpers/eth-transactions.js";
import { RELAY_SOURCE_LOCATION, relayAssetMetadata } from "../../../helpers/assets.js";
import { registerForeignAsset, registerXcmTransactorAndContract } from "../../../helpers/xcm.js";
import { PRECOMPILE_XCM_TRANSACTOR_V3_ADDRESS } from "../../../helpers/constants.js";

const ADDRESS_RELAY_ASSETS = "0xffffffff1fcacbd218edc0eba20fc2308c778080";

describeSuite({
id: "D2579",
title: "Precompiles - xcm transactor V3",
foundationMethods: "dev",
testCases: ({ context, it, log }) => {
beforeAll(async () => {
await registerForeignAsset(context, RELAY_SOURCE_LOCATION, relayAssetMetadata as any);
await registerXcmTransactorAndContract(context);
});

it({
id: "T01",
title: "allows to transact signed with custom weights V2 and fee",
test: async function () {
const dest: [number, {}[]] = [1, []];
const asset = ADDRESS_RELAY_ASSETS;
const transact_call = fromBytes(new Uint8Array([0x01]), "hex");
const transactWeight = { refTime: 1000, proofSize: 1000 };
const overallWeight = { refTime: 2000, proofSize: 2000 };
const feeAmount = 1000;
const refund = true;

const rawTx = await context.writeContract!({
contractAddress: PRECOMPILE_XCM_TRANSACTOR_V3_ADDRESS,
contractName: "XcmTransactorV3",
functionName: "transactThroughSigned",
args: [dest, asset, transactWeight, transact_call, feeAmount, overallWeight, refund],
gas: 500_000n,
rawTxOnly: true,
privateKey: ALITH_PRIVATE_KEY,
});

const { result } = await context.createBlock(rawTx);
expectEVMResult(result!.events, "Succeed");

// 1000 fee for the relay is paid with relay assets
await verifyLatestBlockFees(context);
},
});
},
});
123 changes: 123 additions & 0 deletions test/suites/dev/test-precompile/test-precompile-xcm-transactor11.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import "@moonbeam-network/api-augment";
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
import { ALITH_ADDRESS, ALITH_PRIVATE_KEY, alith } from "@moonwall/util";
import { PalletAssetsAssetAccount, PalletAssetsAssetDetails } from "@polkadot/types/lookup";
import { fromBytes } from "viem";
import { mockAssetBalance } from "../../../helpers/assets.js";
import { verifyLatestBlockFees } from "../../../helpers/block.js";
import { expectEVMResult } from "../../../helpers/eth-transactions.js";
import { registerXcmTransactorDerivativeIndex } from "../../../helpers/xcm.js";
import { PRECOMPILE_XCM_TRANSACTOR_V3_ADDRESS } from "../../../helpers/constants.js";

describeSuite({
id: "D2580",
title: "Precompiles - xcm transactor V3",
foundationMethods: "dev",
testCases: ({ context, it, log }) => {
beforeAll(async () => {
await registerXcmTransactorDerivativeIndex(context);
expect(
await context.readContract!({
contractAddress: PRECOMPILE_XCM_TRANSACTOR_V3_ADDRESS,
contractName: "XcmTransactorV3",
functionName: "indexToAccount",
args: [0],
})
).toBe(ALITH_ADDRESS);
});

it({
id: "T01",
title: "allows to transact through derivative multiloc weights v2 and refund",
test: async function () {
// We need to mint units with sudo.setStorage, as we dont have xcm mocker yet
// And we need relay tokens for issuing a transaction to be executed in the relay
const balance = context.polkadotJs().createType("Balance", 100000000000000);
const assetBalance: PalletAssetsAssetAccount = context
.polkadotJs()
.createType("PalletAssetsAssetAccount", {
balance: balance,
});

const assetId = context
.polkadotJs()
.createType("u128", 42259045809535163221576417993425387648n);
const assetDetails: PalletAssetsAssetDetails = context
.polkadotJs()
.createType("PalletAssetsAssetDetails", {
supply: balance,
});

await mockAssetBalance(
context,
assetBalance,
assetDetails,
alith,
assetId,
ALITH_ADDRESS,
true
);

const beforeAssetBalance = await context
.polkadotJs()
.query.assets.account(assetId.toU8a(), ALITH_ADDRESS);
const beforeAssetDetails = await context.polkadotJs().query.assets.asset(assetId.toU8a());
expect(
beforeAssetBalance.unwrap().balance.toBigInt(),
"supply and balance should be the same"
).to.equal(100000000000000n);
expect(
beforeAssetDetails.unwrap().supply.toBigInt(),
"supply and balance should be the same"
).to.equal(100000000000000n);

const transactor = 0;
const index = 0;
const asset: [number, {}[]] = [1, []];
const transact_call = fromBytes(new Uint8Array([0x01]), "hex");
const transactWeight = { refTime: 1000, proofSize: 1000 };
const overallWeight = { refTime: 2000, proofSize: 2000 };
const feeAmount = 1000;
const refund = true;

const rawTx = await context.writeContract!({
contractAddress: PRECOMPILE_XCM_TRANSACTOR_V3_ADDRESS,
contractName: "XcmTransactorV3",
functionName: "transactThroughDerivativeMultilocation",
args: [
transactor,
index,
asset,
transactWeight,
transact_call,
feeAmount,
overallWeight,
refund,
],
gas: 500_000n,
rawTxOnly: true,
privateKey: ALITH_PRIVATE_KEY,
});

const { result } = await context.createBlock(rawTx);
expectEVMResult(result!.events, "Succeed");

// We have used 1000 units to pay for the fees in the relay, so balance and supply should
// have changed
const afterAssetBalance = await context
.polkadotJs()
.query.assets.account(assetId.toU8a(), ALITH_ADDRESS);

const expectedBalance = 100000000000000n - 1000n;
expect(afterAssetBalance.unwrap().balance.toBigInt()).to.equal(expectedBalance);

const AfterAssetDetails = await context.polkadotJs().query.assets.asset(assetId.toU8a());

expect(AfterAssetDetails.unwrap().supply.toBigInt()).to.equal(expectedBalance);

// 1000 fee for the relay is paid with relay assets
await verifyLatestBlockFees(context);
},
});
},
});
121 changes: 121 additions & 0 deletions test/suites/dev/test-precompile/test-precompile-xcm-transactor12.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import "@moonbeam-network/api-augment";
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
import { ALITH_ADDRESS, alith, ALITH_PRIVATE_KEY } from "@moonwall/util";
import { PalletAssetsAssetAccount, PalletAssetsAssetDetails } from "@polkadot/types/lookup";
import { fromBytes } from "viem";
import { mockAssetBalance } from "../../../helpers/assets.js";
import { verifyLatestBlockFees } from "../../../helpers/block.js";
import { expectEVMResult } from "../../../helpers/eth-transactions.js";
import { registerXcmTransactorDerivativeIndex } from "../../../helpers/xcm.js";
import { PRECOMPILE_XCM_TRANSACTOR_V3_ADDRESS } from "../../../helpers/constants.js";

const ADDRESS_RELAY_ASSETS = "0xffffffff1fcacbd218edc0eba20fc2308c778080";

describeSuite({
id: "D2581",
title: "Precompiles - xcm transactor V3",
foundationMethods: "dev",
testCases: ({ context, it, log }) => {
beforeAll(async () => {
await registerXcmTransactorDerivativeIndex(context);
expect(
await context.readContract!({
contractAddress: PRECOMPILE_XCM_TRANSACTOR_V3_ADDRESS,
contractName: "XcmTransactorV3",
functionName: "indexToAccount",
args: [0],
})
).toBe(ALITH_ADDRESS);
});

it({
id: "T01",
title: "allows to issue transfer xcm transactor with currency Id - weights v2 - refund",
test: async function () {
// We need to mint units with sudo.setStorage, as we dont have xcm mocker yet
// And we need relay tokens for issuing a transaction to be executed in the relay
const balance = context.polkadotJs().createType("Balance", 100000000000000);
const assetBalance: PalletAssetsAssetAccount = context
.polkadotJs()
.createType("PalletAssetsAssetAccount", {
balance: balance,
});

const assetId = context
.polkadotJs()
.createType("u128", 42259045809535163221576417993425387648n);
const assetDetails: PalletAssetsAssetDetails = context
.polkadotJs()
.createType("PalletAssetsAssetDetails", {
supply: balance,
});

await mockAssetBalance(
context,
assetBalance,
assetDetails,
alith,
assetId,
ALITH_ADDRESS,
true
);

const beforeAssetBalance = await context
.polkadotJs()
.query.assets.account(assetId.toU8a(), ALITH_ADDRESS);

const beforeAssetDetails = await context.polkadotJs().query.assets.asset(assetId.toU8a());

expect(beforeAssetBalance.unwrap().balance.toBigInt()).to.equal(100000000000000n);
expect(beforeAssetDetails.unwrap().supply.toBigInt()).to.equal(100000000000000n);

const transactor = 0;
const index = 0;
const asset = ADDRESS_RELAY_ASSETS;
const transact_call = fromBytes(new Uint8Array([0x01]), "hex");
const transactWeight = { refTime: 1000, proofSize: 1000 };
const overallWeight = { refTime: 2000, proofSize: 2000 };
const feeAmount = 1000;
const refund = true;

const rawTx = await context.writeContract!({
contractAddress: PRECOMPILE_XCM_TRANSACTOR_V3_ADDRESS,
contractName: "XcmTransactorV3",
functionName: "transactThroughDerivative",
args: [
transactor,
index,
asset,
transactWeight,
transact_call,
feeAmount,
overallWeight,
refund,
],
gas: 500_000n,
rawTxOnly: true,
privateKey: ALITH_PRIVATE_KEY,
});

const result = await context.createBlock(rawTx);
expectEVMResult(result.result!.events, "Succeed");

// We have used 1000 units to pay for the fees in the relay (plus 1 transact_extra_weight),
// so balance and supply should have changed
const afterAssetBalance = await context
.polkadotJs()
.query.assets.account(assetId.toU8a(), ALITH_ADDRESS);

const expectedBalance = 100000000000000n - 1000n;
expect(afterAssetBalance.unwrap().balance.toBigInt()).to.equal(expectedBalance);

const AfterAssetDetails = await context.polkadotJs().query.assets.asset(assetId.toU8a());

expect(AfterAssetDetails.unwrap().supply.toBigInt()).to.equal(expectedBalance);

// 1000 fee for the relay is paid with relay assets
await verifyLatestBlockFees(context);
},
});
},
});
Loading

0 comments on commit e173e26

Please sign in to comment.