From 75b0c811d0b4d30e5bc13be3ee9809802a4103c6 Mon Sep 17 00:00:00 2001 From: Rust Ninja <102041955+RustNinja@users.noreply.github.com> Date: Tue, 4 Apr 2023 15:34:37 +0100 Subject: [PATCH] Statemint integration tests to cover USDT bidirectional reserve transfer Pendulum <-> Statemint (#196) * add statemint-runtime to integration tests * add Statemint to RelayNet as system chain 1000 * add statemine_transfer_asset_to_pendulum unit tests * check BOB balance in statemine_transfer_asset_to_pendulum test * add statemine_transfer_asset_to_statemint * rename statemine to statemint. because this is tests for polkadot net * add statemint_transfer_incorrect_asset_to_pendulum_fails * move pendulum and statemint configuration from lib.rs to setup.rs * move test from lib.rs to test.rs * move polkadot net configuration to polkadot_test_net * split tests, setup and polkadot_test_net to different files * remove unused import in all files * rename to pendulum-runtime-integration-tests * Revert "rename to pendulum-runtime-integration-tests" This reverts commit 2f18be69312712afbe64875988c7674429ca12ca. --- Cargo.lock | 136 +++++++ runtime/integration-tests/pendulum/Cargo.toml | 4 + runtime/integration-tests/pendulum/src/lib.rs | 334 +---------------- .../pendulum/src/polkadot_test_net.rs | 129 +++++++ .../integration-tests/pendulum/src/setup.rs | 113 ++++++ .../integration-tests/pendulum/src/tests.rs | 352 ++++++++++++++++++ 6 files changed, 738 insertions(+), 330 deletions(-) create mode 100644 runtime/integration-tests/pendulum/src/polkadot_test_net.rs create mode 100644 runtime/integration-tests/pendulum/src/setup.rs create mode 100644 runtime/integration-tests/pendulum/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 2931e95d5..07104e149 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6068,6 +6068,39 @@ dependencies = [ "libm 0.1.4", ] +[[package]] +name = "pallet-asset-tx-payment" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.37#f38bd6671d460293c93062cc1e4fe9e9e490cb29" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-transaction-payment", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-assets" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.37#f38bd6671d460293c93062cc1e4fe9e9e490cb29" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-aura" version = "4.0.0-dev" @@ -7010,6 +7043,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-uniques" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.37#f38bd6671d460293c93062cc1e4fe9e9e490cb29" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-utility" version = "4.0.0-dev" @@ -7128,6 +7176,32 @@ dependencies = [ "sp-std", ] +[[package]] +name = "parachains-common" +version = "1.0.0" +source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.37#09418fc04c2608b123f36ca80f16df3d2096753b" +dependencies = [ + "cumulus-primitives-utility", + "frame-support", + "frame-system", + "pallet-asset-tx-payment", + "pallet-assets", + "pallet-authorship", + "pallet-balances", + "pallet-collator-selection", + "parity-scale-codec", + "polkadot-primitives", + "scale-info", + "sp-consensus-aura", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "substrate-wasm-builder", + "xcm", + "xcm-executor", +] + [[package]] name = "parity-db" version = "0.4.6" @@ -12049,6 +12123,66 @@ dependencies = [ "spacewalk-primitives", ] +[[package]] +name = "statemint-runtime" +version = "1.0.0" +source = "git+https://github.com/paritytech/cumulus.git?branch=polkadot-v0.9.37#09418fc04c2608b123f36ca80f16df3d2096753b" +dependencies = [ + "cumulus-pallet-aura-ext", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-session-benchmarking", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "cumulus-primitives-timestamp", + "cumulus-primitives-utility", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-rpc-runtime-api", + "log", + "pallet-asset-tx-payment", + "pallet-assets", + "pallet-aura", + "pallet-authorship", + "pallet-balances", + "pallet-collator-selection", + "pallet-multisig", + "pallet-proxy", + "pallet-session", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-uniques", + "pallet-utility", + "pallet-xcm", + "parachain-info", + "parachains-common", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain", + "polkadot-runtime-common", + "polkadot-runtime-constants", + "scale-info", + "smallvec", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-core", + "sp-inherents", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std", + "sp-transaction-pool", + "sp-version", + "substrate-wasm-builder", + "xcm", + "xcm-builder", + "xcm-executor", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -14437,6 +14571,7 @@ name = "xcm-simulator-example" version = "0.1.0" dependencies = [ "cumulus-pallet-dmp-queue", + "cumulus-pallet-xcmp-queue", "frame-support", "frame-system", "orml-tokens 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library.git?branch=polkadot-v0.9.37)", @@ -14457,6 +14592,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", + "statemint-runtime", "xcm", "xcm-builder", "xcm-emulator", diff --git a/runtime/integration-tests/pendulum/Cargo.toml b/runtime/integration-tests/pendulum/Cargo.toml index cc513ffa9..ae634aa70 100644 --- a/runtime/integration-tests/pendulum/Cargo.toml +++ b/runtime/integration-tests/pendulum/Cargo.toml @@ -36,3 +36,7 @@ orml-tokens = {git = "https://github.com/open-web3-stack/open-runtime-module-lib cumulus-pallet-dmp-queue = {git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.37"} orml-xtokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.37" } pendulum-runtime = { path = "../../pendulum"} + +statemint-runtime = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.37" } + +cumulus-pallet-xcmp-queue = {git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.37"} diff --git a/runtime/integration-tests/pendulum/src/lib.rs b/runtime/integration-tests/pendulum/src/lib.rs index ac9c745b9..552378512 100644 --- a/runtime/integration-tests/pendulum/src/lib.rs +++ b/runtime/integration-tests/pendulum/src/lib.rs @@ -1,330 +1,4 @@ -use frame_support::{ - assert_ok, - traits::{fungibles::Inspect, GenesisBuild}, -}; -use pendulum_runtime::{Balances, PendulumCurrencyId, Runtime, System, Tokens}; -use polkadot_core_primitives::{AccountId, Balance, BlockNumber}; -use polkadot_parachain::primitives::Id as ParaId; -use polkadot_primitives::v2::{MAX_CODE_SIZE, MAX_POV_SIZE}; -use polkadot_runtime_parachains::configuration::HostConfiguration; -use sp_runtime::traits::AccountIdConversion; -use xcm::{ - latest::{ - AssetId, Fungibility, Junction, Junction::*, Junctions::*, MultiAsset, MultiLocation, - NetworkId, WeightLimit, - }, - v2::{Instruction::WithdrawAsset, Xcm}, - VersionedMultiLocation, -}; -const DOT_FEE: Balance = 3200000000; -use xcm_emulator::{ - decl_test_network, decl_test_parachain, decl_test_relay_chain, Junctions, TestExt, Weight, -}; - -pub const ALICE: [u8; 32] = [4u8; 32]; -pub const BOB: [u8; 32] = [5u8; 32]; -pub const INITIAL_BALANCE: u128 = 1_000_000_000; - -decl_test_relay_chain! { - pub struct Relay { - Runtime = polkadot_runtime::Runtime, - XcmConfig = polkadot_runtime::xcm_config::XcmConfig, - new_ext = relay_ext(), - } -} - -decl_test_parachain! { - pub struct PendulumParachain { - Runtime = pendulum_runtime::Runtime, - RuntimeOrigin = pendulum_runtime::RuntimeOrigin, - XcmpMessageHandler = pendulum_runtime::XcmpQueue, - DmpMessageHandler = pendulum_runtime::DmpQueue, - new_ext = para_ext_pendulum(2094), - } -} - -decl_test_network! { - pub struct MockNet { - relay_chain = Relay, - parachains = vec![ - (2094, PendulumParachain), - ], - } -} - -pub fn para_account_id(id: u32) -> polkadot_core_primitives::AccountId { - ParaId::from(id).into_account_truncating() -} - -pub fn relay_ext() -> sp_io::TestExternalities { - use polkadot_runtime::{Runtime, System}; - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![ - (AccountId::from(ALICE), dot(100000)), - (AccountId::from(BOB), dot(100)), - (ParaId::from(2094).into_account_truncating(), 10 * dot(100000)), - ], - } - .assimilate_storage(&mut t) - .unwrap(); - polkadot_runtime_parachains::configuration::GenesisConfig:: { - config: default_parachains_host_configuration(), - } - .assimilate_storage(&mut t) - .unwrap(); - >::assimilate_storage( - &pallet_xcm::GenesisConfig { safe_xcm_version: Some(2) }, - &mut t, - ) - .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext -} - -pub struct ExtBuilderPendulum { - balances: Vec<(AccountId, PendulumCurrencyId, Balance)>, - parachain_id: u32, -} -impl Default for ExtBuilderPendulum { - fn default() -> Self { - Self { balances: vec![], parachain_id: 2094 } - } -} - -pub fn para_ext_pendulum(parachain_id: u32) -> sp_io::TestExternalities { - ExtBuilderPendulum::default() - .balances(vec![]) - .parachain_id(parachain_id) - .build() -} - -impl ExtBuilderPendulum { - pub fn balances(mut self, balances: Vec<(AccountId, PendulumCurrencyId, Balance)>) -> Self { - self.balances = balances; - self - } - pub fn parachain_id(mut self, parachain_id: u32) -> Self { - self.parachain_id = parachain_id; - self - } - pub fn build(self) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - // let native_currency_id = Pendulum_runtime::Native::get(); - pallet_balances::GenesisConfig:: { - balances: vec![ - (AccountId::from(ALICE), INITIAL_BALANCE), - (AccountId::from(BOB), INITIAL_BALANCE), - ], - } - .assimilate_storage(&mut t) - .unwrap(); - - orml_tokens::GenesisConfig:: { - balances: vec![(AccountId::from(BOB), PendulumCurrencyId::XCM(0), dot(100))], - } - .assimilate_storage(&mut t) - .unwrap(); - >::assimilate_storage( - ¶chain_info::GenesisConfig { parachain_id: self.parachain_id.into() }, - &mut t, - ) - .unwrap(); - >::assimilate_storage( - &pallet_xcm::GenesisConfig { safe_xcm_version: Some(2) }, - &mut t, - ) - .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext - } -} - -fn default_parachains_host_configuration() -> HostConfiguration { - HostConfiguration { - minimum_validation_upgrade_delay: 5, - validation_upgrade_cooldown: 5u32, - validation_upgrade_delay: 5, - code_retention_period: 1200, - max_code_size: MAX_CODE_SIZE, - max_pov_size: MAX_POV_SIZE, - max_head_data_size: 32 * 1024, - group_rotation_frequency: 20, - chain_availability_period: 4, - thread_availability_period: 4, - max_upward_queue_count: 8, - max_upward_queue_size: 1024 * 1024, - max_downward_message_size: 1024, - ump_service_total_weight: Weight::from_ref_time(4 * 1_000_000_000), - max_upward_message_size: 50 * 1024, - max_upward_message_num_per_candidate: 5, - hrmp_sender_deposit: 0, - hrmp_recipient_deposit: 0, - hrmp_channel_max_capacity: 8, - hrmp_channel_max_total_size: 8 * 1024, - hrmp_max_parachain_inbound_channels: 4, - hrmp_max_parathread_inbound_channels: 4, - hrmp_channel_max_message_size: 1024 * 1024, - hrmp_max_parachain_outbound_channels: 4, - hrmp_max_parathread_outbound_channels: 4, - hrmp_max_message_num_per_candidate: 5, - dispute_period: 6, - no_show_slots: 2, - n_delay_tranches: 25, - needed_approvals: 2, - relay_vrf_modulo_samples: 2, - zeroth_delay_tranche_width: 0, - ..Default::default() - } -} - -pub fn dot(amount: Balance) -> Balance { - amount * one(9) -} - -pub fn one(decimals: u32) -> Balance { - 10u128.saturating_pow(decimals.into()) -} - -#[test] -fn transfer_polkadot_from_relay_chain_to_pendulum() { - MockNet::reset(); - - let transfer_amount: Balance = dot(20); - println!("transfer DOT amount : {} ", transfer_amount); - let mut balance_before = 0; - let mut orml_tokens_before = 0; - PendulumParachain::execute_with(|| { - balance_before = Balances::free_balance(&ALICE.into()); - println!("Alice balance_before {}", balance_before); - let orml_tokens_before = pendulum_runtime::Tokens::balance( - pendulum_runtime::PendulumCurrencyId::XCM(0), - &ALICE.into(), - ); - println!("Alice orml tokens DOT before {}", orml_tokens_before); - }); - - Relay::execute_with(|| { - assert_ok!(polkadot_runtime::XcmPallet::reserve_transfer_assets( - polkadot_runtime::RuntimeOrigin::signed(ALICE.into()), - Box::new(Parachain(2094).into().into()), - Box::new(Junction::AccountId32 { network: NetworkId::Any, id: ALICE }.into().into()), - Box::new((Here, transfer_amount).into()), - 0 - )); - }); - - Relay::execute_with(|| { - use polkadot_runtime::{RuntimeEvent, System}; - for i in System::events().iter() { - println!("polkadot_runtime {:?}", i); - } - }); - - println!("____________________________________________________"); - - PendulumParachain::execute_with(|| { - use pendulum_runtime::{RuntimeEvent, System, Tokens}; - for i in System::events().iter() { - println!(" Pendulum_runtime {:?}", i); - } - - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::Tokens(orml_tokens::Event::Deposited { .. }) - ))); - - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { .. }) - ))); - }); - - PendulumParachain::execute_with(|| { - assert_eq!( - pendulum_runtime::Tokens::balance( - pendulum_runtime::PendulumCurrencyId::XCM(0), - &ALICE.into() - ), - orml_tokens_before + transfer_amount - DOT_FEE - ); - }); -} - -#[test] -fn transfer_polkadot_from_pendulum_to_relay_chain() { - MockNet::reset(); - - let transfer_dot_amount: Balance = dot(10); - let FEE = 421434140; - - Relay::execute_with(|| { - let after_bob_free_balance = polkadot_runtime::Balances::free_balance(&BOB.into()); - // println!("BOB DOT BEFORE balance on relay chain {} ", after_bob_free_balance); - assert_eq!(after_bob_free_balance, dot(100)); - }); - - PendulumParachain::execute_with(|| { - assert_ok!(pendulum_runtime::XTokens::transfer( - pendulum_runtime::RuntimeOrigin::signed(BOB.into()), - pendulum_runtime::PendulumCurrencyId::XCM(0), - transfer_dot_amount, - Box::new( - MultiLocation::new( - 1, - Junctions::X1(Junction::AccountId32 { id: BOB, network: NetworkId::Any }) - ) - .into() - ), - WeightLimit::Limited(4_000_000_000), - )); - }); - - PendulumParachain::execute_with(|| { - use pendulum_runtime::{RuntimeEvent, System}; - // for i in System::events().iter() { - // println!(" Pendulum_runtime {:?}", i); - // } - - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::Tokens(orml_tokens::Event::Withdrawn { .. }) - ))); - - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::XTokens(orml_xtokens::Event::TransferredMultiAssets { .. }) - ))); - }); - - Relay::execute_with(|| { - use polkadot_runtime::{RuntimeEvent, System}; - - // for i in System::events().iter() { - // println!("polkadot_runtime {:?}", i); - // } - - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) - ))); - - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) - ))); - - assert!(System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::Ump(polkadot_runtime_parachains::ump::Event::ExecutedUpward { .. }) - ))); - }); - - Relay::execute_with(|| { - let after_bob_free_balance = polkadot_runtime::Balances::free_balance(&BOB.into()); - // println!("BOB DOT AFTER balance on relay chain {} ", after_bob_free_balance); - assert_eq!(after_bob_free_balance, dot(100) + transfer_dot_amount - FEE); - }); -} +#![cfg(test)] +mod polkadot_test_net; +mod setup; +mod tests; diff --git a/runtime/integration-tests/pendulum/src/polkadot_test_net.rs b/runtime/integration-tests/pendulum/src/polkadot_test_net.rs new file mode 100644 index 000000000..bba21cf92 --- /dev/null +++ b/runtime/integration-tests/pendulum/src/polkadot_test_net.rs @@ -0,0 +1,129 @@ +use crate::setup::{dot, ExtBuilderPendulum, ExtStatemintBuilder, ALICE, BOB}; +use frame_support::traits::GenesisBuild; +use polkadot_core_primitives::{AccountId, BlockNumber}; +use polkadot_parachain::primitives::Id as ParaId; +use polkadot_primitives::v2::{MAX_CODE_SIZE, MAX_POV_SIZE}; +use polkadot_runtime_parachains::configuration::HostConfiguration; +use sp_runtime::traits::AccountIdConversion; +use xcm_emulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, Weight}; + +decl_test_relay_chain! { + pub struct Relay { + Runtime = polkadot_runtime::Runtime, + XcmConfig = polkadot_runtime::xcm_config::XcmConfig, + new_ext = relay_ext(), + } +} + +decl_test_parachain! { + pub struct PendulumParachain { + Runtime = pendulum_runtime::Runtime, + RuntimeOrigin = pendulum_runtime::RuntimeOrigin, + XcmpMessageHandler = pendulum_runtime::XcmpQueue, + DmpMessageHandler = pendulum_runtime::DmpQueue, + new_ext = para_ext_pendulum(2094), + } +} + +decl_test_parachain! { + pub struct Statemint { + Runtime = statemint_runtime::Runtime, + RuntimeOrigin = statemint_runtime::RuntimeOrigin, + XcmpMessageHandler = statemint_runtime::XcmpQueue, + DmpMessageHandler = statemint_runtime::DmpQueue, + new_ext = para_ext_statemint(1000), + } +} + +decl_test_network! { + pub struct MockNet { + relay_chain = Relay, + parachains = vec![ + (1000, Statemint), + (2094, PendulumParachain), + ], + } +} + +pub fn para_account_id(id: u32) -> polkadot_core_primitives::AccountId { + ParaId::from(id).into_account_truncating() +} + +pub fn relay_ext() -> sp_io::TestExternalities { + use polkadot_runtime::{Runtime, System}; + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + pallet_balances::GenesisConfig:: { + balances: vec![ + (AccountId::from(ALICE), dot(100000)), + (AccountId::from(BOB), dot(100)), + (para_account_id(2094), 10 * dot(100000)), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + polkadot_runtime_parachains::configuration::GenesisConfig:: { + config: default_parachains_host_configuration(), + } + .assimilate_storage(&mut t) + .unwrap(); + >::assimilate_storage( + &pallet_xcm::GenesisConfig { safe_xcm_version: Some(2) }, + &mut t, + ) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +fn default_parachains_host_configuration() -> HostConfiguration { + HostConfiguration { + minimum_validation_upgrade_delay: 5, + validation_upgrade_cooldown: 5u32, + validation_upgrade_delay: 5, + code_retention_period: 1200, + max_code_size: MAX_CODE_SIZE, + max_pov_size: MAX_POV_SIZE, + max_head_data_size: 32 * 1024, + group_rotation_frequency: 20, + chain_availability_period: 4, + thread_availability_period: 4, + max_upward_queue_count: 8, + max_upward_queue_size: 1024 * 1024, + max_downward_message_size: 1024, + ump_service_total_weight: Weight::from_ref_time(4 * 1_000_000_000), + max_upward_message_size: 50 * 1024, + max_upward_message_num_per_candidate: 5, + hrmp_sender_deposit: 0, + hrmp_recipient_deposit: 0, + hrmp_channel_max_capacity: 8, + hrmp_channel_max_total_size: 8 * 1024, + hrmp_max_parachain_inbound_channels: 4, + hrmp_max_parathread_inbound_channels: 4, + hrmp_channel_max_message_size: 1024 * 1024, + hrmp_max_parachain_outbound_channels: 4, + hrmp_max_parathread_outbound_channels: 4, + hrmp_max_message_num_per_candidate: 5, + dispute_period: 6, + no_show_slots: 2, + n_delay_tranches: 25, + needed_approvals: 2, + relay_vrf_modulo_samples: 2, + zeroth_delay_tranche_width: 0, + ..Default::default() + } +} + +pub fn para_ext_pendulum(parachain_id: u32) -> sp_io::TestExternalities { + ExtBuilderPendulum::default() + .balances(vec![]) + .parachain_id(parachain_id) + .build() +} + +pub fn para_ext_statemint(parachain_id: u32) -> sp_io::TestExternalities { + ExtStatemintBuilder::default() + .balances(vec![]) + .parachain_id(parachain_id) + .build() +} diff --git a/runtime/integration-tests/pendulum/src/setup.rs b/runtime/integration-tests/pendulum/src/setup.rs new file mode 100644 index 000000000..4ecec011c --- /dev/null +++ b/runtime/integration-tests/pendulum/src/setup.rs @@ -0,0 +1,113 @@ +use frame_support::traits::GenesisBuild; +use pendulum_runtime::{PendulumCurrencyId, Runtime, System}; +use polkadot_core_primitives::{AccountId, Balance}; + +pub fn dot(amount: Balance) -> Balance { + amount * 10u128.saturating_pow(9) +} +pub const ALICE: [u8; 32] = [4u8; 32]; +pub const BOB: [u8; 32] = [5u8; 32]; +pub const INITIAL_BALANCE: u128 = 1_000_000_000; + +pub struct ExtBuilderPendulum { + balances: Vec<(AccountId, PendulumCurrencyId, Balance)>, + parachain_id: u32, +} +impl Default for ExtBuilderPendulum { + fn default() -> Self { + Self { balances: vec![], parachain_id: 2094 } + } +} + +impl ExtBuilderPendulum { + pub fn balances(mut self, balances: Vec<(AccountId, PendulumCurrencyId, Balance)>) -> Self { + self.balances = balances; + self + } + pub fn parachain_id(mut self, parachain_id: u32) -> Self { + self.parachain_id = parachain_id; + self + } + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + pallet_balances::GenesisConfig:: { + balances: vec![ + (AccountId::from(ALICE), INITIAL_BALANCE), + (AccountId::from(BOB), INITIAL_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + orml_tokens::GenesisConfig:: { + balances: vec![(AccountId::from(BOB), PendulumCurrencyId::XCM(0), dot(100))], + } + .assimilate_storage(&mut t) + .unwrap(); + >::assimilate_storage( + ¶chain_info::GenesisConfig { parachain_id: self.parachain_id.into() }, + &mut t, + ) + .unwrap(); + >::assimilate_storage( + &pallet_xcm::GenesisConfig { safe_xcm_version: Some(2) }, + &mut t, + ) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext + } +} + +pub struct ExtStatemintBuilder { + balances: Vec<(AccountId, u128, Balance)>, + parachain_id: u32, +} + +impl Default for ExtStatemintBuilder { + fn default() -> Self { + Self { balances: vec![], parachain_id: 1000 } + } +} + +impl ExtStatemintBuilder { + pub fn balances(mut self, balances: Vec<(AccountId, u128, Balance)>) -> Self { + self.balances = balances; + self + } + + #[allow(dead_code)] + pub fn parachain_id(mut self, parachain_id: u32) -> Self { + self.parachain_id = parachain_id; + self + } + + pub fn build(self) -> sp_io::TestExternalities { + use statemint_runtime::Runtime as StatemintRuntime; + + let mut t = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap(); + + pallet_balances::GenesisConfig:: { balances: vec![] } + .assimilate_storage(&mut t) + .unwrap(); + + >::assimilate_storage( + ¶chain_info::GenesisConfig { parachain_id: self.parachain_id.into() }, + &mut t, + ) + .unwrap(); + + >::assimilate_storage( + &pallet_xcm::GenesisConfig { safe_xcm_version: Some(2) }, + &mut t, + ) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext + } +} diff --git a/runtime/integration-tests/pendulum/src/tests.rs b/runtime/integration-tests/pendulum/src/tests.rs new file mode 100644 index 000000000..2037fcee8 --- /dev/null +++ b/runtime/integration-tests/pendulum/src/tests.rs @@ -0,0 +1,352 @@ +use crate::{polkadot_test_net::*, setup::*}; +use frame_support::{ + assert_ok, + traits::{fungible::Mutate, fungibles::Inspect, Currency}, +}; +use pendulum_runtime::{Balances, PendulumCurrencyId, RuntimeOrigin, Tokens, XTokens}; +use sp_runtime::{traits::AccountIdConversion, MultiAddress}; +use xcm::latest::{Junction, Junction::*, Junctions::*, MultiLocation, NetworkId, WeightLimit}; +use xcm_emulator::{Junctions, TestExt}; + +use polkadot_core_primitives::{AccountId, Balance}; +use polkadot_parachain::primitives::Sibling; + +const DOT_FEE: Balance = 3200000000; +const ASSET_ID: u32 = 1984; //Real USDT Asset ID from Statemint +const INCORRECT_ASSET_ID: u32 = 0; +pub const UNIT: Balance = 1_000_000_000_000; +pub const TEN: Balance = 10_000_000_000_000; +const FEE: u128 = 421434140; + +#[test] +fn transfer_polkadot_from_relay_chain_to_pendulum() { + MockNet::reset(); + + let transfer_amount: Balance = dot(20); + let mut orml_tokens_before = 0; + PendulumParachain::execute_with(|| { + orml_tokens_before = pendulum_runtime::Tokens::balance( + pendulum_runtime::PendulumCurrencyId::XCM(0), + &ALICE.into(), + ); + }); + + Relay::execute_with(|| { + assert_ok!(polkadot_runtime::XcmPallet::reserve_transfer_assets( + polkadot_runtime::RuntimeOrigin::signed(ALICE.into()), + Box::new(Parachain(2094).into().into()), + Box::new(Junction::AccountId32 { network: NetworkId::Any, id: ALICE }.into().into()), + Box::new((Here, transfer_amount).into()), + 0 + )); + }); + + PendulumParachain::execute_with(|| { + use pendulum_runtime::{RuntimeEvent, System}; + + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::Tokens(orml_tokens::Event::Deposited { .. }) + ))); + + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::DmpQueue(cumulus_pallet_dmp_queue::Event::ExecutedDownward { .. }) + ))); + }); + + PendulumParachain::execute_with(|| { + assert_eq!( + pendulum_runtime::Tokens::balance( + pendulum_runtime::PendulumCurrencyId::XCM(0), + &ALICE.into() + ), + orml_tokens_before + transfer_amount - DOT_FEE + ); + }); +} + +#[test] +fn transfer_polkadot_from_pendulum_to_relay_chain() { + MockNet::reset(); + + let transfer_dot_amount: Balance = dot(10); + + Relay::execute_with(|| { + let after_bob_free_balance = polkadot_runtime::Balances::free_balance(&BOB.into()); + assert_eq!(after_bob_free_balance, dot(100)); + }); + + PendulumParachain::execute_with(|| { + assert_ok!(pendulum_runtime::XTokens::transfer( + pendulum_runtime::RuntimeOrigin::signed(BOB.into()), + pendulum_runtime::PendulumCurrencyId::XCM(0), + transfer_dot_amount, + Box::new( + MultiLocation::new( + 1, + Junctions::X1(Junction::AccountId32 { id: BOB, network: NetworkId::Any }) + ) + .into() + ), + WeightLimit::Limited(4_000_000_000), + )); + }); + + PendulumParachain::execute_with(|| { + use pendulum_runtime::{RuntimeEvent, System}; + + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::Tokens(orml_tokens::Event::Withdrawn { .. }) + ))); + + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::XTokens(orml_xtokens::Event::TransferredMultiAssets { .. }) + ))); + }); + + Relay::execute_with(|| { + use polkadot_runtime::{RuntimeEvent, System}; + + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::Balances(pallet_balances::Event::Withdraw { .. }) + ))); + + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::Balances(pallet_balances::Event::Deposit { .. }) + ))); + + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::Ump(polkadot_runtime_parachains::ump::Event::ExecutedUpward { .. }) + ))); + }); + + Relay::execute_with(|| { + let after_bob_free_balance = polkadot_runtime::Balances::free_balance(&BOB.into()); + assert_eq!(after_bob_free_balance, dot(100) + transfer_dot_amount - FEE); + }); +} + +#[test] +fn statemint_transfer_incorrect_asset_to_pendulum_fails() { + let para_2094: AccountId = Sibling::from(2094).into_account_truncating(); + + PendulumParachain::execute_with(|| { + assert_eq!( + pendulum_runtime::Tokens::balance( + pendulum_runtime::PendulumCurrencyId::XCM(1), + &BOB.into() + ), + 0 + ); + }); + + Statemint::execute_with(|| { + use statemint_runtime::*; + + let origin = RuntimeOrigin::signed(ALICE.into()); + Balances::make_free_balance_be(&ALICE.into(), TEN); + Balances::make_free_balance_be(&BOB.into(), UNIT); + + // If using non root, create custom asset cost 0.1 Dot + // We're using force_create here to make sure asset is sufficient. + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + INCORRECT_ASSET_ID.into(), + MultiAddress::Id(ALICE.into()), + true, + UNIT / 100 + )); + + assert_ok!(Assets::mint( + origin.clone(), + INCORRECT_ASSET_ID.into(), + MultiAddress::Id(ALICE.into()), + 1000 * UNIT + )); + + // need to have some DOT to be able to receive user assets + Balances::make_free_balance_be(¶_2094, UNIT); + + assert_ok!(PolkadotXcm::limited_reserve_transfer_assets( + origin.clone(), + Box::new(MultiLocation::new(1, X1(Parachain(2094))).into()), + Box::new(Junction::AccountId32 { id: BOB, network: NetworkId::Any }.into().into()), + Box::new( + (X2(PalletInstance(50), GeneralIndex(INCORRECT_ASSET_ID as u128)), TEN).into() + ), + 0, + WeightLimit::Unlimited + )); + + assert_eq!(990 * UNIT, Assets::balance(INCORRECT_ASSET_ID, &AccountId::from(ALICE))); + assert_eq!(0, Assets::balance(INCORRECT_ASSET_ID, &AccountId::from(BOB))); + + assert_eq!(TEN, Assets::balance(INCORRECT_ASSET_ID, ¶_2094)); + // the DOT balance of sibling parachain sovereign account is not changed + assert_eq!(UNIT, Balances::free_balance(¶_2094)); + }); + + // Rerun the Statemint::execute to actually send the egress message via XCM + Statemint::execute_with(|| {}); + + PendulumParachain::execute_with(|| { + use pendulum_runtime::{RuntimeEvent, System}; + + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Fail { + message_hash: _, + error: xcm::v2::Error::FailedToTransactAsset(..), + weight: _ + }) + ))); + }); +} + +#[test] +fn statemint_transfer_asset_to_pendulum() { + let para_2094: AccountId = Sibling::from(2094).into_account_truncating(); + + PendulumParachain::execute_with(|| { + assert_eq!( + pendulum_runtime::Tokens::balance( + pendulum_runtime::PendulumCurrencyId::XCM(1), + &BOB.into() + ), + 0 + ); + }); + + Statemint::execute_with(|| { + use statemint_runtime::*; + + let origin = RuntimeOrigin::signed(ALICE.into()); + Balances::make_free_balance_be(&ALICE.into(), TEN); + Balances::make_free_balance_be(&BOB.into(), UNIT); + + // If using non root, create custom asset cost 0.1 Dot + // We're using force_create here to make sure asset is sufficient. + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + ASSET_ID.into(), + MultiAddress::Id(ALICE.into()), + true, + UNIT / 100 + )); + + assert_ok!(Assets::mint( + origin.clone(), + ASSET_ID.into(), + MultiAddress::Id(ALICE.into()), + 1000 * UNIT + )); + + // need to have some DOT to be able to receive user assets + Balances::make_free_balance_be(¶_2094, UNIT); + + assert_ok!(PolkadotXcm::limited_reserve_transfer_assets( + origin.clone(), + Box::new(MultiLocation::new(1, X1(Parachain(2094))).into()), + Box::new(Junction::AccountId32 { id: BOB, network: NetworkId::Any }.into().into()), + Box::new((X2(PalletInstance(50), GeneralIndex(ASSET_ID as u128)), TEN).into()), + 0, + WeightLimit::Unlimited + )); + + assert_eq!(990 * UNIT, Assets::balance(ASSET_ID, &AccountId::from(ALICE))); + assert_eq!(0, Assets::balance(ASSET_ID, &AccountId::from(BOB))); + + assert_eq!(TEN, Assets::balance(ASSET_ID, ¶_2094)); + // the DOT balance of sibling parachain sovereign account is not changed + assert_eq!(UNIT, Balances::free_balance(¶_2094)); + }); + + // Rerun the Statemint::execute to actually send the egress message via XCM + Statemint::execute_with(|| {}); + + PendulumParachain::execute_with(|| { + use pendulum_runtime::{RuntimeEvent, System}; + for i in System::events().iter() { + println!(" Pendulum_runtime {:?}", i); + } + + assert!(System::events() + .iter() + .any(|r| matches!(r.event, RuntimeEvent::Tokens(orml_tokens::Event::Endowed { .. })))); + + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::Tokens(orml_tokens::Event::Deposited { .. }) + ))); + + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) + ))); + + assert_eq!( + pendulum_runtime::Tokens::balance( + pendulum_runtime::PendulumCurrencyId::XCM(1), + &BOB.into() + ), + TEN + ); + }); +} + +#[test] +fn statemint_transfer_asset_to_statemint() { + statemint_transfer_asset_to_pendulum(); + + Statemint::execute_with(|| {}); + + PendulumParachain::execute_with(|| { + assert_eq!(TEN, Tokens::balance(PendulumCurrencyId::XCM(1), &AccountId::from(BOB))); + // ensure sender has enough PEN balance to be charged as fee + assert_ok!(Balances::mint_into(&AccountId::from(BOB), TEN)); + + assert_ok!(XTokens::transfer( + RuntimeOrigin::signed(BOB.into()), + PendulumCurrencyId::XCM(1), + UNIT * 1, + Box::new( + MultiLocation::new( + 1, + X2( + Parachain(1000), + Junction::AccountId32 { network: NetworkId::Any, id: BOB.into() } + ) + ) + .into() + ), + WeightLimit::Limited(10_000_000_000), + )); + + assert_eq!( + TEN - 1 * UNIT, //inital balance - one unit + Tokens::balance(PendulumCurrencyId::XCM(1), &AccountId::from(BOB)) + ); + + use pendulum_runtime::{RuntimeEvent, System}; + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) + ))); + + // assert_eq!(TEN - ksm_fee_amount, Tokens::free_balance(KSM, &AccountId::from(BOB))); + }); + + Statemint::execute_with(|| { + use statemint_runtime::*; + + // https://github.com/paritytech/cumulus/pull/1278 support using self sufficient asset + // for paying xcm execution fee on Statemint. + assert_eq!(990_000_000_000, Assets::balance(ASSET_ID, &AccountId::from(BOB))); + }); +}