Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(moonbeam, moonriver): support evm native foreign assets in xcm transactor #3203

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions runtime/moonbase/tests/xcm_mock/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -777,8 +777,10 @@ impl pallet_xcm_transactor::Config for Runtime {
type SovereignAccountDispatcherOrigin = frame_system::EnsureRoot<AccountId>;
type CurrencyId = CurrencyId;
type AccountIdToLocation = xcm_primitives::AccountIdToLocation<AccountId>;
type CurrencyIdToLocation =
CurrencyIdToLocation<xcm_primitives::AsAssetType<AssetId, AssetType, AssetManager>>;
type CurrencyIdToLocation = CurrencyIdToLocation<(
EvmForeignAssets,
AsAssetType<moonbeam_core_primitives::AssetId, AssetType, AssetManager>,
)>;
type SelfLocation = SelfLocation;
type Weigher = xcm_builder::FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
type UniversalLocation = UniversalLocation;
Expand Down Expand Up @@ -1086,7 +1088,9 @@ pub(crate) fn para_events() -> Vec<RuntimeEvent> {

use frame_support::traits::tokens::{PayFromAccount, UnityAssetBalanceConversion};
use frame_support::traits::{OnFinalize, OnInitialize, UncheckedOnRuntimeUpgrade};
use moonbase_runtime::EvmForeignAssets;
use pallet_evm::FrameSystemAccountProvider;
use xcm_primitives::AsAssetType;

pub(crate) fn on_runtime_upgrade() {
VersionUncheckedMigrateToV1::<Runtime>::on_runtime_upgrade();
Expand Down
5 changes: 4 additions & 1 deletion runtime/moonbeam/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,10 @@ impl pallet_xcm_transactor::Config for Runtime {
type SovereignAccountDispatcherOrigin = EnsureRoot<AccountId>;
type CurrencyId = CurrencyId;
type AccountIdToLocation = AccountIdToLocation<AccountId>;
type CurrencyIdToLocation = CurrencyIdToLocation<AsAssetType<AssetId, AssetType, AssetManager>>;
type CurrencyIdToLocation = CurrencyIdToLocation<(
EvmForeignAssets,
AsAssetType<AssetId, AssetType, AssetManager>,
)>;
type XcmSender = XcmRouter;
type SelfLocation = SelfLocation;
type Weigher = XcmWeigher;
Expand Down
55 changes: 41 additions & 14 deletions runtime/moonbeam/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ use sp_runtime::{traits::Dispatchable, BuildStorage, Digest, DigestItem, Perbill
use std::collections::BTreeMap;

use fp_rpc::ConvertTransaction;
use moonbeam_runtime::EvmForeignAssets;
use sp_runtime::traits::MaybeEquivalence;

pub fn existential_deposit() -> u128 {
<Runtime as pallet_balances::Config>::ExistentialDeposit::get()
Expand Down Expand Up @@ -142,6 +144,7 @@ pub struct ExtBuilder {
evm_accounts: BTreeMap<H160, GenesisAccount>,
// [assettype, metadata, Vec<Account, Balance,>, is_sufficient]
xcm_assets: Vec<XcmAssetInitialization>,
evm_native_foreign_assets: bool,
safe_xcm_version: Option<u32>,
}

Expand Down Expand Up @@ -175,6 +178,7 @@ impl Default for ExtBuilder {
chain_id: CHAIN_ID,
evm_accounts: BTreeMap::new(),
xcm_assets: vec![],
evm_native_foreign_assets: false,
safe_xcm_version: None,
}
}
Expand Down Expand Up @@ -219,6 +223,11 @@ impl ExtBuilder {
self
}

pub fn with_evm_native_foreign_assets(mut self) -> Self {
self.evm_native_foreign_assets = true;
self
}

pub fn with_safe_xcm_version(mut self, safe_xcm_version: u32) -> Self {
self.safe_xcm_version = Some(safe_xcm_version);
self
Expand Down Expand Up @@ -294,22 +303,40 @@ impl ExtBuilder {
// If any xcm assets specified, we register them here
for xcm_asset_initialization in xcm_assets {
let asset_id: AssetId = xcm_asset_initialization.asset_type.clone().into();
AssetManager::register_foreign_asset(
root_origin(),
xcm_asset_initialization.asset_type,
xcm_asset_initialization.metadata,
1,
xcm_asset_initialization.is_sufficient,
)
.unwrap();
for (account, balance) in xcm_asset_initialization.balances {
moonbeam_runtime::Assets::mint(
origin_of(AssetManager::account_id()),
asset_id.into(),
account,
balance,
if self.evm_native_foreign_assets {
let AssetType::Xcm(location) = xcm_asset_initialization.asset_type;
let metadata = xcm_asset_initialization.metadata.clone();
EvmForeignAssets::register_foreign_asset(
asset_id,
xcm_builder::WithLatestLocationConverter::convert_back(&location).unwrap(),
metadata.decimals,
metadata.symbol.try_into().unwrap(),
metadata.name.try_into().unwrap(),
)
.expect("register evm native foreign asset");

for (account, balance) in xcm_asset_initialization.balances {
EvmForeignAssets::mint_into(asset_id.into(), account, balance.into())
.expect("mint evm native foreign asset");
}
} else {
AssetManager::register_foreign_asset(
root_origin(),
xcm_asset_initialization.asset_type,
xcm_asset_initialization.metadata,
1,
xcm_asset_initialization.is_sufficient,
)
.unwrap();
for (account, balance) in xcm_asset_initialization.balances {
moonbeam_runtime::Assets::mint(
origin_of(AssetManager::account_id()),
asset_id.into(),
account,
balance,
)
.unwrap();
}
}
}
System::set_block_number(1);
Expand Down
171 changes: 115 additions & 56 deletions runtime/moonbeam/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
#![cfg(test)]

mod common;

use common::*;
use std::cell::Cell;
use std::rc::Rc;

use fp_evm::{Context, IsPrecompileResult};
use frame_support::{
Expand All @@ -38,10 +41,11 @@ use moonbeam_runtime::{
asset_config::ForeignAssetInstance,
currency::GLMR,
xcm_config::{CurrencyId, SelfReserve},
AccountId, Balances, CrowdloanRewards, Executive, OpenTechCommitteeCollective,
ParachainStaking, PolkadotXcm, Precompiles, Runtime, RuntimeBlockWeights, RuntimeCall,
RuntimeEvent, System, TransactionPayment, TransactionPaymentAsGasPrice, Treasury,
TreasuryCouncilCollective, XcmTransactor, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, WEEKS,
AccountId, Balances, CrowdloanRewards, EvmForeignAssets, Executive,
OpenTechCommitteeCollective, ParachainStaking, PolkadotXcm, Precompiles, Runtime,
RuntimeBlockWeights, RuntimeCall, RuntimeEvent, System, TransactionPayment,
TransactionPaymentAsGasPrice, Treasury, TreasuryCouncilCollective, XcmTransactor,
FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, WEEKS,
};
use moonbeam_xcm_benchmarks::weights::XcmWeight;
use moonkit_xcm_primitives::AccountIdAssetIdConversion;
Expand Down Expand Up @@ -1942,62 +1946,117 @@ fn xcm_asset_erc20_precompiles_approve() {

#[test]
fn xtokens_precompile_transfer() {
ExtBuilder::default()
.with_xcm_assets(vec![XcmAssetInitialization {
asset_type: AssetType::Xcm(xcm::v3::Location::parent()),
metadata: AssetRegistrarMetadata {
name: b"RelayToken".to_vec(),
symbol: b"Relay".to_vec(),
decimals: 12,
is_frozen: false,
},
balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)],
is_sufficient: true,
}])
.with_balances(vec![
(AccountId::from(ALICE), 2_000 * GLMR),
(AccountId::from(BOB), 1_000 * GLMR),
])
.with_safe_xcm_version(3)
.build()
.execute_with(|| {
let xtokens_precompile_address = H160::from_low_u64_be(2052);
fn run_test_variant(evm_native: bool) {
let mut builder = ExtBuilder::default();

// We have the assetId that corresponds to the relay chain registered
let relay_asset_id: moonbeam_runtime::AssetId =
AssetType::Xcm(xcm::v3::Location::parent()).into();
if evm_native {
builder = builder.with_evm_native_foreign_assets();
}

// Its address is
let asset_precompile_address = Runtime::asset_id_to_account(
FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX,
relay_asset_id,
);
let asset_type = AssetType::Xcm(xcm::v3::Location::parent());
builder
.with_xcm_assets(vec![XcmAssetInitialization {
asset_type: asset_type.clone(),
metadata: AssetRegistrarMetadata {
name: b"RelayToken".to_vec(),
symbol: b"Relay".to_vec(),
decimals: 12,
is_frozen: false,
},
balances: vec![(AccountId::from(ALICE), 1_000_000_000_000_000)],
is_sufficient: true,
}])
.with_balances(vec![
(AccountId::from(ALICE), 2_000 * GLMR),
(AccountId::from(BOB), 1_000 * GLMR),
])
.with_safe_xcm_version(3)
.build()
.execute_with(|| {
let xtokens_precompile_address = H160::from_low_u64_be(2052);

// Alice has 1000 tokens. She should be able to send through precompile
let destination = Location::new(
1,
[Junction::AccountId32 {
network: None,
id: [1u8; 32],
}],
);
// We have the assetId that corresponds to the relay chain registered
let relay_asset_id: moonbeam_runtime::AssetId =
AssetType::Xcm(xcm::v3::Location::parent()).into();

// We use the address of the asset as an identifier of the asset we want to transfer
Precompiles::new()
.prepare_test(
ALICE,
xtokens_precompile_address,
XtokensPCall::transfer {
currency_address: Address(asset_precompile_address.into()),
amount: 500_000_000_000_000u128.into(),
destination,
weight: 4_000_000,
},
)
.expect_cost(25121)
.expect_no_logs()
.execute_returns(())
})
// Its address is
let asset_precompile_address = Runtime::asset_id_to_account(
FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX,
relay_asset_id,
);

// Alice has 1000 tokens. She should be able to send through precompile
let destination = Location::new(
1,
[Junction::AccountId32 {
network: None,
id: [1u8; 32],
}],
);

let inside = Rc::new(Cell::new(false));
let inside2 = inside.clone();

// We use the address of the asset as an identifier of the asset we want to transfer
Precompiles::new()
.prepare_test(
ALICE,
xtokens_precompile_address,
XtokensPCall::transfer {
currency_address: Address(asset_precompile_address.into()),
amount: 500_000_000_000_000u128.into(),
destination,
weight: 4_000_000,
},
)
.expect_cost(if evm_native { 176721 } else { 25121 })
.expect_no_logs()
// We expect an evm subcall ERC20.burnFrom
.with_subcall_handle(move |subcall| {
let Subcall {
address,
transfer,
input,
target_gas: _,
is_static,
context,
} = subcall;

assert_eq!(context.caller, EvmForeignAssets::account_id().into());

let asset_id: u128 = asset_type.clone().into();
let expected_address: H160 = Runtime::asset_id_to_account(
FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX,
asset_id,
)
.into();
assert_eq!(address, expected_address);
assert_eq!(is_static, false);

assert!(transfer.is_none());

assert_eq!(context.address, expected_address);
assert_eq!(context.apparent_value, 0u8.into());

assert_eq!(&input[..4], &keccak256!("burnFrom(address,uint256)")[..4]);
assert_eq!(&input[4..16], &[0u8; 12]);
assert_eq!(&input[16..36], ALICE);

inside2.set(true);

SubcallOutput {
output: Default::default(),
cost: 149_000,
logs: vec![],
..SubcallOutput::succeed()
}
})
.execute_returns(())
})
}

run_test_variant(false);
run_test_variant(true);
}

#[test]
Expand Down
8 changes: 6 additions & 2 deletions runtime/moonbeam/tests/xcm_mock/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -763,8 +763,10 @@ impl pallet_xcm_transactor::Config for Runtime {
type SovereignAccountDispatcherOrigin = frame_system::EnsureRoot<AccountId>;
type CurrencyId = CurrencyId;
type AccountIdToLocation = xcm_primitives::AccountIdToLocation<AccountId>;
type CurrencyIdToLocation =
CurrencyIdToLocation<xcm_primitives::AsAssetType<AssetId, AssetType, AssetManager>>;
type CurrencyIdToLocation = CurrencyIdToLocation<(
EvmForeignAssets,
AsAssetType<moonbeam_core_primitives::AssetId, AssetType, AssetManager>,
)>;
type SelfLocation = SelfLocation;
type Weigher = xcm_builder::FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
type UniversalLocation = UniversalLocation;
Expand Down Expand Up @@ -1072,8 +1074,10 @@ pub(crate) fn para_events() -> Vec<RuntimeEvent> {

use frame_support::traits::tokens::{PayFromAccount, UnityAssetBalanceConversion};
use frame_support::traits::{OnFinalize, OnInitialize, UncheckedOnRuntimeUpgrade};
use moonbeam_runtime::EvmForeignAssets;
use pallet_evm::FrameSystemAccountProvider;
use sp_weights::constants::WEIGHT_REF_TIME_PER_SECOND;
use xcm_primitives::AsAssetType;

pub(crate) fn on_runtime_upgrade() {
VersionUncheckedMigrateToV1::<Runtime>::on_runtime_upgrade();
Expand Down
5 changes: 4 additions & 1 deletion runtime/moonriver/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,10 @@ impl pallet_xcm_transactor::Config for Runtime {
type SovereignAccountDispatcherOrigin = EnsureRoot<AccountId>;
type CurrencyId = CurrencyId;
type AccountIdToLocation = AccountIdToLocation<AccountId>;
type CurrencyIdToLocation = CurrencyIdToLocation<AsAssetType<AssetId, AssetType, AssetManager>>;
type CurrencyIdToLocation = CurrencyIdToLocation<(
EvmForeignAssets,
AsAssetType<AssetId, AssetType, AssetManager>,
)>;
type XcmSender = XcmRouter;
type SelfLocation = SelfLocation;
type Weigher = XcmWeigher;
Expand Down
Loading
Loading