diff --git a/Cargo.lock b/Cargo.lock index e17b09b97..830e9023b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8011,15 +8011,21 @@ dependencies = [ "frame-support", "frame-system", "log", + "orml-traits", + "orml-xcm-support", + "orml-xtokens", + "pallet-assets", "pallet-balances", "pallet-message-queue", "pallet-uniques", "pallet-xcm", "parity-scale-codec", + "polkadex-primitives", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-runtime-parachains", "scale-info", + "smallvec", "sp-core", "sp-io", "sp-runtime", @@ -8028,6 +8034,10 @@ dependencies = [ "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", + "thea", + "thea-message-handler", + "thea-primitives", + "xcm-helper", "xcm-simulator", ] diff --git a/Cargo.toml b/Cargo.toml index 667dd71d5..5d4caecc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -187,7 +187,6 @@ serde = { version = "1.0.171", default-features = false, features = ["derive"] } serde_json = { version = "1.0.102", default-features = false, features = ["alloc"] } hash-db = { version = "0.16.0", default-features = false } trie-db = { version = "0.27.1", default-features = false } - #Parachain Dependencies cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0", default-features = false } orml-xtokens = { git = "https://github.com/Polkadex-Substrate/orml-1.1.0.git", branch = "master", default-features = false } #FIXME: Remove rev @@ -204,7 +203,7 @@ cumulus-pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk", branc cumulus-pallet-xcmp-queue = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0", default-features = false } cumulus-primitives-timestamp = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0", default-features = false } cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0", default-features = false } -#Here Oeml +#Here Orml orml-xcm-support = { git = "https://github.com/Polkadex-Substrate/orml-1.1.0.git", branch = "master", default-features = false } #FIXME: Remove rev pallet-aura = { git = "https://github.com/paritytech/polkadot-sdk", default-features = false, branch = "release-polkadot-v1.1.0" } pallet-collator-selection = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0", default-features = false } diff --git a/check-all-ci-tests.sh b/check-all-ci-tests.sh index 9b7827e3c..807b12b43 100755 --- a/check-all-ci-tests.sh +++ b/check-all-ci-tests.sh @@ -18,7 +18,7 @@ cargo fmt --check || exit RUSTFLAGS="-D warnings" cargo build || exit -cargo build --features try-runtime || exit +RUSTFLAGS="-D warnings" cargo build --features try-runtime || exit cargo build --features runtime-benchmarks || exit ./target/debug/polkadex-node benchmark pallet --pallet "*" --extrinsic "*" --steps 2 --repeat 1 || exit cargo clippy -- -D warnings || exit diff --git a/pallets/thea-council/src/mock.rs b/pallets/thea-council/src/mock.rs index 5eceef617..7adb46d39 100644 --- a/pallets/thea-council/src/mock.rs +++ b/pallets/thea-council/src/mock.rs @@ -144,6 +144,7 @@ impl xcm_helper::Config for Test { type SubstrateNetworkId = frame_support::traits::ConstU8<0>; type NativeAssetId = NativeAssetId; type WeightInfo = xcm_helper::weights::WeightInfo; + type SiblingAddressConverter = (); } parameter_types! { diff --git a/pallets/xcm-helper/src/lib.rs b/pallets/xcm-helper/src/lib.rs index f999f690f..f2ddd6090 100644 --- a/pallets/xcm-helper/src/lib.rs +++ b/pallets/xcm-helper/src/lib.rs @@ -222,6 +222,8 @@ pub mod pallet { type NativeAssetId: Get; /// Weight Info type WeightInfo: XcmHelperWeightInfo; + /// Sibling Address Converter + type SiblingAddressConverter: xcm_executor::traits::ConvertLocation; } /// Pending Withdrawals @@ -273,6 +275,8 @@ pub mod pallet { polkadex_primitives::AssetId, ExtraData, ), + /// Sibling Deposit + SiblingDeposit(Box, Box), /// Asset Withdraw using XCM /// parameters. [id, asset_id] AssetWithdrawn(H160, polkadex_primitives::AssetId), @@ -286,6 +290,16 @@ pub mod pallet { NativeAssetIdMappingRegistered(polkadex_primitives::AssetId, Box), /// Whitelisted Token removed WhitelistedTokenRemoved(polkadex_primitives::AssetId), + /// Not able too decode Destination + NotAbleToDecodeDestination, + /// Not able to mint token + NotAbleToMintToken, + /// Not able to Make Xcm Call + NotAbleToMakeXcmCall, + /// Not able to handle Destination + NotAbleToHandleDestination, + /// Xcm sibling deposit failed + XcmSiblingDepositFailed(Box, Box), } // Errors inform users that something went wrong. @@ -407,31 +421,58 @@ pub mod pallet { ) -> xcm::latest::Result { // Create approved deposit let MultiAsset { id, fun } = what; - - let (recipient, extra) = - extract_data_from_multilocation(*who).ok_or(XcmError::FailedToDecode)?; - - let amount: u128 = Self::get_amount(fun).ok_or(XcmError::Trap(101))?; let asset_id = Self::generate_asset_id_for_parachain(*id); - let deposit: Deposit = Deposit { - id: Self::new_random_id(None), - recipient: recipient.into(), - asset_id, - amount, - extra: extra.clone(), - }; - - let parachain_network_id = T::SubstrateNetworkId::get(); - let unique_id = deposit.id; - T::Executor::execute_withdrawals(parachain_network_id, sp_std::vec![deposit].encode()) + if let Some(account) = T::SiblingAddressConverter::convert_location(who) { + let pallet_account: T::AccountId = + T::AssetHandlerPalletId::get().into_account_truncating(); + let amount: u128 = Self::get_amount(fun).ok_or(XcmError::Trap(101))?; + if Self::resolve_deposit_parachain( + asset_id.into(), + amount, + &account, + pallet_account.clone(), + 1u128, + pallet_account.clone(), + ) + .is_err() + { + log::error!(target:"xcm-helper","Deposit Failed"); + Self::deposit_event(Event::::XcmSiblingDepositFailed( + Box::new(*who), + Box::new(what.clone()), + )); + }; + Self::deposit_event(Event::::SiblingDeposit( + Box::new(*who), + Box::new(what.clone()), + )); + } else { + let (recipient, extra) = + extract_data_from_multilocation(*who).ok_or(XcmError::Trap(99))?; + let amount: u128 = Self::get_amount(fun).ok_or(XcmError::Trap(101))?; + let asset_id = Self::generate_asset_id_for_parachain(*id); + let deposit: Deposit = Deposit { + id: Self::new_random_id(None), + recipient: recipient.into(), + asset_id, + amount, + extra: extra.clone(), + }; + let parachain_network_id = T::SubstrateNetworkId::get(); + let unique_id = deposit.id; + T::Executor::execute_withdrawals( + parachain_network_id, + sp_std::vec![deposit].encode(), + ) .map_err(|_| XcmError::Trap(102))?; - Self::deposit_event(Event::::AssetDeposited( - unique_id, - Box::new(*who), - Box::new(what.clone()), - asset_id, - extra, - )); + Self::deposit_event(Event::::AssetDeposited( + unique_id, + Box::new(*who), + Box::new(what.clone()), + asset_id, + extra, + )); + } Ok(()) } @@ -443,13 +484,19 @@ pub mod pallet { _context: Option<&XcmContext>, ) -> sp_std::result::Result { let MultiAsset { id: _, fun } = what; - let who = T::AccountIdConvert::convert_location(who).ok_or(XcmError::FailedToDecode)?; + let who_account = + T::AccountIdConvert::convert_location(who).ok_or(XcmError::FailedToDecode)?; let amount: u128 = Self::get_amount(fun).ok_or(XcmError::Trap(101))?; let asset_id = Self::generate_asset_id_for_parachain(what.id); let pallet_account: T::AccountId = T::AssetHandlerPalletId::get().into_account_truncating(); - Self::resolver_withdraw(asset_id.into(), amount.saturated_into(), &who, pallet_account) - .map_err(|_| XcmError::Trap(25))?; + Self::resolver_withdraw_parachain( + asset_id.into(), + amount.saturated_into(), + &who_account, + pallet_account, + ) + .map_err(|_| XcmError::Trap(110))?; Ok(what.clone().into()) } @@ -504,7 +551,7 @@ pub mod pallet { .ok_or(Error::::UnableToConvertToAccount)?; let pallet_account: T::AccountId = T::AssetHandlerPalletId::get().into_account_truncating(); - Self::resolver_deposit( + Self::resolve_deposit_parachain( withdrawal.asset_id.into(), withdrawal.amount, &destination_account, @@ -565,7 +612,9 @@ pub mod pallet { == AssetId::Concrete(MultiLocation { parents: 1, interior: Junctions::X1(Parachain(T::ParachainId::get())), - }) { + }) || asset + == AssetId::Concrete(MultiLocation { parents: 0, interior: Junctions::Here }) + { return polkadex_primitives::AssetId::Polkadex; } // If it's not native, then hash and generate the asset id @@ -618,6 +667,10 @@ pub mod pallet { >::insert(block_no, vec![withdrawal]); } + pub fn insert_parachain_asset(asset: AssetId, asset_id: polkadex_primitives::AssetId) { + >::insert(asset_id, asset); + } + pub fn handle_new_pending_withdrawals(n: BlockNumberFor) { let mut failed_withdrawal: Vec = Vec::default(); >::mutate(n, |withdrawals| { @@ -630,6 +683,8 @@ pub mod pallet { Err(_) => { failed_withdrawal.push(withdrawal); log::error!(target:"xcm-helper","Withdrawal failed: Not able to decode destination"); + // Emit Event + Self::deposit_event(Event::::NotAbleToDecodeDestination); continue; }, }; @@ -651,7 +706,7 @@ pub mod pallet { }; let pallet_account: T::AccountId = T::AssetHandlerPalletId::get().into_account_truncating(); - if Self::resolver_deposit( + if Self::resolve_deposit_parachain( withdrawal.asset_id.into(), withdrawal.amount, &pallet_account, @@ -663,9 +718,10 @@ pub mod pallet { { failed_withdrawal.push(withdrawal.clone()); log::error!(target:"xcm-helper","Withdrawal failed: Not able to mint token"); + Self::deposit_event(Event::::NotAbleToMintToken); }; // Deposit Fee - if Self::resolver_deposit( + if Self::resolve_deposit_parachain( fee_asset_id.into(), fee_amount, &pallet_account, @@ -677,22 +733,23 @@ pub mod pallet { { failed_withdrawal.push(withdrawal.clone()); log::error!(target:"xcm-helper","Withdrawal failed: Not able to mint token"); + Self::deposit_event(Event::::NotAbleToMintToken); }; - if orml_xtokens::module::Pallet::::transfer_multiassets( - RawOrigin::Signed( - T::AssetHandlerPalletId::get() - .into_account_truncating(), - ) - .into(), - Box::new(vec![multi_asset, fee_multi_asset].into()), - 1, - Box::new(destination.clone()), - cumulus_primitives_core::WeightLimit::Unlimited, - ) - .is_err() - { + if let Err(err) = + orml_xtokens::module::Pallet::::transfer_multiassets( + RawOrigin::Signed( + T::AssetHandlerPalletId::get() + .into_account_truncating(), + ) + .into(), + Box::new(vec![multi_asset, fee_multi_asset].into()), + 1, + Box::new(destination.clone()), + cumulus_primitives_core::WeightLimit::Unlimited, + ) { failed_withdrawal.push(withdrawal.clone()); - log::error!(target:"xcm-helper","Withdrawal failed: Not able to make xcm calls"); + Self::deposit_event(Event::::NotAbleToMakeXcmCall); + log::error!(target:"xcm-helper","Withdrawal failed: Not able to make xcm calls: {:?}", err); } else { // Deposit event Self::deposit_event(Event::::AssetWithdrawn( @@ -708,8 +765,42 @@ pub mod pallet { }; let pallet_account: T::AccountId = T::AssetHandlerPalletId::get().into_account_truncating(); + let destination_location = match destination { + VersionedMultiLocation::V3(location) => location, + _ => { + failed_withdrawal.push(withdrawal); + log::error!(target:"xcm-helper","Withdrawal failed: Not able to decode destination"); + Self::deposit_event(Event::::NotAbleToDecodeDestination); + continue; + }, + }; + if let ( + Some(soverign_account), + polkadex_primitives::AssetId::Polkadex, + ) = ( + T::SiblingAddressConverter::convert_location( + &destination_location, + ), + withdrawal.asset_id, + ) { + // Deposit to Sovereign Account + if Self::resolve_deposit_parachain( + withdrawal.asset_id.into(), + withdrawal.amount, + &soverign_account, + pallet_account.clone(), + 1u128, + pallet_account.clone(), + ) + .is_err() + { + failed_withdrawal.push(withdrawal.clone()); + Self::deposit_event(Event::::NotAbleToMintToken); + log::error!(target:"xcm-helper","Withdrawal failed: Not able to mint token"); + }; + } // Mint - if Self::resolver_deposit( + if Self::resolve_deposit_parachain( withdrawal.asset_id.into(), withdrawal.amount, &pallet_account, @@ -720,22 +811,24 @@ pub mod pallet { .is_err() { failed_withdrawal.push(withdrawal.clone()); + Self::deposit_event(Event::::NotAbleToMintToken); log::error!(target:"xcm-helper","Withdrawal failed: Not able to mint token"); }; - if orml_xtokens::module::Pallet::::transfer_multiassets( - RawOrigin::Signed( - T::AssetHandlerPalletId::get().into_account_truncating(), - ) - .into(), - Box::new(multi_asset.into()), - 0, - Box::new(destination.clone()), - cumulus_primitives_core::WeightLimit::Unlimited, - ) - .is_err() - { + if let Err(err) = + orml_xtokens::module::Pallet::::transfer_multiassets( + RawOrigin::Signed( + T::AssetHandlerPalletId::get() + .into_account_truncating(), + ) + .into(), + Box::new(multi_asset.into()), + 0, + Box::new(destination.clone()), + cumulus_primitives_core::WeightLimit::Unlimited, + ) { failed_withdrawal.push(withdrawal.clone()); - log::error!(target:"xcm-helper","Withdrawal failed: Not able to make xcm calls"); + log::error!(target:"xcm-helper","Withdrawal failed: Not able to make xcm calls {:?}", err); + Self::deposit_event(Event::::NotAbleToMakeXcmCall); } else { // Deposit event Self::deposit_event(Event::::AssetWithdrawn( @@ -744,10 +837,13 @@ pub mod pallet { )) } } else { - failed_withdrawal.push(withdrawal) + log::error!(target:"xcm-helper","Withdrawal failed: Not able to handle dest"); + Self::deposit_event(Event::::NotAbleToDecodeDestination); + failed_withdrawal.push(withdrawal); } } else if Self::handle_deposit(withdrawal.clone(), destination).is_err() { failed_withdrawal.push(withdrawal); + Self::deposit_event(Event::::NotAbleToHandleDestination); log::error!(target:"xcm-helper","Withdrawal failed: Not able to handle dest"); } } else { @@ -761,6 +857,10 @@ pub mod pallet { >::insert(n, failed_withdrawal); } } + + pub fn sibling_account_converter(para_id: MultiLocation) -> Option { + T::SiblingAddressConverter::convert_location(¶_id) + } } impl AssetIdConverter for Pallet { diff --git a/pallets/xcm-helper/src/mock.rs b/pallets/xcm-helper/src/mock.rs index ef34875e3..1b24bca63 100644 --- a/pallets/xcm-helper/src/mock.rs +++ b/pallets/xcm-helper/src/mock.rs @@ -127,6 +127,7 @@ impl xcm_helper::Config for Test { type SubstrateNetworkId = (); type NativeAssetId = NativeAssetId; type WeightInfo = crate::weights::WeightInfo; + type SiblingAddressConverter = (); } parameter_types! { diff --git a/polkadex-xcm-simulator/Cargo.toml b/polkadex-xcm-simulator/Cargo.toml index 37ae52ba2..282d8e64d 100644 --- a/polkadex-xcm-simulator/Cargo.toml +++ b/polkadex-xcm-simulator/Cargo.toml @@ -11,6 +11,7 @@ log = { version = "0.4.14", default-features = false } frame-system = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } frame-support = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } +pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } pallet-message-queue = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } pallet-uniques = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } sp-std = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } @@ -28,6 +29,22 @@ polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot-sdk", polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } polkadot-parachain-primitives = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.1.0" } +#ORML Pallets +orml-xtokens = { git = "https://github.com/Polkadex-Substrate/orml-1.1.0.git", branch = "master" } +orml-xcm-support = { git = "https://github.com/Polkadex-Substrate/orml-1.1.0.git", branch = "master" } +orml-traits = { git = "https://github.com/Polkadex-Substrate/orml-1.1.0.git", branch = "master" } + +#Polkadex Pallets +thea-primitives = { workspace = true } +polkadex-primitives = { workspace = true } +xcm-helper = { path = "../pallets/xcm-helper" } +thea-message-handler = { path = "../pallets/thea-message-handler" } +thea = { path = "../pallets/thea" } +smallvec = "1.13.1" + + + + [features] default = [] runtime-benchmarks = [ diff --git a/polkadex-xcm-simulator/src/lib.rs b/polkadex-xcm-simulator/src/lib.rs index 4b7958bf0..ac5930ad6 100644 --- a/polkadex-xcm-simulator/src/lib.rs +++ b/polkadex-xcm-simulator/src/lib.rs @@ -43,6 +43,15 @@ decl_test_parachain! { } } +decl_test_parachain! { + pub struct ParaC { + Runtime = parachain::Runtime, + XcmpMessageHandler = parachain::MsgQueue, + DmpMessageHandler = parachain::MsgQueue, + new_ext = para_ext(3), + } +} + decl_test_relay_chain! { pub struct Relay { Runtime = relay_chain::Runtime, @@ -61,6 +70,7 @@ decl_test_network! { parachains = vec![ (1, ParaA), (2, ParaB), + (3, ParaC), ], } } @@ -120,6 +130,7 @@ pub fn relay_ext() -> sp_io::TestExternalities { (ALICE, INITIAL_BALANCE), (child_account_id(1), INITIAL_BALANCE), (child_account_id(2), INITIAL_BALANCE), + (child_account_id(3), INITIAL_BALANCE), ], } .assimilate_storage(&mut t) @@ -141,8 +152,11 @@ pub type ParachainPalletXcm = pallet_xcm::Pallet; mod tests { use super::*; + use crate::parachain::{Balances, XcmHelper}; use codec::Encode; + use frame_support::traits::fungible::Mutate; use frame_support::{assert_ok, weights::Weight}; + use thea_primitives::extras::ExtraData; use xcm::latest::QueryResponseInfo; use xcm_simulator::TestExt; @@ -264,69 +278,15 @@ mod tests { ParaA::execute_with(|| { // free execution, full amount received + use parachain::{RuntimeEvent, System}; assert_eq!( pallet_balances::Pallet::::free_balance(&ALICE), - INITIAL_BALANCE + withdraw_amount - ); - }); - } - - #[test] - fn remote_locking_and_unlocking() { - MockNet::reset(); - - let locked_amount = 100; - - ParaB::execute_with(|| { - let message = Xcm(vec![LockAsset { - asset: (Here, locked_amount).into(), - unlocker: Parachain(1).into(), - }]); - assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone())); - }); - - Relay::execute_with(|| { - use pallet_balances::{BalanceLock, Reasons}; - assert_eq!( - relay_chain::Balances::locks(&child_account_id(2)), - vec![BalanceLock { - id: *b"py/xcmlk", - amount: locked_amount, - reasons: Reasons::All - }] - ); - }); - - ParaA::execute_with(|| { - assert_eq!( - parachain::MsgQueue::received_dmp(), - vec![Xcm(vec![NoteUnlockable { - owner: (Parent, Parachain(2)).into(), - asset: (Parent, locked_amount).into() - }])] - ); - }); - - ParaB::execute_with(|| { - // Request unlocking part of the funds on the relay chain - let message = Xcm(vec![RequestUnlock { - asset: (Parent, locked_amount - 50).into(), - locker: Parent.into(), - }]); - assert_ok!(ParachainPalletXcm::send_xcm(Here, (Parent, Parachain(1)), message)); - }); - - Relay::execute_with(|| { - use pallet_balances::{BalanceLock, Reasons}; - // Lock is reduced - assert_eq!( - relay_chain::Balances::locks(&child_account_id(2)), - vec![BalanceLock { - id: *b"py/xcmlk", - amount: locked_amount - 50, - reasons: Reasons::All - }] + INITIAL_BALANCE ); + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::XcmHelper(xcm_helper::Event::AssetDeposited(..)) + ))); }); } @@ -356,141 +316,6 @@ mod tests { }); } - /// Scenario: - /// The relay-chain teleports an NFT to a parachain. - /// - /// Asserts that the parachain accounts are updated as expected. - #[test] - fn teleport_nft() { - MockNet::reset(); - - Relay::execute_with(|| { - // Mint the NFT (1, 69) and give it to our "parachain#1 alias". - assert_ok!(relay_chain::Uniques::mint( - relay_chain::RuntimeOrigin::signed(ALICE), - 1, - 69, - child_account_account_id(1, ALICE), - )); - // The parachain#1 alias of Alice is what must hold it on the Relay-chain for it to be - // withdrawable by Alice on the parachain. - assert_eq!( - relay_chain::Uniques::owner(1, 69), - Some(child_account_account_id(1, ALICE)) - ); - }); - ParaA::execute_with(|| { - assert_ok!(parachain::ForeignUniques::force_create( - parachain::RuntimeOrigin::root(), - (Parent, GeneralIndex(1)).into(), - ALICE, - false, - )); - assert_eq!( - parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()), - None, - ); - assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0); - - // IRL Alice would probably just execute this locally on the Relay-chain, but we can't - // easily do that here since we only send between chains. - let message = Xcm(vec![ - WithdrawAsset((GeneralIndex(1), 69u32).into()), - InitiateTeleport { - assets: AllCounted(1).into(), - dest: Parachain(1).into(), - xcm: Xcm(vec![DepositAsset { - assets: AllCounted(1).into(), - beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(), - }]), - }, - ]); - // Send teleport - let alice = AccountId32 { id: ALICE.into(), network: None }; - assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message)); - }); - ParaA::execute_with(|| { - assert_eq!( - parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()), - Some(ALICE), - ); - assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000); - }); - Relay::execute_with(|| { - assert_eq!(relay_chain::Uniques::owner(1, 69), None); - }); - } - - /// Scenario: - /// The relay-chain transfers an NFT into a parachain's sovereign account, who then mints a - /// trustless-backed-derivated locally. - /// - /// Asserts that the parachain accounts are updated as expected. - #[test] - fn reserve_asset_transfer_nft() { - sp_tracing::init_for_tests(); - MockNet::reset(); - - Relay::execute_with(|| { - assert_ok!(relay_chain::Uniques::force_create( - relay_chain::RuntimeOrigin::root(), - 2, - ALICE, - false - )); - assert_ok!(relay_chain::Uniques::mint( - relay_chain::RuntimeOrigin::signed(ALICE), - 2, - 69, - child_account_account_id(1, ALICE) - )); - assert_eq!( - relay_chain::Uniques::owner(2, 69), - Some(child_account_account_id(1, ALICE)) - ); - }); - ParaA::execute_with(|| { - assert_ok!(parachain::ForeignUniques::force_create( - parachain::RuntimeOrigin::root(), - (Parent, GeneralIndex(2)).into(), - ALICE, - false, - )); - assert_eq!( - parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()), - None, - ); - assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0); - - let message = Xcm(vec![ - WithdrawAsset((GeneralIndex(2), 69u32).into()), - DepositReserveAsset { - assets: AllCounted(1).into(), - dest: Parachain(1).into(), - xcm: Xcm(vec![DepositAsset { - assets: AllCounted(1).into(), - beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(), - }]), - }, - ]); - // Send transfer - let alice = AccountId32 { id: ALICE.into(), network: None }; - assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message)); - }); - ParaA::execute_with(|| { - log::debug!(target: "xcm-exceutor", "Hello"); - assert_eq!( - parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()), - Some(ALICE), - ); - assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000); - }); - - Relay::execute_with(|| { - assert_eq!(relay_chain::Uniques::owner(2, 69), Some(child_account_id(1))); - }); - } - /// Scenario: /// The relay-chain creates an asset class on a parachain and then Alice transfers her NFT into /// that parachain's sovereign account, who then mints a trustless-backed-derivative locally. @@ -648,4 +473,164 @@ mod tests { ); }); } + + #[test] + fn trasnfer_pdex_token_to_non_native_chain() { + MockNet::reset(); + ParaA::execute_with(|| { + let destination = MultiLocation { + parents: 1, + interior: Junctions::X2( + Junction::Parachain(2), + Junction::AccountId32 { network: None, id: [1; 32] }, + ), + }; + let destination = VersionedMultiLocation::V3(destination); + let deposit = thea_primitives::types::Withdraw { + id: Default::default(), + asset_id: polkadex_primitives::AssetId::Polkadex, + amount: 2000000000000, + destination: destination.encode(), + fee_asset_id: None, + fee_amount: None, + is_blocked: false, + extra: ExtraData::None, + }; + let block_no = 1; + let multlocation = + MultiLocation { parents: 1, interior: Junctions::X1(Junction::Parachain(1)) }; + let pdex_asset_id = AssetId::Concrete(multlocation); + assert_ok!(Balances::mint_into(&XcmHelper::get_pallet_account(), 100000000000000000)); + XcmHelper::insert_parachain_asset( + pdex_asset_id, + polkadex_primitives::AssetId::Polkadex, + ); + XcmHelper::insert_pending_withdrawal(block_no, deposit.clone()); + XcmHelper::handle_new_pending_withdrawals(block_no); + }); + + ParaB::execute_with(|| { + use parachain::{RuntimeEvent, System}; + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::XcmHelper(xcm_helper::Event::AssetDeposited(..)) + ))); + }) + } + + #[test] + fn test_on_initialize_with_native_asset_deposit_to_polkadex_parachain() { + MockNet::reset(); + ParaA::execute_with(|| { + let location = + MultiLocation { parents: 1, interior: Junctions::X1(Junction::Parachain(1)) }; + let asset_id_ml = AssetId::Concrete(location); + let destination = MultiLocation { + parents: 0, + interior: Junctions::X1(Junction::AccountId32 { network: None, id: [1; 32] }), + }; + let destination: VersionedMultiLocation = destination.into(); + let deposit = thea_primitives::types::Withdraw { + id: Default::default(), + asset_id: polkadex_primitives::AssetId::Polkadex, + amount: 2000000000000, + destination: destination.encode(), + fee_asset_id: None, + fee_amount: None, + is_blocked: false, + extra: ExtraData::None, + }; + assert_ok!(Balances::mint_into(&XcmHelper::get_pallet_account(), 100000000000000000)); + XcmHelper::insert_parachain_asset(asset_id_ml, polkadex_primitives::AssetId::Polkadex); + let block_no = 1; + XcmHelper::insert_pending_withdrawal(block_no, deposit.clone()); + XcmHelper::handle_new_pending_withdrawals(block_no); + }); + } + + #[test] + fn send_sibling_asset_to_non_reserve_sibling() { + MockNet::reset(); + + ParaC::execute_with(|| { + let multlocation = MultiLocation { parents: 0, interior: Junctions::Here }; + let pdex_asset_id = AssetId::Concrete(multlocation); + assert_ok!(Balances::mint_into( + &XcmHelper::get_pallet_account(), + 100_000_000_000_000_000 + )); + let para_a = + MultiLocation { parents: 1, interior: Junctions::X1(Junction::Parachain(1)) }; + let para_b = + MultiLocation { parents: 1, interior: Junctions::X1(Junction::Parachain(2)) }; + let para_c = + MultiLocation { parents: 1, interior: Junctions::X1(Junction::Parachain(3)) }; + assert_ok!(Balances::mint_into( + &XcmHelper::sibling_account_converter(para_a).unwrap(), + 100_000_000_000_000_000 + )); + assert_ok!(Balances::mint_into( + &XcmHelper::sibling_account_converter(para_b).unwrap(), + 100_000_000_000_000_000 + )); + assert_ok!(Balances::mint_into( + &XcmHelper::sibling_account_converter(para_c).unwrap(), + 100_000_000_000_000_000 + )); + XcmHelper::insert_parachain_asset( + pdex_asset_id, + polkadex_primitives::AssetId::Polkadex, + ); + }); + ParaA::execute_with(|| { + let destination = MultiLocation { + parents: 1, + interior: Junctions::X2( + Junction::Parachain(2), + Junction::AccountId32 { network: None, id: [1; 32] }, + ), + }; + let destination = VersionedMultiLocation::V3(destination); + let multlocation = + MultiLocation { parents: 1, interior: Junctions::X1(Junction::Parachain(3)) }; + let non_reserve_asset_id = AssetId::Concrete(multlocation); + let asset_id = XcmHelper::generate_asset_id_for_parachain(non_reserve_asset_id); + let deposit = thea_primitives::types::Withdraw { + id: Default::default(), + asset_id, + amount: 2000000000000, + destination: destination.encode(), + fee_asset_id: None, + fee_amount: None, + is_blocked: false, + extra: ExtraData::None, + }; + let block_no = 1; + assert_ok!(Balances::mint_into(&XcmHelper::get_pallet_account(), 100000000000000000)); + XcmHelper::insert_parachain_asset(non_reserve_asset_id, asset_id); + XcmHelper::insert_pending_withdrawal(block_no, deposit.clone()); + XcmHelper::handle_new_pending_withdrawals(block_no); + }); + ParaC::execute_with(|| { + let multlocation = MultiLocation { parents: 0, interior: Junctions::Here }; + let pdex_asset_id = AssetId::Concrete(multlocation); + assert_ok!(Balances::mint_into(&XcmHelper::get_pallet_account(), 100000000000000000)); + XcmHelper::insert_parachain_asset( + pdex_asset_id, + polkadex_primitives::AssetId::Polkadex, + ); + use parachain::{RuntimeEvent, System}; + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::XcmHelper(xcm_helper::Event::SiblingDeposit(..)) + ))); + }); + ParaB::execute_with(|| { + use parachain::{RuntimeEvent, System}; + assert!(System::events().iter().any(|r| matches!( + r.event, + RuntimeEvent::XcmHelper(xcm_helper::Event::AssetDeposited(..)) + ))); + }) + } } diff --git a/polkadex-xcm-simulator/src/parachain.rs b/polkadex-xcm-simulator/src/parachain.rs index 6ec8c22ec..7e93377b2 100644 --- a/polkadex-xcm-simulator/src/parachain.rs +++ b/polkadex-xcm-simulator/src/parachain.rs @@ -18,37 +18,40 @@ use codec::{Decode, Encode}; use core::marker::PhantomData; +use frame_support::traits::AsEnsureOriginWithArg; use frame_support::{ construct_runtime, parameter_types, - traits::{ContainsPair, EnsureOrigin, EnsureOriginWithArg, Everything, EverythingBut, Nothing}, + traits::{EnsureOrigin, EnsureOriginWithArg, Everything, EverythingBut, Nothing}, weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, + PalletId, }; - -use frame_system::EnsureRoot; -use sp_core::{ConstU32, H256}; -use sp_runtime::{ - traits::{Get, Hash, IdentityLookup}, - AccountId32, -}; -use sp_std::prelude::*; - +use frame_system::{EnsureRoot, EnsureSigned}; +use orml_traits::location::AbsoluteReserveProvider; +use orml_traits::parameter_type_with_key; use pallet_xcm::XcmPassthrough; use polkadot_core_primitives::BlockNumber as RelayBlockNumber; use polkadot_parachain_primitives::primitives::{ DmpMessageHandler, Id as ParaId, Sibling, XcmpMessageFormat, XcmpMessageHandler, }; +use sp_core::{ConstU32, H256}; +use sp_runtime::traits::Convert; +use sp_runtime::{ + traits::{Get, Hash, IdentityLookup}, + AccountId32, Perbill, SaturatedConversion, +}; +use sp_std::prelude::*; +use thea::ecdsa::AuthorityId; +use thea::ecdsa::AuthoritySignature; use xcm::{latest::prelude::*, VersionedXcm}; use xcm_builder::{ - Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, ConvertedConcreteId, - CurrencyAdapter as XcmCurrencyAdapter, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, - IsConcrete, NativeAsset, NoChecking, NonFungiblesAdapter, ParentIsPreset, + Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, EnsureXcmOrigin, + FixedRateOfFungible, FixedWeightBounds, NativeAsset, ParentIsPreset, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, - SovereignSignedViaLocation, -}; -use xcm_executor::{ - traits::{ConvertLocation, JustTry}, - Config, XcmExecutor, + SovereignSignedViaLocation, TakeRevenue, }; +use xcm_executor::traits::WeightTrader; +use xcm_executor::{traits::ConvertLocation, Config, XcmExecutor}; +use xcm_helper::{AssetIdConverter, WhitelistedTokenHandler}; pub type SovereignAccountOf = ( SiblingParachainConvertsVia, @@ -63,6 +66,13 @@ parameter_types! { pub const BlockHashCount: u64 = 250; } +pub mod currency { + pub type Balance = u128; + pub const PDEX: Balance = 1_000_000_000_000; + pub const DOLLARS: Balance = PDEX; // 1_000_000_000_000 + pub const CENTS: Balance = DOLLARS / 100; // 10_000_000_000 +} + impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; @@ -197,19 +207,23 @@ parameter_types! { pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; pub ForeignPrefix: MultiLocation = (Parent,).into(); + pub const RelayLocation: MultiLocation = MultiLocation::parent(); + pub PdexLocation: MultiLocation = Here.into(); } -pub type LocalAssetTransactor = ( - XcmCurrencyAdapter, LocationToAccountId, AccountId, ()>, - NonFungiblesAdapter< - ForeignUniques, - ConvertedConcreteId, - SovereignAccountOf, - AccountId, - NoChecking, - (), - >, -); +// Can be used later +// pub type LocalAssetTransactor = CurrencyAdapter< +// // Use this currency: +// Balances, +// // Use this currency when it is a fungible asset matching the given location or name: +// IsConcrete, +// // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID: +// LocationToAccountId, +// // Our chain's account ID type (we can't get away without mentioning it explicitly): +// AccountId, +// // We don't track any teleports. +// (), +// >; pub type XcmRouter = super::ParachainXcmRouter; pub type Barrier = AllowUnpaidExecutionFrom; @@ -223,18 +237,48 @@ parameter_types! { pub type TrustedTeleporters = xcm_builder::Case; pub type TrustedReserves = EverythingBut>; +use smallvec::smallvec; + +pub struct WeightToFee; +impl WeightToFeePolynomial for WeightToFee { + type Balance = Balance; + fn polynomial() -> WeightToFeeCoefficients { + // Extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: + let p = CENTS; + let q = 10 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); + smallvec![WeightToFeeCoefficient { + degree: 1, + negative: false, + coeff_frac: Perbill::from_rational(p % q, q), + coeff_integer: p / q, + }] + } +} + pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; - type AssetTransactor = LocalAssetTransactor; + type AssetTransactor = XcmHelper; type OriginConverter = XcmOriginToCallOrigin; type IsReserve = (NativeAsset, TrustedReserves); type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = FixedWeightBounds; - type Trader = FixedRateOfFungible; + type Trader = ( + // If the XCM message is paying the fees in PDEX ( the native ) then + // it will go to the author of the block as rewards + //UsingComponents>, + FixedRateOfFungible, + ForeignAssetFeeHandler< + //TODO: Should we go for FixedRateOfForeignAsset + WeightToFee, + RevenueCollector, + XcmHelper, + XcmHelper, + >, + ); type ResponseHandler = (); type AssetTrap = (); type AssetLocker = PolkadotXcm; @@ -404,22 +448,10 @@ parameter_types! { pub ReachableDest: Option = Some(Parent.into()); } -pub struct TrustedLockerCase(PhantomData); -impl> ContainsPair - for TrustedLockerCase -{ - fn contains(origin: &MultiLocation, asset: &MultiAsset) -> bool { - let (o, a) = T::get(); - a.matches(asset) && &o == origin - } -} - parameter_types! { pub RelayTokenForRelay: (MultiLocation, MultiAssetFilter) = (Parent.into(), Wild(AllOf { id: Concrete(Parent.into()), fun: WildFungible })); } -pub type TrustedLockers = TrustedLockerCase; - impl pallet_xcm::Config for Runtime { type RuntimeEvent = RuntimeEvent; type SendXcmOrigin = EnsureXcmOrigin; @@ -437,8 +469,8 @@ impl pallet_xcm::Config for Runtime { type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; type Currency = Balances; type CurrencyMatcher = (); - type TrustedLockers = TrustedLockers; - type SovereignAccountOf = LocationToAccountId; + type TrustedLockers = (); + type SovereignAccountOf = (); type MaxLockers = ConstU32<8>; type MaxRemoteLockConsumers = ConstU32<0>; type RemoteLockConsumerIdentifier = (); @@ -450,6 +482,124 @@ impl pallet_xcm::Config for Runtime { type Block = frame_system::mocking::MockBlock; +parameter_types! { + pub const AssetDeposit: Balance = 100 * currency::DOLLARS; + pub const ApprovalDeposit: Balance = currency::DOLLARS; + pub const StringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = 10 * currency::DOLLARS; + pub const MetadataDepositPerByte: Balance = currency::DOLLARS; +} +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type RemoveItemsLimit = ConstU32<1000>; + type AssetId = u128; + type AssetIdParameter = codec::Compact; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = EnsureRoot; + type AssetDeposit = AssetDeposit; + type AssetAccountDeposit = AssetDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = StringLimit; + type Freezer = (); + type Extra = (); + type CallbackHandle = (); + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = AssetU128; +} + +#[cfg(feature = "runtime-benchmarks")] +pub struct AssetU128; +#[cfg(feature = "runtime-benchmarks")] +use pallet_assets::BenchmarkHelper; + +#[cfg(feature = "runtime-benchmarks")] +impl BenchmarkHelper> for AssetU128 { + fn create_asset_id_parameter(id: u32) -> codec::Compact { + codec::Compact::from(id as u128) + } +} + +pub const POLKADEX_NATIVE_ASSET_ID: u128 = 0; + +parameter_types! { + pub const AssetHandlerPalletId: PalletId = PalletId(*b"XcmHandl"); + pub const WithdrawalExecutionBlockDiff: u32 = 1; + pub ParachainId: u32 = MsgQueue::parachain_id().into(); + pub const ParachainNetworkId: u8 = 1; // Our parachain's thea id is one. + pub const PolkadexAssetid: u128 = POLKADEX_NATIVE_ASSET_ID; +} + +impl xcm_helper::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AccountIdConvert = LocationToAccountId; + type Assets = Assets; + type AssetId = u128; + type Currency = Balances; + type AssetCreateUpdateOrigin = EnsureRoot; + type Executor = TheaMessageHandler; + type AssetHandlerPalletId = AssetHandlerPalletId; + type WithdrawalExecutionBlockDiff = WithdrawalExecutionBlockDiff; + type ParachainId = ParachainId; + type SubstrateNetworkId = ParachainNetworkId; + type NativeAssetId = PolkadexAssetid; + type WeightInfo = xcm_helper::weights::WeightInfo; + type SiblingAddressConverter = SiblingParachainConvertsVia; +} + +parameter_types! { + pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(MsgQueue::parachain_id().into()))); + pub BaseXcmWeight: Weight = Weight::from_parts(100_000_000, 0); + pub const MaxAssetsForTransfer: usize = 2; +} + +parameter_type_with_key! { + pub ParachainMinFee: |_location: MultiLocation| -> Option { + Some(1u128) + }; +} + +pub struct AccountIdToMultiLocation; +impl Convert for AccountIdToMultiLocation { + fn convert(account: AccountId) -> MultiLocation { + X1(xcm::prelude::AccountId32 { network: None, id: account.into() }).into() + } +} + +impl orml_xtokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type CurrencyId = polkadex_primitives::AssetId; + type CurrencyIdConvert = XcmHelper; + type AccountIdToMultiLocation = AccountIdToMultiLocation; + type SelfLocation = SelfLocation; + type MinXcmFee = ParachainMinFee; + type XcmExecutor = XcmExecutor; + type MultiLocationsFilter = Everything; + type Weigher = FixedWeightBounds; + type BaseXcmWeight = BaseXcmWeight; + type MaxAssetsForTransfer = MaxAssetsForTransfer; + type ReserveProvider = AbsoluteReserveProvider; + type UniversalLocation = UniversalLocation; +} + +parameter_types! { + pub const TheaMaxAuthorities: u32 = 200; +} + +impl thea_message_handler::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type TheaId = AuthorityId; + type Signature = AuthoritySignature; + type MaxAuthorities = TheaMaxAuthorities; + type Executor = XcmHelper; + type WeightInfo = thea_message_handler::weights::WeightInfo; +} + construct_runtime!( pub enum Runtime { @@ -458,5 +608,113 @@ construct_runtime!( MsgQueue: mock_msg_queue::{Pallet, Storage, Event}, PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin}, ForeignUniques: pallet_uniques::{Pallet, Call, Storage, Event}, + Assets: pallet_assets::{Pallet, Call, Storage, Event}, + XTokens: orml_xtokens::{Pallet, Call, Storage, Event}, + XcmHelper: xcm_helper::{Pallet, Call, Storage, Event}, + TheaMessageHandler: thea_message_handler::{Pallet, Call, Storage, Event} } ); + +pub struct ForeignAssetFeeHandler +where + T: WeightToFeeT, + R: TakeRevenue, + AC: AssetIdConverter, + WH: WhitelistedTokenHandler, +{ + /// Total used weight + weight: Weight, + /// Total consumed assets + consumed: u128, + /// Asset Id (as MultiLocation) and units per second for payment + asset_location_and_units_per_second: Option<(MultiLocation, u128)>, + _pd: PhantomData<(T, R, AC, WH)>, +} + +impl WeightTrader for ForeignAssetFeeHandler +where + T: WeightToFeeT, + R: TakeRevenue, + AC: AssetIdConverter, + WH: WhitelistedTokenHandler, +{ + fn new() -> Self { + Self { + weight: Weight::zero(), + consumed: 0, + asset_location_and_units_per_second: None, + _pd: PhantomData, + } + } + + /// NOTE: If the token is allowlisted by AMM pallet ( probably using governance ) + /// then it will be allowed to execute for free even if the pool is not there. + /// If pool is not there and token is not present in allowlisted then it will be rejected. + fn buy_weight( + &mut self, + weight: Weight, + payment: xcm_executor::Assets, + _context: &XcmContext, + ) -> sp_std::result::Result { + let _fee_in_native_token = T::weight_to_fee(&weight); + let payment_asset = payment.fungible_assets_iter().next().ok_or(XcmError::Trap(1000))?; + if let AssetId::Concrete(location) = payment_asset.id { + // let foreign_currency_asset_id = + // AC::convert_location_to_asset_id(location).ok_or(XcmError::Trap(1001))?; + // let _path = [PolkadexAssetid::get(), foreign_currency_asset_id.into()]; + //WILL BE RESTORED LATER + // let (unused, expected_fee_in_foreign_currency) = + // if WH::check_whitelisted_token(foreign_currency_asset_id) { + // (payment, 0u128) + // } else { + // return Err(XcmError::Trap(1004)); + // }; + let (unused, expected_fee_in_foreign_currency) = (payment, 0u128); + self.weight = self.weight.saturating_add(weight); + if let Some((old_asset_location, _)) = self.asset_location_and_units_per_second { + if old_asset_location == location { + self.consumed = self + .consumed + .saturating_add((expected_fee_in_foreign_currency).saturated_into()); + } + } else { + self.consumed = self + .consumed + .saturating_add((expected_fee_in_foreign_currency).saturated_into()); + self.asset_location_and_units_per_second = Some((location, 0)); + } + Ok(unused) + } else { + Err(XcmError::Trap(1005)) + } + } +} + +use crate::parachain::currency::CENTS; +use frame_support::weights::constants::ExtrinsicBaseWeight; +use frame_support::weights::WeightToFee as WeightToFeeT; +use frame_support::weights::{ + WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, +}; + +impl Drop for ForeignAssetFeeHandler +where + T: WeightToFeeT, + R: TakeRevenue, + AC: AssetIdConverter, + WH: WhitelistedTokenHandler, +{ + fn drop(&mut self) { + if let Some((asset_location, _)) = self.asset_location_and_units_per_second { + if self.consumed > 0 { + R::take_revenue((asset_location, self.consumed).into()); + } + } + } +} + +pub struct RevenueCollector; + +impl TakeRevenue for RevenueCollector { + fn take_revenue(_revenue: MultiAsset) {} +} diff --git a/primitives/polkadex/src/assets.rs b/primitives/polkadex/src/assets.rs index c4be5e631..29ed9537c 100644 --- a/primitives/polkadex/src/assets.rs +++ b/primitives/polkadex/src/assets.rs @@ -79,6 +79,45 @@ pub trait Resolver< Ok(()) } + fn resolve_deposit_parachain( + asset: AssetId, + amount: Balance, + who: &AccountId, + admin: AccountId, + min_balance: Balance, + _locking_account: AccountId, + ) -> Result<(), DispatchError> { + if asset == NativeAssetId::get() { + Native::mint_into(who, amount.saturated_into())?; + } else { + if !Others::asset_exists(asset.into()) { + Others::create(asset.into(), admin, true, min_balance.saturated_into())?; + } + Others::mint_into(asset.into(), who, amount.saturated_into())?; + } + Ok(()) + } + + fn resolver_withdraw_parachain( + asset: AssetId, + amount: Balance, + who: &AccountId, + _locking_account: AccountId, + ) -> Result<(), DispatchError> { + if asset == NativeAssetId::get() { + Native::burn_from(who, amount.saturated_into(), Precision::Exact, Fortitude::Force)?; + } else { + Others::burn_from( + asset.into(), + who, + amount.saturated_into(), + Precision::Exact, + Fortitude::Polite, + )?; + } + Ok(()) + } + /// Deposit will burn tokens if asset is non native and in case of native, will transfer /// native tokens from `who` to `NativeLockingAccount` fn resolver_withdraw( diff --git a/runtimes/parachain/src/lib.rs b/runtimes/parachain/src/lib.rs index c53ba6b00..b457f4874 100644 --- a/runtimes/parachain/src/lib.rs +++ b/runtimes/parachain/src/lib.rs @@ -490,6 +490,7 @@ impl xcm_helper::Config for Runtime { type SubstrateNetworkId = ParachainNetworkId; type NativeAssetId = PolkadexAssetid; type WeightInfo = xcm_helper::weights::WeightInfo; + type SiblingAddressConverter = SiblingParachainConvertsVia; } parameter_types! { @@ -538,6 +539,8 @@ impl pallet_assets::Config for Runtime { pub struct AssetU128; #[cfg(feature = "runtime-benchmarks")] use pallet_assets::BenchmarkHelper; +use polkadot_parachain::primitives::Sibling; +use xcm_builder::SiblingParachainConvertsVia; #[cfg(feature = "runtime-benchmarks")] impl BenchmarkHelper> for AssetU128 { diff --git a/runtimes/parachain/src/xcm_config.rs b/runtimes/parachain/src/xcm_config.rs index 54ff3ed25..520a88d43 100644 --- a/runtimes/parachain/src/xcm_config.rs +++ b/runtimes/parachain/src/xcm_config.rs @@ -26,6 +26,7 @@ use frame_support::{ }; use frame_system::EnsureRoot; +use orml_traits::location::RelativeReserveProvider; use orml_traits::{location::AbsoluteReserveProvider, parameter_type_with_key}; use orml_xcm_support::MultiNativeAsset; use pallet_xcm::XcmPassthrough; @@ -167,7 +168,7 @@ impl xcm_executor::Config for XcmConfig { // How to withdraw and deposit an asset. type AssetTransactor = XcmHelper; type OriginConverter = XcmOriginToTransactDispatchOrigin; - type IsReserve = MultiNativeAsset; + type IsReserve = MultiNativeAsset; // Teleporting is disabled. type IsTeleporter = (); type Aliasers = Nothing;