From ba148c72ef3d2d7e921d32ec39ab0f3eec4fad6c Mon Sep 17 00:00:00 2001 From: Agusrodri Date: Sat, 5 Oct 2024 14:52:31 -0700 Subject: [PATCH] add pallet-xcm precompile to MB and MR with TS tests --- Cargo.lock | 35 +-- Cargo.toml | 30 +-- runtime/moonbeam/Cargo.toml | 2 + runtime/moonbeam/src/precompiles.rs | 35 ++- runtime/moonriver/Cargo.toml | 2 + runtime/moonriver/src/precompiles.rs | 32 ++- test/contracts/src/XcmInterface.sol | 119 ++++++++-- .../test-precompile-pallet-xcm.ts | 211 +++++++++++++++++- 8 files changed, 402 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4130b4b4f6..b42a1c57e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -486,7 +486,7 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "async-backing-primitives" version = "0.9.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "sp-api", "sp-consensus-slots", @@ -6794,6 +6794,7 @@ dependencies = [ "pallet-evm-precompile-relay-verifier", "pallet-evm-precompile-sha3fips", "pallet-evm-precompile-simple", + "pallet-evm-precompile-xcm", "pallet-evm-precompile-xcm-transactor", "pallet-evm-precompile-xcm-utils", "pallet-evm-precompile-xtokens", @@ -7224,6 +7225,7 @@ dependencies = [ "pallet-evm-precompile-relay-verifier", "pallet-evm-precompile-sha3fips", "pallet-evm-precompile-simple", + "pallet-evm-precompile-xcm", "pallet-evm-precompile-xcm-transactor", "pallet-evm-precompile-xcm-utils", "pallet-evm-precompile-xtokens", @@ -7575,7 +7577,7 @@ dependencies = [ [[package]] name = "nimbus-consensus" version = "0.9.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "async-backing-primitives", "async-trait", @@ -7615,7 +7617,7 @@ dependencies = [ [[package]] name = "nimbus-primitives" version = "0.9.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "async-trait", "frame-benchmarking", @@ -8200,7 +8202,7 @@ dependencies = [ [[package]] name = "pallet-async-backing" version = "0.9.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "cumulus-pallet-parachain-system", "cumulus-primitives-core", @@ -8220,7 +8222,7 @@ dependencies = [ [[package]] name = "pallet-author-inherent" version = "0.9.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "frame-benchmarking", "frame-support", @@ -8239,7 +8241,7 @@ dependencies = [ [[package]] name = "pallet-author-mapping" version = "2.0.5" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "frame-benchmarking", "frame-support", @@ -8258,7 +8260,7 @@ dependencies = [ [[package]] name = "pallet-author-slot-filter" version = "0.9.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "frame-benchmarking", "frame-support", @@ -8615,7 +8617,7 @@ dependencies = [ [[package]] name = "pallet-emergency-para-xcm" version = "0.1.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "cumulus-pallet-parachain-system", "cumulus-primitives-core", @@ -9329,7 +9331,7 @@ dependencies = [ [[package]] name = "pallet-evm-precompile-xcm" version = "0.1.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "cumulus-primitives-core", "evm", @@ -9340,12 +9342,15 @@ dependencies = [ "num_enum 0.7.3", "pallet-evm", "pallet-xcm", + "parity-scale-codec", "precompile-utils", + "scale-info", "sp-core", "sp-runtime", "sp-std", "sp-weights", "staging-xcm", + "staging-xcm-executor", "xcm-primitives 0.1.0", ] @@ -9577,7 +9582,7 @@ dependencies = [ [[package]] name = "pallet-maintenance-mode" version = "0.1.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -9628,7 +9633,7 @@ dependencies = [ [[package]] name = "pallet-migrations" version = "0.1.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "frame-benchmarking", "frame-support", @@ -9956,7 +9961,7 @@ dependencies = [ [[package]] name = "pallet-randomness" version = "0.1.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "environmental", "frame-benchmarking", @@ -10031,7 +10036,7 @@ dependencies = [ [[package]] name = "pallet-relay-storage-roots" version = "0.1.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "cumulus-pallet-parachain-system", "cumulus-primitives-core", @@ -14892,7 +14897,7 @@ dependencies = [ [[package]] name = "session-keys-primitives" version = "0.1.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "async-trait", "frame-support", @@ -18545,7 +18550,7 @@ dependencies = [ [[package]] name = "xcm-primitives" version = "0.1.0" -source = "git+https://github.com/Moonsong-Labs/moonkit?branch=moonbeam-polkadot-stable2407#9c9c3a7c3f8cbc64e27846de74f942599b402cd8" +source = "git+https://github.com/Moonsong-Labs/moonkit?branch=agustin-xcm-transfer-assets-using-temporary#fcbd46e3fe8b1d5d49cd1e53ddfaadc42cce5c66" dependencies = [ "frame-support", "impl-trait-for-tuples", diff --git a/Cargo.toml b/Cargo.toml index 761621cf37..a4d448cf8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -337,23 +337,23 @@ westend-runtime = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", xcm-simulator = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-stable2407" } # Moonkit (wasm) -async-backing-primitives = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } -moonkit-xcm-primitives = { package = "xcm-primitives", git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } -nimbus-primitives = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } -pallet-async-backing = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } -pallet-author-inherent = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } -pallet-author-mapping = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } -pallet-author-slot-filter = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } -pallet-emergency-para-xcm = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } -pallet-evm-precompile-xcm = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } -pallet-maintenance-mode = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } -pallet-migrations = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } -pallet-randomness = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } -pallet-relay-storage-roots = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } -session-keys-primitives = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407", default-features = false } +async-backing-primitives = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } +moonkit-xcm-primitives = { package = "xcm-primitives", git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } +nimbus-primitives = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } +pallet-async-backing = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } +pallet-author-inherent = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } +pallet-author-mapping = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } +pallet-author-slot-filter = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } +pallet-emergency-para-xcm = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } +pallet-evm-precompile-xcm = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } +pallet-maintenance-mode = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } +pallet-migrations = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } +pallet-randomness = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } +pallet-relay-storage-roots = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } +session-keys-primitives = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary", default-features = false } # Moonkit (client) -nimbus-consensus = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "moonbeam-polkadot-stable2407" } +nimbus-consensus = { git = "https://github.com/Moonsong-Labs/moonkit", branch = "agustin-xcm-transfer-assets-using-temporary" } # Other (wasm) async-trait = { version = "0.1.42" } diff --git a/runtime/moonbeam/Cargo.toml b/runtime/moonbeam/Cargo.toml index c52ea28aeb..5859ed6938 100644 --- a/runtime/moonbeam/Cargo.toml +++ b/runtime/moonbeam/Cargo.toml @@ -171,6 +171,7 @@ nimbus-primitives = { workspace = true } pallet-async-backing = { workspace = true } pallet-author-inherent = { workspace = true } pallet-author-slot-filter = { workspace = true } +pallet-evm-precompile-xcm = { workspace = true } pallet-relay-storage-roots = { workspace = true } # Benchmarking @@ -256,6 +257,7 @@ std = [ "pallet-evm-precompile-referenda/std", "pallet-evm-precompile-relay-encoder/std", "pallet-evm-precompile-relay-verifier/std", + "pallet-evm-precompile-xcm/std", "pallet-evm-precompile-xcm-transactor/std", "pallet-evm-precompile-xcm-utils/std", "pallet-evm-precompile-xtokens/std", diff --git a/runtime/moonbeam/src/precompiles.rs b/runtime/moonbeam/src/precompiles.rs index 685f292ce3..934c7ff3b5 100644 --- a/runtime/moonbeam/src/precompiles.rs +++ b/runtime/moonbeam/src/precompiles.rs @@ -15,13 +15,17 @@ // along with Moonbeam. If not, see . use crate::{ - asset_config::ForeignAssetInstance, xcm_config::XcmExecutorConfig, OpenTechCommitteeInstance, - Runtime, TreasuryCouncilInstance, + asset_config::ForeignAssetInstance, + xcm_config::{AssetType, XcmExecutorConfig}, + AccountId, AssetId, AssetManager, Balances, Erc20XcmBridge, OpenTechCommitteeInstance, Runtime, + TreasuryCouncilInstance, H160, }; -use crate::{AssetId, H160}; use frame_support::parameter_types; use moonbeam_runtime_common::weights as moonbeam_weights; -use moonkit_xcm_primitives::AccountIdAssetIdConversion; +use moonkit_xcm_primitives::{ + location_matcher::{Erc20PalletMatcher, ForeignAssetMatcher, SingleAddressMatcher}, + AccountIdAssetIdConversion, +}; use pallet_evm_precompile_author_mapping::AuthorMappingPrecompile; use pallet_evm_precompile_balances_erc20::{Erc20BalancesPrecompile, Erc20Metadata}; use pallet_evm_precompile_batch::BatchPrecompile; @@ -45,6 +49,7 @@ use pallet_evm_precompile_relay_encoder::RelayEncoderPrecompile; use pallet_evm_precompile_relay_verifier::RelayDataVerifierPrecompile; use pallet_evm_precompile_sha3fips::Sha3FIPS256; use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; +use pallet_evm_precompile_xcm::PalletXcmPrecompile; use pallet_evm_precompile_xcm_transactor::{ v1::XcmTransactorPrecompileV1, v2::XcmTransactorPrecompileV2, v3::XcmTransactorPrecompileV3, }; @@ -54,6 +59,7 @@ use pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSet; use pallet_precompile_benchmarks::WeightInfo; use precompile_utils::precompile_set::*; use sp_std::prelude::*; +use xcm_primitives::AsAssetType; parameter_types! { pub P256VerifyWeight: frame_support::weights::Weight = @@ -93,6 +99,9 @@ pub const FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4]; /// to Erc20AssetsPrecompileSet being marked as local pub const LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8, 255u8, 255u8, 254u8]; +/// Const to identify ERC20_BALANCES_PRECOMPILE address +pub const ERC20_BALANCES_PRECOMPILE: u64 = 2050; + parameter_types! { pub ForeignAssetPrefix: &'static [u8] = FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX; pub LocalAssetPrefix: &'static [u8] = LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX; @@ -100,6 +109,19 @@ parameter_types! { type EthereumPrecompilesChecks = (AcceptDelegateCall, CallableByContract, CallableByPrecompile); +// Pallet-xcm precompile types. +// Type that converts AssetId into Location +type AssetIdToLocationManager = AsAssetType; + +// The pallet-balances address is identified by ERC20_BALANCES_PRECOMPILE const +type SingleAddressMatch = SingleAddressMatcher; + +// Type that matches an AccountId with a foreign asset address (if any) +type ForeignAssetMatch = ForeignAssetMatcher; + +// Erc20XcmBridge pallet is used to match ERC20s +type Erc20Match = Erc20PalletMatcher; + #[precompile_utils::precompile_name_from_address] type MoonbeamPrecompilesAt = ( // Ethereum precompiles: @@ -249,6 +271,11 @@ type MoonbeamPrecompilesAt = ( RelayDataVerifierPrecompile, (CallableByContract, CallableByPrecompile), >, + PrecompileAt< + AddressU64<2074>, + PalletXcmPrecompile, + (CallableByContract, CallableByPrecompile), + >, ); pub struct DisabledLocalAssets(sp_std::marker::PhantomData); diff --git a/runtime/moonriver/Cargo.toml b/runtime/moonriver/Cargo.toml index 1347ed8ca9..2d240629f6 100644 --- a/runtime/moonriver/Cargo.toml +++ b/runtime/moonriver/Cargo.toml @@ -172,6 +172,7 @@ nimbus-primitives = { workspace = true } pallet-async-backing = { workspace = true } pallet-author-inherent = { workspace = true } pallet-author-slot-filter = { workspace = true } +pallet-evm-precompile-xcm = { workspace = true } pallet-relay-storage-roots = { workspace = true } # Benchmarking @@ -257,6 +258,7 @@ std = [ "pallet-evm-precompile-referenda/std", "pallet-evm-precompile-relay-encoder/std", "pallet-evm-precompile-relay-verifier/std", + "pallet-evm-precompile-xcm/std", "pallet-evm-precompile-xcm-transactor/std", "pallet-evm-precompile-xcm-utils/std", "pallet-evm-precompile-xtokens/std", diff --git a/runtime/moonriver/src/precompiles.rs b/runtime/moonriver/src/precompiles.rs index a7106e4ac0..2349fa5b26 100644 --- a/runtime/moonriver/src/precompiles.rs +++ b/runtime/moonriver/src/precompiles.rs @@ -15,11 +15,16 @@ // along with Moonbeam. If not, see . use crate::{ - asset_config::ForeignAssetInstance, xcm_config::XcmExecutorConfig, OpenTechCommitteeInstance, - Runtime, TreasuryCouncilInstance, + asset_config::ForeignAssetInstance, + xcm_config::{AssetType, XcmExecutorConfig}, + AccountId, AssetId, AssetManager, Balances, Erc20XcmBridge, OpenTechCommitteeInstance, Runtime, + TreasuryCouncilInstance, }; use frame_support::parameter_types; use moonbeam_runtime_common::weights as moonriver_weights; +use moonkit_xcm_primitives::location_matcher::{ + Erc20PalletMatcher, ForeignAssetMatcher, SingleAddressMatcher, +}; use pallet_evm_precompile_author_mapping::AuthorMappingPrecompile; use pallet_evm_precompile_balances_erc20::{Erc20BalancesPrecompile, Erc20Metadata}; use pallet_evm_precompile_batch::BatchPrecompile; @@ -43,6 +48,7 @@ use pallet_evm_precompile_relay_encoder::RelayEncoderPrecompile; use pallet_evm_precompile_relay_verifier::RelayDataVerifierPrecompile; use pallet_evm_precompile_sha3fips::Sha3FIPS256; use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256}; +use pallet_evm_precompile_xcm::PalletXcmPrecompile; use pallet_evm_precompile_xcm_transactor::{ v1::XcmTransactorPrecompileV1, v2::XcmTransactorPrecompileV2, v3::XcmTransactorPrecompileV3, }; @@ -51,6 +57,7 @@ use pallet_evm_precompile_xtokens::XtokensPrecompile; use pallet_evm_precompileset_assets_erc20::Erc20AssetsPrecompileSet; use pallet_precompile_benchmarks::WeightInfo; use precompile_utils::precompile_set::*; +use xcm_primitives::AsAssetType; parameter_types! { pub P256VerifyWeight: frame_support::weights::Weight = @@ -87,12 +94,28 @@ impl Erc20Metadata for NativeErc20Metadata { /// to Erc20AssetsPrecompileSet being marked as foreign pub const FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX: &[u8] = &[255u8; 4]; +/// Const to identify ERC20_BALANCES_PRECOMPILE address +pub const ERC20_BALANCES_PRECOMPILE: u64 = 2050; + parameter_types! { pub ForeignAssetPrefix: &'static [u8] = FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX; } type EthereumPrecompilesChecks = (AcceptDelegateCall, CallableByContract, CallableByPrecompile); +// Pallet-xcm precompile types. +// Type that converts AssetId into Location +type AssetIdToLocationManager = AsAssetType; + +// The pallet-balances address is identified by ERC20_BALANCES_PRECOMPILE const +type SingleAddressMatch = SingleAddressMatcher; + +// Type that matches an AccountId with a foreign asset address (if any) +type ForeignAssetMatch = ForeignAssetMatcher; + +// Erc20XcmBridge pallet is used to match ERC20s +type Erc20Match = Erc20PalletMatcher; + #[precompile_utils::precompile_name_from_address] type MoonriverPrecompilesAt = ( // Ethereum precompiles: @@ -242,6 +265,11 @@ type MoonriverPrecompilesAt = ( RelayDataVerifierPrecompile, (CallableByContract, CallableByPrecompile), >, + PrecompileAt< + AddressU64<2074>, + PalletXcmPrecompile, + (CallableByContract, CallableByPrecompile), + >, ); /// The PrecompileSet installed in the Moonriver runtime. diff --git a/test/contracts/src/XcmInterface.sol b/test/contracts/src/XcmInterface.sol index f05c771008..97eca04fe9 100644 --- a/test/contracts/src/XcmInterface.sol +++ b/test/contracts/src/XcmInterface.sol @@ -35,68 +35,139 @@ interface XCM { uint256 amount; } + // The values start at `0` and are represented as `uint8` + enum TransferType { + Teleport, + LocalReserve, + DestinationReserve + } + /// @dev Function to send assets via XCM using transfer_assets() pallet-xcm extrinsic. - /// @custom:selector 59df8416 + /// @custom:selector 9ea8ada7 /// @param dest The destination chain. /// @param beneficiary The actual account that will receive the tokens on dest. - /// @param assets The combination (array) of assets to send. + /// @param assets The combination (array) of assets to send in Location format. /// @param feeAssetItem The index of the asset that will be used to pay for fees. - /// @param weight The weight to be used for the whole XCM operation. - /// (uint64::MAX in refTime means Unlimited weight) function transferAssetsLocation( Location memory dest, Location memory beneficiary, AssetLocationInfo[] memory assets, - uint32 feeAssetItem, - Weight memory weight + uint32 feeAssetItem ) external; /// @dev Function to send assets via XCM to a 20 byte-like parachain /// using transfer_assets() pallet-xcm extrinsic. - /// @custom:selector b489262e + /// @custom:selector a0aeb5fe /// @param paraId The para-id of the destination chain. /// @param beneficiary The actual account that will receive the tokens on paraId destination. - /// @param assets The combination (array) of assets to send. + /// @param assets The combination (array) of assets to send in Address format. /// @param feeAssetItem The index of the asset that will be used to pay for fees. - /// @param weight The weight to be used for the whole XCM operation. - /// (uint64::MAX in refTime means Unlimited weight) function transferAssetsToPara20( uint32 paraId, address beneficiary, AssetAddressInfo[] memory assets, - uint32 feeAssetItem, - Weight memory weight + uint32 feeAssetItem ) external; /// @dev Function to send assets via XCM to a 32 byte-like parachain /// using transfer_assets() pallet-xcm extrinsic. - /// @custom:selector 4461e6f5 + /// @custom:selector f23032c3 /// @param paraId The para-id of the destination chain. /// @param beneficiary The actual account that will receive the tokens on paraId destination. - /// @param assets The combination (array) of assets to send. + /// @param assets The combination (array) of assets to send in Address format. /// @param feeAssetItem The index of the asset that will be used to pay for fees. - /// @param weight The weight to be used for the whole XCM operation. - /// (uint64::MAX in refTime means Unlimited weight) function transferAssetsToPara32( uint32 paraId, bytes32 beneficiary, AssetAddressInfo[] memory assets, - uint32 feeAssetItem, - Weight memory weight + uint32 feeAssetItem ) external; /// @dev Function to send assets via XCM to the relay chain /// using transfer_assets() pallet-xcm extrinsic. - /// @custom:selector d7c89659 + /// @custom:selector 6521cc2c /// @param beneficiary The actual account that will receive the tokens on the relay chain. - /// @param assets The combination (array) of assets to send. + /// @param assets The combination (array) of assets to send in Address format. /// @param feeAssetItem The index of the asset that will be used to pay for fees. - /// @param weight The weight to be used for the whole XCM operation. - /// (uint64::MAX in refTime means Unlimited weight) function transferAssetsToRelay( bytes32 beneficiary, AssetAddressInfo[] memory assets, - uint32 feeAssetItem, - Weight memory weight + uint32 feeAssetItem + ) external; + + /// @dev Function to send assets through transfer_assets_using_type_and_then() pallet-xcm + /// extrinsic. + /// Important: in this selector RemoteReserve type (for either assets or fees) is not allowed. + /// If users want to send assets and fees (in Location format) with a remote reserve, + /// they must use the selector fc19376c. + /// @custom:selector 8425d893 + /// @param dest The destination chain. + /// @param assets The combination (array) of assets to send in Location format. + /// @param assetsTransferType The TransferType corresponding to assets being sent. + /// @param remoteFeesIdIndex The index of the asset (inside assets array) to use as fees. + /// @param feesTransferType The TransferType corresponding to the asset used as fees. + /// @param customXcmOnDest The XCM message to execute on destination chain. + function transferAssetsUsingTypeAndThenLocation( + Location memory dest, + AssetLocationInfo[] memory assets, + TransferType assetsTransferType, + uint8 remoteFeesIdIndex, + TransferType feesTransferType, + bytes memory customXcmOnDest + ) external; + + /// @dev Function to send assets through transfer_assets_using_type_and_then() pallet-xcm + /// extrinsic. + /// @custom:selector fc19376c + /// @param dest The destination chain. + /// @param assets The combination (array) of assets to send in Location format. + /// @param remoteFeesIdIndex The index of the asset (inside assets array) to use as fees. + /// @param customXcmOnDest The XCM message to execute on destination chain. + /// @param remoteReserve The remote reserve corresponding for assets and fees. They MUST + /// share the same reserve. + function transferAssetsUsingTypeAndThenLocation( + Location memory dest, + AssetLocationInfo[] memory assets, + uint8 remoteFeesIdIndex, + bytes memory customXcmOnDest, + Location memory remoteReserve + ) external; + + /// @dev Function to send assets through transfer_assets_using_type_and_then() pallet-xcm + /// extrinsic. + /// Important: in this selector RemoteReserve type (for either assets or fees) is not allowed. + /// If users want to send assets and fees (in Address format) with a remote reserve, + /// they must use the selector aaecfc62. + /// @custom:selector 998093ee + /// @param dest The destination chain. + /// @param assets The combination (array) of assets to send in Address format. + /// @param assetsTransferType The TransferType corresponding to assets being sent. + /// @param remoteFeesIdIndex The index of the asset (inside assets array) to use as fees. + /// @param feesTransferType The TransferType corresponding to the asset used as fees. + /// @param customXcmOnDest The XCM message to execute on destination chain. + function transferAssetsUsingTypeAndThenAddress( + Location memory dest, + AssetAddressInfo[] memory assets, + TransferType assetsTransferType, + uint8 remoteFeesIdIndex, + TransferType feesTransferType, + bytes memory customXcmOnDest + ) external; + + /// @dev Function to send assets through transfer_assets_using_type_and_then() pallet-xcm + /// extrinsic. + /// @custom:selector aaecfc62 + /// @param dest The destination chain. + /// @param assets The combination (array) of assets to send in Address format. + /// @param remoteFeesIdIndex The index of the asset (inside assets array) to use as fees. + /// @param customXcmOnDest The XCM message to execute on destination chain. + /// @param remoteReserve The remote reserve corresponding for assets and fees. They MUST + /// share the same reserve. + function transferAssetsUsingTypeAndThenAddress( + Location memory dest, + AssetAddressInfo[] memory assets, + uint8 remoteFeesIdIndex, + bytes memory customXcmOnDest, + Location memory remoteReserve ) external; } \ No newline at end of file diff --git a/test/suites/dev/moonbase/test-precompile/test-precompile-pallet-xcm.ts b/test/suites/dev/moonbase/test-precompile/test-precompile-pallet-xcm.ts index a25642d9dc..a369afd5e8 100644 --- a/test/suites/dev/moonbase/test-precompile/test-precompile-pallet-xcm.ts +++ b/test/suites/dev/moonbase/test-precompile/test-precompile-pallet-xcm.ts @@ -2,6 +2,7 @@ import "@moonbeam-network/api-augment"; import { beforeAll, describeSuite, fetchCompiledContract, expect } from "@moonwall/cli"; import { ALITH_ADDRESS, BALTATHAR_ADDRESS, alith, createEthersTransaction } from "@moonwall/util"; import { u128 } from "@polkadot/types-codec"; +import { numberToHex } from "@polkadot/util" import { PalletAssetsAssetAccount, PalletAssetsAssetDetails } from "@polkadot/types/lookup"; import { encodeFunctionData } from "viem"; import { expectEVMResult, mockOldAssetBalance } from "../../../../helpers"; @@ -74,7 +75,7 @@ describeSuite({ to: PRECOMPILE_PALLET_XCM_ADDRESS, data: encodeFunctionData({ abi: xcmInterface, - args: [dest, beneficiary, assetLocationInfo, 0, weight], + args: [dest, beneficiary, assetLocationInfo, 0], functionName: "transferAssetsLocation", }), gasLimit: 500_000n, @@ -110,7 +111,7 @@ describeSuite({ to: PRECOMPILE_PALLET_XCM_ADDRESS, data: encodeFunctionData({ abi: xcmInterface, - args: [paraId, BALTATHAR_ADDRESS, assetAddressInfo, 0, weight], + args: [paraId, BALTATHAR_ADDRESS, assetAddressInfo, 0], functionName: "transferAssetsToPara20", }), gasLimit: 500_000n, @@ -147,7 +148,7 @@ describeSuite({ to: PRECOMPILE_PALLET_XCM_ADDRESS, data: encodeFunctionData({ abi: xcmInterface, - args: [paraId, beneficiaryAddress, assetAddressInfo, 0, weight], + args: [paraId, beneficiaryAddress, assetAddressInfo, 0], functionName: "transferAssetsToPara32", }), gasLimit: 500_000n, @@ -183,7 +184,7 @@ describeSuite({ to: PRECOMPILE_PALLET_XCM_ADDRESS, data: encodeFunctionData({ abi: xcmInterface, - args: [beneficiaryAddress, assetAddressInfo, 0, weight], + args: [beneficiaryAddress, assetAddressInfo, 0], functionName: "transferAssetsToRelay", }), gasLimit: 500_000n, @@ -200,5 +201,207 @@ describeSuite({ expect(assetBalanceAfter).to.equal(assetBalanceBefore - amountToSend); }, }); + + it({ + id: "T05", + title: "allows to call transferAssetsUsingTypeAndThenLocation::8425d893 selector", + test: async function () { + const { abi: xcmInterface } = fetchCompiledContract("XCM"); + const assetBalanceBefore = ( + await context.polkadotJs().query.assets.account(assetId.toU8a(), ALITH_ADDRESS) + ) + .unwrap() + .balance.toBigInt(); + + const dest: [number, any[]] = [1, []]; + const assetLocation: [number, any[]] = [1, []]; + const assetLocationInfo = [[assetLocation, amountToSend]]; + + // DestinationReserve + let assetsAndFeesTransferType = 2; + + const message = { + V3: [ + { + ClearOrigin: null, + }, + ], + }; + const xcmOnDest = context.polkadotJs().createType("XcmVersionedXcm", message); + + const rawTxn = await createEthersTransaction(context, { + to: PRECOMPILE_PALLET_XCM_ADDRESS, + data: encodeFunctionData({ + abi: xcmInterface, + args: [dest, assetLocationInfo, assetsAndFeesTransferType, 0n, assetsAndFeesTransferType, + xcmOnDest.toHex()], + functionName: "transferAssetsUsingTypeAndThenLocation", + }), + gasLimit: 500_000n, + }); + + const result = await context.createBlock(rawTxn); + expectEVMResult(result.result!.events, "Succeed"); + + const assetBalanceAfter = ( + await context.polkadotJs().query.assets.account(assetId.toU8a(), ALITH_ADDRESS) + ) + .unwrap() + .balance.toBigInt(); + expect(assetBalanceAfter).to.equal(assetBalanceBefore - amountToSend); + }, + }); + + it({ + id: "T06", + title: "allows to call transferAssetsUsingTypeAndThenLocation::fc19376c selector", + test: async function () { + const { abi: xcmInterface } = fetchCompiledContract("XCM"); + const assetBalanceBefore = ( + await context.polkadotJs().query.assets.account(assetId.toU8a(), ALITH_ADDRESS) + ) + .unwrap() + .balance.toBigInt(); + + const paraIdInHex = numberToHex(2000, 32); + const parachain_enum_selector = "0x00"; + + // This represents X2(Parent, Parachain(2000)) + const dest: [number, any[]] = [1, [parachain_enum_selector + paraIdInHex.slice(2)]]; + + const remoteReserve: [number, any[]] = [1, []]; + const assetLocation: [number, any[]] = [1, []]; + const assetLocationInfo = [[assetLocation, amountToSend]]; + + const message = { + V3: [ + { + ClearOrigin: null, + }, + ], + }; + const xcmOnDest = context.polkadotJs().createType("XcmVersionedXcm", message); + + const rawTxn = await createEthersTransaction(context, { + to: PRECOMPILE_PALLET_XCM_ADDRESS, + data: encodeFunctionData({ + abi: xcmInterface, + args: [dest, assetLocationInfo, 0n, xcmOnDest.toHex(), remoteReserve], + functionName: "transferAssetsUsingTypeAndThenLocation", + }), + gasLimit: 500_000n, + }); + + const result = await context.createBlock(rawTxn); + expectEVMResult(result.result!.events, "Succeed"); + + const assetBalanceAfter = ( + await context.polkadotJs().query.assets.account(assetId.toU8a(), ALITH_ADDRESS) + ) + .unwrap() + .balance.toBigInt(); + expect(assetBalanceAfter).to.equal(assetBalanceBefore - amountToSend); + }, + }); + + it({ + id: "T07", + title: "allows to call transferAssetsUsingTypeAndThenAddress::998093ee selector", + test: async function () { + const { abi: xcmInterface } = fetchCompiledContract("XCM"); + const assetBalanceBefore = ( + await context.polkadotJs().query.assets.account(assetId.toU8a(), ALITH_ADDRESS) + ) + .unwrap() + .balance.toBigInt(); + + // Relay as destination + const dest: [number, any[]] = [1, []]; + const assetAddressInfo = [[ADDRESS_ERC20, amountToSend]]; + + // DestinationReserve + let assetsAndFeesTransferType = 2; + + const message = { + V3: [ + { + ClearOrigin: null, + }, + ], + }; + const xcmOnDest = context.polkadotJs().createType("XcmVersionedXcm", message); + + const rawTxn = await createEthersTransaction(context, { + to: PRECOMPILE_PALLET_XCM_ADDRESS, + data: encodeFunctionData({ + abi: xcmInterface, + args: [dest, assetAddressInfo, assetsAndFeesTransferType, 0n, assetsAndFeesTransferType, + xcmOnDest.toHex()], + functionName: "transferAssetsUsingTypeAndThenAddress", + }), + gasLimit: 500_000n, + }); + + const result = await context.createBlock(rawTxn); + expectEVMResult(result.result!.events, "Succeed"); + + const assetBalanceAfter = ( + await context.polkadotJs().query.assets.account(assetId.toU8a(), ALITH_ADDRESS) + ) + .unwrap() + .balance.toBigInt(); + expect(assetBalanceAfter).to.equal(assetBalanceBefore - amountToSend); + }, + }); + + it({ + id: "T08", + title: "allows to call transferAssetsUsingTypeAndThenAddress::aaecfc62 selector", + test: async function () { + const { abi: xcmInterface } = fetchCompiledContract("XCM"); + const assetBalanceBefore = ( + await context.polkadotJs().query.assets.account(assetId.toU8a(), ALITH_ADDRESS) + ) + .unwrap() + .balance.toBigInt(); + + const paraIdInHex = numberToHex(2000, 32); + const parachain_enum_selector = "0x00"; + + // This represents X2(Parent, Parachain(2000)) + const dest: [number, any[]] = [1, [parachain_enum_selector + paraIdInHex.slice(2)]]; + const assetAddressInfo = [[ADDRESS_ERC20, amountToSend]]; + const remoteReserve: [number, any[]] = [1, []]; + + const message = { + V3: [ + { + ClearOrigin: null, + }, + ], + }; + const xcmOnDest = context.polkadotJs().createType("XcmVersionedXcm", message); + + const rawTxn = await createEthersTransaction(context, { + to: PRECOMPILE_PALLET_XCM_ADDRESS, + data: encodeFunctionData({ + abi: xcmInterface, + args: [dest, assetAddressInfo, 0n, xcmOnDest.toHex(), remoteReserve], + functionName: "transferAssetsUsingTypeAndThenAddress", + }), + gasLimit: 500_000n, + }); + + const result = await context.createBlock(rawTxn); + expectEVMResult(result.result!.events, "Succeed"); + + const assetBalanceAfter = ( + await context.polkadotJs().query.assets.account(assetId.toU8a(), ALITH_ADDRESS) + ) + .unwrap() + .balance.toBigInt(); + expect(assetBalanceAfter).to.equal(assetBalanceBefore - amountToSend); + }, + }); }, });